# Vega UI > Composable, accessible React components on top of real dialogs, popovers and inputs. Themed with CSS tokens, in light and dark. --- # Getting started Install the packages, connect the styles and the theme, and render your first component. ## Requirements - `react` and `react-dom` `^19.0.0` - a bundler that loads CSS imported from packages, such as Vite, webpack or Next.js ## Install ```bash pnpm add @vega-ui/react @vega-ui/theme-core @vega-ui/icons ``` - `@vega-ui/react`: the components and their stylesheet. - `@vega-ui/theme-core`: the light and dark themes. Components read their colors, surfaces and text from its variables, so without it they render unstyled. - `@vega-ui/icons`: the icons used across the examples. `@vega-ui/react` already depends on it, but pnpm and Yarn Plug'n'Play only let the app import packages it lists itself. Install `@vega-ui/i18n` as well when the app uses calendar systems or the date helpers directly. See [Dates and calendar systems](http://vega-ui.dev/docs/i18n/#install). ## Connect Styles Components do not import their CSS. Import the theme and the stylesheet once, at the app entry point, theme first: ```tsx import '@vega-ui/theme-core'; import '@vega-ui/react/style.css'; ``` With CSS layers, declare the order first and import the library into its own layers, so app styles win regardless of specificity: ```css @layer theme, library, app; @import url('@vega-ui/theme-core') layer(theme); @import url('@vega-ui/react/style.css') layer(library); ``` Styles outside any layer win over every layer, so app styles can also stay unlayered. ## Apply A Theme The theme variables are defined on the `.light` and `.dark` classes. Put the class on the root element: ```html ``` Keep it on `` or `
`, not on an inner wrapper. `Dialog`, `Drawer` and `Sheet` render into `document.body`, outside the app tree, and only pick up a theme set on an ancestor of `body`. To switch the theme, replace the class. Custom themes are described in [Themes](http://vega-ui.dev/docs/styling/themes/). ## Fonts The default font stack is `Montserrat, Arial, sans-serif`. The library does not load Montserrat: without it in the app, text falls back to Arial. Load Montserrat in the app, or set your own stack: ```css :root { --default-font-family: Inter, system-ui, sans-serif; } ``` Headings follow `--default-font-family`. Code uses `--code-font-family`. ## First Component ```tsx import { Button } from '@vega-ui/react'; export function App() { return ; } ``` For Next.js and server rendering, see [Next.js and SSR](http://vega-ui.dev/docs/nextjs/). ## Common Mistakes - Only `@vega-ui/react/style.css` is imported: without `@vega-ui/theme-core` the variables are undefined. - The theme class is on an inner wrapper: `Dialog`, `Drawer` and `Sheet` open without a theme. - Montserrat is not loaded and the font stack is not replaced: text renders in Arial. - `@vega-ui/icons` is imported but not installed: the build fails to resolve it. ## Working On The Library ```bash pnpm install pnpm storybook pnpm test pnpm docs:validate ``` - `pnpm storybook`: the component playground. - `pnpm test`: the tests of every package; component tests run in Chromium, Firefox and WebKit. - `pnpm --filter @vega-ui/react test`: the component tests only. - `pnpm docs:validate`: checks the structure of the documentation. --- # Styling This section documents the global styling model behind VegaUI. Read it before the Styling page of a component. ## Scope - [Tokens](http://vega-ui.dev/docs/styling/tokens/): global design tokens from `@vega-ui/tokens-core` - [Themes](http://vega-ui.dev/docs/styling/themes/): light and dark theme layers from `@vega-ui/theme-core` - [CSS variables](http://vega-ui.dev/docs/styling/css-variables/): how global and component variables are composed in real apps ## Source Of Truth - `packages/tokens/src/*.css`: raw token definitions - `packages/theme/src/*.css`: semantic theme layers - `packages/ui/src/**/style.module.css`: component-level override points ## Mental Model Use the styling system in this order: 1. import global tokens 2. apply a theme class such as `.light` or `.dark` 3. consume semantic variables in components 4. use component-local `--component-*` variables only for targeted overrides --- # Themes VegaUI ships a separate theme layer in @vega-ui/theme-core. The package entrypoint is packages/theme/src/index.css, which imports both light.css and dark.css. ## Theme Model Themes are class-based: - `.light`: light theme semantic values - `.dark`: dark theme semantic values Each theme imports `@vega-ui/tokens-core` first, then maps raw token scales into semantic application variables such as: - `--background-color` - `--text-color` - `--focus-color` - `--surface-primary` - `--surface-secondary` - `--border-color` - `--fills-primary` - `--label-primary` ## Key Semantic Variables These are the main variables application code and component styles should rely on first. | Variable | Role | Typical Consumers | | --- | --- | --- | | `--background-color` | base app canvas color | app shell backgrounds, thumb-on-track contrast, custom page layout | | `--text-color` | default content color | `Text`, `Heading`, field values, icon triggers, option rows | | `--focus-color` | focus outline color | buttons, links, sliders, radios, checkboxes, segmented control | | `--surface-primary` | primary container surface | `DialogContent`, `DrawerContent`, `SheetContent`, `PopoverContent` | | `--surface-secondary` | floating or transient surface | `SelectListbox`, `TooltipContent`, `TooltipArrow` | | `--border-color` | default structural border | `Card`, `Fieldset`, `TableRow`, `CheckboxCard` | | `--border-color-hover` | interactive border emphasis | hover-state border progression for border-driven surfaces | | `--color-error` | validation and error feedback | `TextField`, `TextArea`, `PinField`, `HelperText` | | `--fills-primary` | accent-selected fill | checked `Checkbox`, checked `Radio`, page control progress | | `--fills-secondary` | neutral track or subdued fill | `Progress`, `Meter`, `MeterStack`, `Slider`, `Code`, off `Switch` | | `--label-primary` | strong indicator label | page control active indicators and derived emphasis fills | | `--label-secondary` | muted secondary text | `Fieldset` legend text, `Code` foreground, secondary metadata | | `--disable-text-color` | disabled primary content | disabled button text, disabled field values, disabled segmented items | | `--disable-background-color` | disabled control surface | disabled `TextField`, `TextArea`, `Select`, `Checkbox`, `Switch`, `ButtonBase` | | `--surface-shadow` | elevated surface shadow | `Dialog`, `Drawer`, `Sheet`, `Popover`, `Tooltip`, `SelectListbox` | ## Semantic Token Types `Key Semantic Variables` is the quick-reference layer. This section is the classification layer: it groups theme variables by semantic family so the system is easier to extend and reason about. | Token | Semantic Type | Meaning In UI | | --- | --- | --- | | `--fills-primary` | `accent-soft-fill` | primary accent fill for selected or active UI | | `--fills-primary-hover` | `accent-soft-fill-hover` | hover state for the primary accent fill | | `--fills-primary-active` | `accent-soft-fill-active` | active state for the primary accent fill | | `--fills-secondary` | `neutral-track-fill` | neutral fill for tracks, rails, and subdued containers | | `--fills-secondary-hover` | `neutral-track-fill-hover` | hover state for neutral track-like surfaces | | `--fills-secondary-active` | `neutral-track-fill-active` | active state for neutral track-like surfaces | | `--fills-tertiary` | `field-surface` | default background for text-entry and field-like controls | | `--fills-tertiary-hover` | `field-surface-hover` | hover state for field surfaces | | `--fills-tertiary-active` | `field-surface-active` | active state for field surfaces | | `--fills-quaternary-hover` | `micro-surface-hover` | lightweight hover fill for icon actions and micro-interactions | | `--fills-quaternary-active` | `micro-surface-active` | active state for micro-interactions | | `--surface-primary` | `container-surface` | main elevated surface for containers such as dialogs or sheets | | `--surface-secondary` | `floating-surface` | floating surface for listboxes, popovers, and tooltips | | `--surface-shadow` | `elevation-shadow` | shadow for elevated surfaces | | `--text-color` | `content-primary` | default readable content color | | `--text-color-inverse` | `content-on-accent` | readable content color on accent-filled backgrounds | | `--label-primary` | `label-strong` | strong UI label or indicator color | | `--label-secondary` | `label-muted` | secondary label or metadata color | | `--label-tertiary` | `label-subtle` | placeholder, helper, and subdued label color | | `--border-color` | `border-default` | default structural border color | | `--border-color-hover` | `border-hover` | hover state for structural borders | | `--border-color-active` | `border-active` | active state for structural borders | | `--disable-background-color` | `disabled-surface` | disabled background and surface fill | | `--disable-text-color` | `disabled-content` | disabled primary text or value color | | `--disable-label-text-color` | `disabled-subtle-content` | disabled secondary, helper, or placeholder text color | | `--disable-border-color` | `disabled-border` | disabled border or indicator color | | `--focus-color` | `focus-ring` | focus ring and outline color | | `--color-error` | `feedback-error` | error and validation feedback color | | `--overlay` | `backdrop-overlay` | backdrop tint for modal and overlay layers | | `--separator-opaque` | `separator-strong` | visible separators, handles, and dividers | ## Semantic Families Think about theme variables in these families first: - `fills-*`: interactive fill semantics for selected, hovered, pressed, or field-like surfaces - `surface-*`: container and floating surface semantics for overlays and elevated UI - `text-*` and `label-*`: readable content and UI-label semantics - `border-*`: structural boundary and border-emphasis semantics - `disable-*`: disabled-state surface, content, and border semantics - `focus-color`, `color-error`, `overlay`, `separator-*`: system and state-feedback semantics ## Semantic Types In Practice These semantic types come from how the UI package actually uses the variables: - `accent-soft-fill`: selected or checked states such as `Checkbox`, `Radio`, and page-control progress - `neutral-track-fill`: tracks and neutral bars such as `Progress`, `Meter`, `MeterStack`, and `Slider` - `field-surface`: input-like controls such as `TextField`, `TextArea`, `PinField`, and `SelectCombobox` - `micro-surface-*`: low-emphasis hover and active surfaces for icon buttons, trigger buttons, and picker items - `container-surface`: primary overlay or panel surfaces such as `DialogContent`, `DrawerContent`, and `SheetContent` - `floating-surface`: floating content surfaces such as `SelectListbox`, `TooltipContent`, and `PopoverContent` - `content-*`, `label-*`, `border-*`, and `disable-*`: text, label, border, and disabled-state semantics reused across the entire kit Use this section to answer “what class of semantic token do I need here?”, then use `Key Semantic Variables` to pick the concrete variable name. ## How To Apply A Theme Put the theme class on ``: ```html ``` `Dialog`, `Drawer` and `Sheet` render into `document.body`, so a class on an inner wrapper does not reach them. ## App Shell With Theme Switcher ```tsx import { useEffect, useState } from 'react'; import { Button } from '@vega-ui/react'; type ThemeName = 'light' | 'dark'; export function ThemeSwitcher() { const [theme, setTheme] = useState