These interactive maps show Tennessee’s 2023 and 2026 U.S. House of Representative districts, the latter of which were approved by Tennessee’s General Assembly and governor in May of 2026. The 2023 district borders came from the U.S. Census Bureau’s American Community Survey. The 2026 borders came from a shapefile provided by the Tennessee Comptroller of the Treasurey after a public records request.

Zoom in for map details. Grab and pan the map as needed. Clicking on a district will reveal the district’s number - a handy feature if you are zoomed in too closely to read the static district labels. Click the three stacked squares icon in the lower left to change the base map and/or toggle map layers off or on.

Embeddable .html versions of both maps are available for download from my GitHub page.


Tennessee’s 2023 House districts


Tennessee’s 2026 House districts


Code:

# ============================================================
# Step 0. INSTALL AND LOAD REQUIRED PACKAGES
# ============================================================

if (!require("tidyverse")) install.packages("tidyverse")
if (!require("tidycensus")) install.packages("tidycensus")
if (!require("sf")) install.packages("sf")
if (!require("leaflet")) install.packages("leaflet")
if (!require("leaflet.extras2")) install.packages("leaflet.extras2")
if (!require("htmlwidgets")) install.packages("htmlwidgets")

library(tidyverse)
library(tidycensus)
library(sf)
library(leaflet)
library(leaflet.extras2)
library(htmlwidgets)

# ============================================================
# Step 1. LOAD & STANDARDIZE DISTRICT GEOMETRY
# ============================================================

# --- 2023 Enacted Districts ---
cd_2023 <- get_acs(
  geography = "congressional district",
  state = "TN",
  variables = "B01001_001",
  year = 2023,
  survey = "acs5",
  geometry = TRUE
) %>%
  st_transform(4326) %>%
  mutate(
    district_num = as.integer(stringr::str_extract(NAME, "\\d+")),
    label = as.character(district_num)
  ) %>%
  select(label, district_num, geometry)

# --- 2026 Proposed Districts ---
NewDistricts <- st_read(
  "NewCongressional26.shp",
  quiet = TRUE
) %>%
  st_transform(4326) %>%
  st_make_valid() %>%
  mutate(
    district_num = as.integer(DISTRICT),
    label = as.character(district_num)
  ) %>%
  select(label, district_num, geometry)

# ============================================================
# Step 2. LABEL POINTS
# ============================================================

cd_2023_labels <- st_point_on_surface(cd_2023)
cd_2026_labels <- st_point_on_surface(NewDistricts)

# ============================================================
# Step 3. MAP 1: 2023 DISTRICTS (CLICK + HOVER)
# ============================================================

Map_2023 <- leaflet() %>%
  
  # ---- BASE MAPS ----
addProviderTiles("CartoDB.Voyager", group = "Voyager (Default)") %>%
  addProviderTiles("CartoDB.Positron", group = "Positron (Minimal)") %>%
  addProviderTiles("Esri.WorldStreetMap", group = "Street Map") %>%
  addProviderTiles("Esri.WorldImagery", group = "Satellite") %>%
  
  # ---- DISTRICTS ----
addPolygons(
  data = cd_2023,
  color = "#245482",
  weight = 3,
  fillOpacity = 0,
  popup = ~paste0("<b>District ", label, "</b>"),
  highlightOptions = highlightOptions(
    weight = 5,
    color = "#000000",
    fillOpacity = 0.1,
    bringToFront = TRUE
  ),
  group = "2023 Districts"
) %>%
  
  # ---- LABELS ----
addLabelOnlyMarkers(
  data = cd_2023_labels,
  label = ~label,
  labelOptions = labelOptions(
    noHide = TRUE,
    direction = "center",
    textsize = "12px",
    style = list("font-weight" = "bold", "color" = "#245482")
  ),
  group = "District Labels"
) %>%
  
  addLayersControl(
    baseGroups = c(
      "Voyager (Default)",
      "Positron (Minimal)",
      "Street Map",
      "Satellite"
    ),
    overlayGroups = c("2023 Districts", "District Labels"),
    options = layersControlOptions(position = "bottomleft", collapsed = TRUE)
  )

Map_2023

# ============================================================
# Step 4. MAP 2: 2026 DISTRICTS (CLICK + HOVER)
# ============================================================

Map_2026 <- leaflet() %>%
  
  # ---- BASE MAPS ----
addProviderTiles("CartoDB.Voyager", group = "Voyager (Default)") %>%
  addProviderTiles("CartoDB.Positron", group = "Positron (Minimal)") %>%
  addProviderTiles("Esri.WorldStreetMap", group = "Street Map") %>%
  addProviderTiles("Esri.WorldImagery", group = "Satellite") %>%
  
  # ---- DISTRICTS ----
addPolygons(
  data = NewDistricts,
  color = "#245482",
  weight = 3,
  fillOpacity = 0,
  popup = ~paste0("<b>District ", label, "</b>"),
  highlightOptions = highlightOptions(
    weight = 5,
    color = "#000000",
    fillOpacity = 0.1,
    bringToFront = TRUE
  ),
  group = "2026 Districts"
) %>%
  
  # ---- LABELS ----
addLabelOnlyMarkers(
  data = cd_2026_labels,
  label = ~label,
  labelOptions = labelOptions(
    noHide = TRUE,
    direction = "center",
    textsize = "12px",
    style = list("font-weight" = "bold", "color" = "#245482")
  ),
  group = "District Labels"
) %>%
  
  addLayersControl(
    baseGroups = c(
      "Voyager (Default)",
      "Positron (Minimal)",
      "Street Map",
      "Satellite"
    ),
    overlayGroups = c("2026 Districts", "District Labels"),
    options = layersControlOptions(position = "bottomleft", collapsed = TRUE)
  )

Map_2026

# ============================================================
# Step 5. EXPORT MAPS
# ============================================================

saveWidget(Map_2023, "Districts_2023_Map.html", selfcontained = TRUE)
saveWidget(Map_2026, "Districts_2026_Map.html", selfcontained = TRUE)