Svelte 5 · Bits UI 2 · Tailwind 4 · dark only
Vanguard Design
The components behind Vanguard: Vanguard 1.0's charcoal, blue and monospace, rebuilt with GitHub Primer's functional color roles and Bits UI's accessible primitives. Every state of every component is on this page.
Roles, not hex
Components reach for accent, danger, surface. Retune a role once; everything follows.
Quiet by default
Secondary is the default button, badges are subtle, danger waits for hover. Emphasis is earned.
Keyboard first
Bits UI handles focus, roving tabindex and ARIA. Every state has a visible focus ring.
Vanguard 1.0's charcoal and blue, organized into functional roles. Components use roles, never raw hex, so a role can be retuned in one place. Every text role clears WCAG AA on every background.
Backgrounds
Darkest to lightest. Elevation reads as lighter, not as heavier shadow.
Text
Contrast measured against canvas.
- Aa 1234 fg-strong Headings, selected
- Aa 1234 fg Body
- Aa 1234 fg-muted Secondary text
- Aa 1234 fg-subtle Placeholders, hints
- Aa 1234 fg-disabled Disabled (exempt)
Borders
- border-muted Dividers within a surface
- border Cards, tables, surfaces
- border-emphasis Control edges
- border-strong Hover; checkbox, radio, switch
Roles
Each hue ships four steps: text, solid fill, tint and border.
Primary actions, links, selection, info
Wins, saved, healthy
Ties, pending, warnings
Losses, errors, destructive actions
Alliance
Separate from danger and accent so 'red alliance' never reads as 'error' in code.
JetBrains Mono everywhere, as in Vanguard 1.0: team numbers, scores and timestamps align in columns without extra work. The scale is anchored at 13px for dense, data-heavy screens.
Scale
- 3xl · 32/40 Qualification 12 · 184–97 Page title
- 2xl · 24/32 Qualification 12 · 184–97 Section title
- xl · 20/28 Qualification 12 · 184–97 Large stat
- lg · 16/24 Qualification 12 · 184–97 Dialog, card title
- md · 14/20 Qualification 12 · 184–97 Emphasized body, large controls
- base · 13/20 Qualification 12 · 184–97 Body and default controls
- sm · 12/18 Qualification 12 · 184–97 Secondary text, small controls
- xs · 11/16 Qualification 12 · 184–97 Badges, table meta
- 2xs · 10/14 Qualification 12 · 184–97 Dense badges only
Weights and emphasis
Four radii and three shadows. Controls are 6px, floating panels 8px. Shadows only appear on things that float; resting surfaces separate by border and tone.
Radius
Elevation
Input
nativeSingle-line text. Inputs sit in an inset well so they read as fillable on any surface. Focus adds a blue edge and halo; errors swap both to red and never rely on color alone (see Field).
States
| state | Empty | Filled |
|---|---|---|
| Default | ||
| Hover | ||
| Focus | ||
| Invalid | ||
| Disabled | ||
| Read-only |
Sizes
Adornments
Field
bits-ui · LabelWraps a control with its label, help text and error, and wires up id, aria-describedby and aria-invalid for you. Errors pair color with an icon and a message that says how to fix it.
Live validation
Type letters to see the error.
Your FTC team, e.g. 6547.
No event found with code USCAFFL. Check the code on ftc-events.
In a form
Visible to your whole team.
Textarea
nativeMulti-line text. Resizes vertically by default; `autosize` grows with the content instead.
States
| state | Filled |
|---|---|
| Default | |
| Hover | |
| Focus | |
| Invalid | |
| Disabled |
Checkbox
bits-ui · CheckboxIndependent on/off choices that take effect on submit. The label is part of the hit target. Indeterminate shows a parent whose children are partly selected.
States
| value | Default | Hover | Active | Focus | Disabled |
|---|---|---|---|---|---|
| Unchecked | |||||
| Checked | |||||
| Indeterminate |
Try it
The parent reflects its children.
Includes surrogate matches.
Switch
bits-ui · SwitchA setting that applies immediately, like a light switch. If the change needs a Save button, use a Checkbox instead.
States
| value | Default | Hover | Active | Focus | Disabled |
|---|---|---|---|---|---|
| Off | |||||
| On |
Settings list
Pull new scores every 30 seconds.
Requires the mobile app.
Sizes
RadioGroup
bits-ui · RadioGroupOne choice from a short list, all options visible. Arrow keys move the selection. For more than about five options, use a Select.
States
| value | Default | Hover | Active | Focus | Disabled |
|---|---|---|---|---|---|
| Unchecked | |||||
| Checked |
Vertical
Selected: rank
Official ranking points.
Offensive power rating.
Not available for this season.
Horizontal
Select
bits-ui · SelectPick one option from a list too long to show at once. Typeahead works while the trigger is focused, even closed. Options can carry a description and be disabled.
States
| state | Placeholder | Selected |
|---|---|---|
| Default | ||
| Hover | ||
| Focus | ||
| Invalid | ||
| Disabled |
Try it
Open to see the list, descriptions and a disabled option.
Sizes
SegmentedControl
bits-ui · ToggleGroupSwitch between views of the same content. Always has exactly one selection; clicking the active segment does nothing. For separate content panels, use Tabs.
Text
Selected: all
Icons
Selected: list
Block
Disabled
Slider
bits-ui · SliderPick a value from a continuous range where the exact number matters less than the position. Pair with a visible value; arrow keys step, Page Up/Down jump.
States
| Default | Hover | Focus | Disabled | |
|---|---|---|---|---|
| Value 40 |
With a value
Vertical
Tabs
bits-ui · TabsSwitch between related panels without leaving the page. The underline marks the active tab, as in Vanguard 1.0's admin nav; counts summarize what's inside. Arrow keys move between tabs.
Try it
Active: schedule
Qualification matches for today, in order.
32 teams, sorted by ranking points.
4 teams still need scouting notes.
Trigger states
Default · hover · focus · active · disabled
Accordion
bits-ui · AccordionStacked sections that expand in place, for secondary detail people only sometimes need. Don't hide anything required to finish a task.
Single
One section open at a time.
Multiple, with meta and disabled
Dialog
bits-ui · DialogFocused tasks that need the page to wait. Focus moves in and is trapped; Escape, the ✕ and clicking outside close it. Keep the primary action last in the footer.
Try it
AlertDialog
bits-ui · AlertDialogInterrupts to confirm a consequential action. Name the button after the action (“Delete note”, not “OK”). The confirm can be async: it shows progress and the dialog waits.
Try it
Last result: —
Popover
bits-ui · PopoverNon-modal floating content anchored to a trigger: quick settings, previews, small forms. Closes on Escape or outside click, and focus returns to the trigger.
Try it
Tooltip
bits-ui · TooltipA short text label for a control, shown on hover and keyboard focus. Never put essential information or interactive content in one. Once one tooltip opens, neighbors open instantly.
Try it
Hover or tab through.
Badge
nativeCompact status and metadata, from Vanguard's W/L/T match pills. Subtle is the default; solid is for the one thing on screen that must pop. Red and blue are alliance colors, not status.
Tones × variants
| variant | neutral | accent | success | attention | danger | red | blue |
|---|---|---|---|---|---|---|---|
| subtle | Draft | Live | Win | Tie | Loss | Red | Blue |
| solid | Draft | Live | Win | Tie | Loss | Red | Blue |
Sizes
Dots and icons
Alert
nativeAn inline message about the page or a section. Icon, color and text carry the tone together. Say what happened and what to do next.
Tones
Live scoring is on
Notes saved
Schedule is running late
Couldn't reach FTC Events
Without title, dismissible
Progress
bits-ui · ProgressProgress of a known amount of work, or an indeterminate bar when the length is unknown, like Vanguard's status bar loader. Label it, or give it an aria-label.
Values
Tones, sizes, indeterminate
Spinner
nativeFor short waits in a small space. Prefer a Progress bar or a skeleton for anything that fills a region.
Sizes and color
Card
nativeGroups related content on a surface. The optional stripe marks a category, such as the alliance a card belongs to, as in Vanguard's match details.
Red alliance
Qualification 12
Blue alliance
Qualification 12
Rankings
SoCal League Meet 3
- 1 CC6547 Cobalt Colts 9-1-0
- 2 TT16236 Torque Theory 8-2-0
- 3 NP11115 Null Pointers 7-2-1
Plain card
A title, a body and a footer. Use `flush` for edge-to-edge lists and tables.
Avatar
bits-ui · AvatarCircles for people, rounded squares for teams. Falls back to initials while the image loads or if it fails.
Sizes
20 · 24 · 32 · 40 · 64px
Fallbacks and shapes
Separator
bits-ui · SeparatorA 1px divider between groups. Decorative by default; set decorative=false when it separates meaningful sections.
Horizontal and vertical
Above
Kbd
nativeKeyboard keys in hints and menus.