Skip to content
Twentyfirst UIHalo

Theming and tokens

Both kits define exactly the same token names. The swatches show Halo in the current theme; Pro maps its own scale onto Halo's names, references like {bg-000} point at other tokens.

Theme and density are attributes: data-theme="light|dark|system" and data-density="compact|comfortable" on <html> or any subtree, or the theme and density props of UIProvider. Halo follows the system theme and is comfortable by default; Pro is dark and compact by default.

tsx
<UIProvider theme="dark" density="compact">…</UIProvider>
// Tailwind: bg-surface text-ink rounded-lg shadow-card text-h2

Colour

TokenHereHaloProUse
--canvas#f4f3f0 / #0f0f10{bg-000}Page background behind every panel and card.
--surface#ffffff / #1a1a1c{bg-100}Cards, panels, inputs and the main workspace sheet.
--surface-sunken#ecebe7 / #232326{bg-200}Search fields, segmented-tab tracks, quiet chips and icon-button fills on `surface`.
--frame#121212 / #050505{bg-100}The dark app frame: top bar, dock and the outer shell around the workspace.
--on-frame#f4f3f0 / #f2f1ed{fg-100}Text and icons on `frame`.
--on-frame-muted#a3a29d{fg-300}Secondary text and idle nav icons on `frame` (7:1+).
--ink#141414 / #f2f1ed{fg-100}Headings, numbers and body copy on `surface`, `canvas`, `surface-sunken` and every tint.
--ink-muted#5f5e5a / #a9a8a3{fg-200}Descriptions, meta lines and labels on `surface` and `canvas` (4.5:1+ in both themes).
--ink-subtle#6b6a65 / #8e8d88{fg-300}Placeholders, disabled text and the quietest meta; 4.5:1 on surface and surface-sunken in both themes, still clearly lighter than ink-muted.
--line#e5e4df / #2c2c30{line-200}Hairline dividers and table rules; decorative, never the only boundary of a control.
--line-strong#a8a7a1 / #5a5a60{line-300}Dashed placeholder tiles and input borders (3:1 on `surface`).
--accent#141414 / #f2f1ed{fg-100}Monochrome accent: primary button fill, active tab bar, checked controls, chart emphasis.
--on-accent#ffffff / #141414#ffffff / {bg-000}Text and icons on accent fills (17:1 or more).
--sky#cfe3fb / #1e3550{info-bg}Info tint: stat tiles, event cards, the 'scheduled' state. Text on it is `ink`.
--sky-ink#1f4f8a / #9cc6f7{info}Icons and labels on `sky` or as an icon colour on `surface`.
--mint#d6efc3 / #24401a{ok-bg}Success tint: published/live states, positive stat tiles. Text on it is `ink`.
--mint-ink#2f5d16 / #a8db86{ok}Icons and labels on `mint`; success marks on `surface`.
--lilac#e9cdf4 / #3d2547{signal-bg}Highlight tint: the one featured card in a grid, lesson events. Text on it is `ink`.
--lilac-ink#6a2a82 / #dba6ee{signal}Icons and labels on `lilac`.
--butter#fbe7aa / #4a3a10{warn-bg}Money and attention tint: revenue tiles, task events, pending states. Text on it is `ink`.
--butter-ink#6b4d00 / #f3d374{warn}Icons and labels on `butter`.
--blush#f8d6d2 / #4a2320{danger-bg}Danger and support tint: errors, tickets, destructive confirms. Text on it is `ink`.
--blush-ink#8a2b23 / #f2a8a0{danger}Icons and labels on `blush`; destructive text on `surface`.
--focus#2f6fe0 / #8fb8ff{fg-100}Focus ring: 2px solid outline, 1px offset, on every interactive element.
--count#d6efc3{signal}Count pills on nav items and tabs (unread, open approvals).
--on-count#141414{bg-000}Text on `count`.
--on-frame-success#a8db86{ok}Success marks on frame: the brand dot, ok lines in logs.
--on-frame-danger#f2a8a0{danger}Error lines in logs and other danger marks on frame.
--scrimrgba(10, 10, 10, 0.32)rgba(17,17,20,0.36) / rgba(0,0,0,0.62)Backdrop behind dialogs, sheets and the command palette.
--scrim-strongrgba(10, 10, 10, 0.38){scrim}Backdrop behind modals and the command palette.
--bg-000{canvas}#f6f6f7 / #09090bCanvas: app background, behind hairline grids, inputs on surfaces.
--bg-100{surface}#ffffff / #0e0e11Surface: every grid cell, panel, table, sidebar, dialog.
--bg-200{surface-sunken}#f0f0f2 / #16161aRaised: row and button hover, kbd keys, skeletons, code blocks.
--bg-300{line}#e7e7ea / #1e1e23Selected: active nav item, selected row, pressed segment, open menu trigger.
--fg-100{ink}#111114 / #ededf0Primary text and icons on every surface (bg-000 to bg-300).
--fg-200{ink-muted}#4f4f58 / #a6a6b0Secondary text: descriptions, table cells that are not the row's key, inactive nav items. On bg-000 to bg-300.
--fg-300{ink-muted}#5e5e68 / #90909bMuted text: meta, timestamps, column headers, eyebrows. On bg-000 to bg-300.
--fg-400{ink-subtle}#a3a3ad / #5c5c66Disabled text and placeholders only. Below 4.5:1 by design; never for information.
--line-100{line}#ececef / #1a1a1fFaint hairline: row separators inside tables and lists, background grid.
--line-200{line}#dfdfe3 / #26262cHairline: the structural 1px grid between cells, panel and overlay borders, table header rule. Decorative, not a control boundary.
--line-300{line-strong}#8a8a94 / #62626dControl border (3:1 on bg-000, bg-100, bg-200): inputs, checkboxes, secondary buttons, crosshair marks.
--chart-1{accent}{fg-100}Chart series 1 / the highlighted series.
--chart-2{line-strong}#9a9aa4 / #6e6e79Chart series 2 / comparison (prior period).
--chart-grid{line}{line-100}Chart gridlines.
--chart-sky{sky} / {sky-ink}{info}Chart series tinted sky: the matching status colour.
--chart-mint{mint} / {mint-ink}{ok}Chart series tinted mint: the matching status colour.
--chart-lilac{lilac} / {lilac-ink}{signal}Chart series tinted lilac: the matching status colour.
--chart-butter{butter} / {butter-ink}{warn}Chart series tinted butter: the matching status colour.
--chart-blush{blush} / {blush-ink}{danger}Chart series tinted blush: the matching status colour.
--accent-hover{accent}#000000 / #ffffffHover state of accent fills.
--ok#2f5d16 / #a8db86#177447 / #5cc28fSuccess / done / healthy: text and status shapes (circle). On bg-000 to bg-300.
--ok-bg#d6efc3 / #24401argba(23,116,71,0.09) / rgba(92,194,143,0.12)Tint behind ok badges, banners and diff additions.
--info#1f4f8a / #9cc6f7#2856b0 / #7aa7f5Running / in progress / neutral notices. Shape: pulsing dot.
--info-bg#cfe3fb / #1e3550rgba(40,86,176,0.08) / rgba(122,167,245,0.12)Tint behind info badges and banners.
--warn#6b4d00 / #f3d374#765600 / #d9b44aWarning: budget at 80 %, expiring domains, degraded checks. Shape: triangle.
--warn-bg#fbe7aa / #4a3a10rgba(118,86,0,0.09) / rgba(217,180,74,0.12)Tint behind warning badges and banners.
--danger#8a2b23 / #f2a8a0#b0301f / #ef6f61Error, failed run, destructive actions, budget stop. Shape: square.
--danger-bg#f8d6d2 / #4a2320rgba(176,48,31,0.08) / rgba(239,111,97,0.12)Tint behind error badges, banners, diff removals.
--signal#6a2a82 / #dba6ee#9a4807 / #f2994aNeeds a human: approval waiting, beacons, the approval count. Shape: diamond. The only hue that may draw the eye unprompted.
--signal-bg#e9cdf4 / #3d2547rgba(154,72,7,0.09) / rgba(242,153,74,0.14)Tint behind approval cards' header and signal badges.
--idle#5f5e5a / #a9a8a3{fg-300}Status idle: ready, inactive (ring). Alias of `ink-muted`.
--diff-add#2f5d16 / #a8db86{ok}Added lines in override diffs.
--diff-add-bg#d6efc3 / #24401a{ok-bg}Fill of added lines. Alias of `mint`.
--diff-del#8a2b23 / #f2a8a0{danger}Removed lines in override diffs.
--diff-del-bg#f8d6d2 / #4a2320{danger-bg}Fill of removed lines. Alias of `blush`.
--paper#ffffff#ffffffDocument previews (invoices, PDFs): paper is white in both themes.
--paper-ink#141414#111114Text on paper.
--frame-hoverrgba(255, 255, 255, 0.08){bg-200}Hover fill on the dark frame (top bar, dock, code blocks). Same in both themes.
--frame-activergba(255, 255, 255, 0.12){bg-300}Active or selected fill on the dark frame. Same in both themes.
--frame-strongrgba(255, 255, 255, 0.18){bg-300}Strong fill or divider on the dark frame. Same in both themes.
--on-frame-strong#ffffff{fg-100}Highlighted text on the frame (log highlights). Same in both themes.
--on-frame-warn#f3d374{warn}Warnings and numbers in logs and code on the frame. Same in both themes.
--on-frame-signal#d4b8f0{signal}Keywords in code on the frame. Same in both themes.
--ink-hoverrgba(0, 0, 0, 0.06){bg-200}Hover fill on tinted surfaces such as alerts. Same in both themes.
--hairlinergba(0, 0, 0, 0.12){line-200}Thin outline around swatches and colour wells. Same in both themes.
--media-scrimrgba(10, 10, 10, 0.6)rgba(10, 10, 10, 0.6)Labels and counters on top of photos. Same in both themes.
--media-ink#ffffff#ffffffText and lines on top of photos. Same in both themes.
--media-shadowrgba(0, 0, 0, 0.3)rgba(0, 0, 0, 0.3)Shadow behind lines drawn on photos. Same in both themes.
--lightboxrgba(8, 8, 8, 0.92)rgba(8, 8, 8, 0.92)Full-screen image viewer background. Same in both themes.
--lightbox-inkrgba(255, 255, 255, 0.8)rgba(255, 255, 255, 0.8)Captions in the image viewer. Same in both themes.
--paper-muted#706f6a#706f6aSecondary text on paper (4.5:1 on white).
--paper-subtle#6b6a65#6b6a65Small print on `paper`. Same in both themes.
--serp-ink#202124#202124Search ad preview: text. Same in both themes.
--serp-muted#4d5156#4d5156Search ad preview: description and URL. Same in both themes.
--serp-link#1a0dab#1a0dabSearch ad preview: headline link. Same in both themes.
--serp-chip#f1f3f4#f1f3f4Search ad preview: favicon chip. Same in both themes.

Shadow

TokenHaloProUse
--shadow-card0 1px 2px rgba(20,20,20,0.04), 0 6px 20px rgba(20,20,20,0.05) / 0 1px 2px rgba(0,0,0,0.4)noneResting cards. Pro: none, hairlines divide.
--shadow-lift0 2px 4px rgba(20,20,20,0.06), 0 14px 32px rgba(20,20,20,0.10) / 0 2px 6px rgba(0,0,0,0.5), 0 14px 32px rgba(0,0,0,0.45)noneHovered card. Pro: none.
--shadow-float0 16px 40px rgba(0,0,0,0.22) / 0 16px 40px rgba(0,0,0,0.6)0 16px 40px rgba(17,17,20,0.12) / 0 16px 40px rgba(0,0,0,0.55)Floating layers: dock, toasts, menus and dialogs.
--shadow-overlay{shadow-float}0 16px 40px rgba(17,17,20,0.12) / 0 16px 40px rgba(0,0,0,0.55)Only floating layers: menus, popovers, dialogs, toasts, command palette. Always paired with a line-200 border.

Component knobs

TokenHaloProUse
--button-radius{radius-pill}{radius-1}Corners of buttons (Button, IconButton). One knob for a theme's button shape.
--field-radius{radius-pill}{radius-1}Corners of inputs and selects.
--badge-radius{radius-pill}{radius-1}Corners of badges and chips.
--panel-bg{surface}{bg-100}Background of a panel: a cell of the hairline grid, a section, a side column.
--panel-bordertransparent{line-200}Border colour of a panel standing on its own; transparent where panels float.
--panel-radius{radius-lg}{radius-0}Corners of a panel. Pro: square cells of the hairline grid.
--panel-shadow{shadow-card}noneResting shadow of a panel. Pro: none, the hairlines divide.
--panel-pad{space-6}{space-4}Inner padding of a panel.
--panel-gap{space-4}1pxGap between panels in a grid: the hairline in Pro, air between cards in Halo.

Spacing

TokenHaloProUse
--space-0-52px2pxIcon-to-badge nudges, hairline offsets.
--space-14px4pxGap inside badges and kbd groups.
--space-28px8pxGap between icon and label, between buttons in a group.
--space-312px12pxCompact horizontal cell and control padding.
--space-416px16pxGrid cell padding, comfortable control padding, page gutter on mobile.
--space-520px20pxDialog body padding.
--space-624px24pxCell padding on overview grids; background-grid pitch.
--space-832px32pxGap between stacked sections inside a panel.
--space-1040px40pxOuter margin of the app frame on large screens.
--space-1248px48pxEmpty-state padding.
--space-1664px64pxLogin and onboarding vertical rhythm.

Radius

TokenHaloProUse
--radius-sm10px{radius-1}Inputs inside cells, row hovers, small tiles.
--radius-md16px{radius-0}Stat cells, event cards, menus: square in Pro.
--radius-lg22px{radius-0}Cards and panels: square cells of the hairline grid.
--radius-xl30px{radius-0}The workspace sheet and app frame: square in Pro.
--radius-pill999px{radius-1}Buttons, chips, badges, tabs and inputs: 2px in Pro.
--radius-00px0pxDefault for everything structural: cells, panels, tables, dialogs, sheets, cards.
--radius-1{radius-sm}2pxControls: buttons, inputs, badges, kbd, switches, tooltips.
--radius-full9999px9999pxOnly status dots and radio buttons.

Motion

TokenHaloProUse
--dur-fast120ms{duration-fast}Press, hover colour changes, chip toggles.
--dur-base220ms{duration-base}Tab indicator slide, menu open, card lift.
--dur-enter520ms{duration-base}Entrances: short and quiet in Pro.
--dur-slow900ms{duration-base}Count-ups, chart draw-ins and progress fills: short in Pro.
--stagger-step55ms0msNo staggered entrances in Pro.
--ease-outcubic-bezier(0.22, 1, 0.36, 1){ease-standard}Entrances.
--ease-springcubic-bezier(0.34, 1.56, 0.64, 1){ease-standard}No overshoot in Pro: the standard curve.
--ease-in-outcubic-bezier(0.65, 0, 0.35, 1){ease-standard}Things moving between two resting places.
--duration-fast{dur-fast}90msHover and press feedback.
--duration-base{dur-base}140msMenus, popovers, sheets, toasts entering.
--ease-standard{ease-out}cubic-bezier(0.2, 0, 0, 1)The only easing curve.

Sizes

TokenHaloProUse
--control-sm32px24pxSmall buttons in dense toolbars.
--control-md40px{control-dense}Default control height (follows density in components).
--control-lg48px{control-comfy}Large controls.
--row-dense40px28pxRow height for tables, lists and nav items in compact density.
--row-comfy52px36pxRow height in comfortable density.
--control-dense{control-sm}28pxButton and input height in compact density.
--control-comfy{control-md}34pxButton and input height in comfortable density.
--topbar-h60px44pxTop bar height.
--sidebar-w44px232pxSidebar width, expanded.
--sidebar-w-collapsed44px52pxSidebar width, icon-only.
--subnav-w208px{sidebar-w}SubNav width.
--side-panel-w304px320pxSide panel width.
--icon-sm14px14pxIcons inside badges and dense table cells.
--icon-md16px16pxDefault Lucide icon size.
--icon-lg20px16pxIcons in navigation: same as icon-md in Pro.
--line-width1px1pxEvery border and grid line (Pro calls it hairline).