Frontend Architecture

React 19 + TypeScript + Vite single-page application with TanStack Query for server state and Tailwind CSS v4 for styling.

Stack

Technology Version Purpose
React 19.x UI framework
TypeScript 5.9 Type safety
Vite 7.x Build tool + dev server (port 5173)
TanStack Query 5.x Server state, caching, mutations
TanStack Virtual 3.x Virtualized lists/tables
Tailwind CSS 4.x Utility-first styling
React Router 7.x Client-side routing
Radix UI Tooltips Accessible tooltip primitives
Lucide React Icons Icon library
Sonner Toasts Toast notifications

Project Structure

frontend/src/
├── App.tsx              # Routes, lazy loading, providers
├── main.tsx             # Entry point
├── index.css            # Tailwind config, theme variables
├── pages/               # Page components (one per route)
├── components/          # Reusable components
│   └── ui/              # Generic primitives (button, dialog, input, etc.)
├── api/                 # API client modules (one per domain)
├── hooks/               # Custom hooks (queries, mutations, utilities)
├── contexts/            # React Context providers
├── layouts/             # Layout wrappers (MainLayout with sidebar)
└── lib/                 # Utility functions

Pages

All pages are lazy-imported in App.tsx:

Page Route Description
Dashboard / Overview, generation trigger, cache stats
Templates /templates Template list and management
TemplateForm /templates/new, /templates/:id Create/edit template with variable picker
Teams /teams Team list and management
TeamImport /teams/import Bulk import teams from cache
EventGroups /event-groups Event group list
EventGroupForm /event-groups/new, /event-groups/:id Create/edit event group
EventGroupImport /event-groups/import Bulk import event groups
EPG /epg XMLTV preview, download, run history
Channels /channels Managed channel list with sync status
Settings /settings All settings tabs
DetectionLibrary /detection-library Keywords and team aliases

API Client Pattern

api/client.ts provides a typed HTTP client:

const API_BASE = "/api/v1"

export const api = {
  get<T>(path: string): Promise<T>,
  post<T>(path: string, data?): Promise<T>,
  put<T>(path: string, data): Promise<T>,
  patch<T>(path: string, data?): Promise<T>,
  delete<T>(path: string): Promise<T>,
}

One API module per domain (teams, templates, groups, channels, settings, etc.) with type definitions and async functions wrapping api.get/post/put/delete.

State Management

Approach Used For
TanStack Query Server state (data fetching, caching, invalidation)
React Context Generation progress (SSE polling + cancellation)
localStorage Theme preference (dark/light)
React hooks Local form state

Query client defaults: staleTime: 1min, retry: 1.

Key Components

UI Primitives (components/ui/)

Generic building blocks: button, input, dialog, card, table, tooltip, badge, checkbox, switch, label, select.

Feature Components

Component Purpose
LeaguePicker League selection with sport grouping and logos
SoccerModeSelector Soccer-specific league/team picker
VariablePicker Template variable browser with auto-completion
CheckboxListPicker Searchable multi-select with grouping
SelectedBadges Badge overflow with “+N more” tooltip (maxBadges=10)
ChannelProfileSelector Dispatcharr channel profile picker
StreamProfileSelector Dispatcharr stream profile picker
RunHistoryTable Shared EPG run history (Dashboard + EPG page)
SortPriorityManager Drag-drop priority editor
VirtualizedTable Large dataset rendering

Theme System

CSS custom properties in oklch color space, defined in index.css:

  • Dark theme (default) + Light theme toggled via html.dark/html.light
  • Tokens: background, foreground, primary, secondary, muted, accent, destructive, success, warning, error, info

Development

npm run dev    # Vite dev server on :5173, proxies /api → :9195
npm run build  # TypeScript check + production build → dist/

The Vite dev proxy forwards /api/* and /health to the backend at localhost:9195. Use :5173 during development for hot-reload.

Build Output

dist/index.html           ~0.7 KB
dist/assets/index-*.css   ~66 KB (gzip: ~12 KB)
dist/assets/index-*.js    ~859 KB (gzip: ~232 KB)

Content-hash filenames for HTTP cache-busting. Single-chunk build (no code splitting beyond lazy routes).


Back to top

Teamarr - Sports EPG Generator for Dispatcharr

This site uses Just the Docs, a documentation theme for Jekyll.