An interactive county-level election map for the 2026 Democratic and Republican primaries in Texas. Heavily inspired by the "big boards" used on TV by Steve Kornacki and John King.
To run locally:
npm install -g serveserve . -p 8080- visit http://localhost:8080/ on your browser.
The provided CSV template (candidates_template.csv) file shows what data is needed for each candidate in the race:
candidate_id: A unique ID provided for this candidate, will be referenced in the results file.party: D or R for Democratic or Republican candidatename_first: Candidate's first namename_last: Candidate's last nameincumbent:trueorfalseif this candidate should be flagged as an incumbentphoto_url: optional URL to an image to show as a candidate's profile picture on the right side summaryhex_color: color this candidate will be shaded as on the big board
Check out the template (results_template.csv). Each row of the results file has:
candidate_id: A unique ID for a candidatecounty: County name in all caps, used for joining to the map make sure to include aSTATEWIDEcounty which is the results for the whole state combined.votes: Integer number of votes this candidate has receivedpct_vote: 0-100 float that shows the percent of the vote the candidate has received.pct_reporting: 0-100 float representing the percent of the precincts that has been reported, this should be the same for all candidates in a particular county.called:trueorfalseif this county or statewide result has been called for a particular candidate. If multiple candidates receive a call in theSTATEWIDEresult, then instead ofWINNER ✓it will displayADVANCED TO RUNOFF ✓on the right side summary.
In index.html edit these variables to configure your data source and map settings
Edit the following variables to point to the CSV file you have hosted for the backend, or supply null and the map will fallback to some hard coded test data. I would recommend serving these CSVs from an AWS S3 bucket or a Google Cloud Storage bucket.
const CANDIDATES_URLconst RESULTS_URL
const LIVE_UPDATES being set to true will make the app refresh with new data every const REFRESH_SEC seconds. When LIVE_UPDATES is true precent reported will max out at >99.9% and never show 100% even if 100 is supplied in the results CSV.
LIVE_UPDATES set to false will no longer refresh automatically, will display "FINAL RESULTS" on the top right, and will allow 100% reporting to be shown.
