Skip to main content
WireKit
Copy for LLM

Design Tokens

The complete CSS-variable surface that every WireKit component reads from. Override any variable in your :root {} (light) or .dark {} (dark mode) block to retheme the library — no Tailwind config changes, no component overrides, no rebuild needed.

Looking for setup help, theme presets, or accessibility guarantees? See the Theming guide. This page is the pure variable reference.

All Design Tokens

Colors — Accent

Variable Light Dark Used for
--color-wk-accent neutral-900 neutral-50 Accent fill — button / badge backgrounds
--color-wk-accent-hover neutral-800 neutral-200 Accent fill hover
--color-wk-accent-text neutral-900 neutral-50 Accent-toned text on the page background (links, stepper, callout) — alias of --color-wk-accent-content
--color-wk-accent-content neutral-900 neutral-50 Readable accent text on the page or a soft-tinted accent surface
--color-wk-accent-fg neutral-50 neutral-900 Text/icon on an accent fill

Three accent roles, don't mix them. --color-wk-accent is a fill — it sits behind other content and can be a bright, saturated brand color. Never use it as a text color: on a light brand accent, text drawn in the fill color fails contrast against the page background. Accent-toned text reads --color-wk-accent-text (an alias of --color-wk-accent-content), which defaults to a near-black/near-white that always clears WCAG AA. Text that sits on an accent fill (a button label) reads --color-wk-accent-fg. When you re-tint, set --color-wk-accent to your brand fill and --color-wk-accent-content to a readable text tone of it — otherwise links fall back to the safe near-neutral default.

Colors — Danger

Variable Light Dark Used for
--color-wk-danger red-600 red-600 Danger button bg
--color-wk-danger-hover red-700 red-700 Danger button hover
--color-wk-danger-fg white white Text on danger bg
--color-wk-danger-text red-700 red-400 Error message text

Colors — Success

Variable Light Dark Used for
--color-wk-success green-600 green-500 Success states
--color-wk-success-hover green-500 green-400 Success hover
--color-wk-success-fg zinc-900 zinc-900 Text on success bg
--color-wk-success-text oklch(45.6% 0.17 149.7) green-400 Success message text
--color-wk-border-success = success-text = success-text Success-state border on a form control. Deliberately the same value as --color-wk-success-text: the border and the helper text below it read as one state, and a divergence looks like a rendering fault rather than a design choice. Re-tint both together.

Colors — Warning

Variable Light Dark Used for
--color-wk-warning amber-500 amber-400 Warning states
--color-wk-warning-hover amber-600 amber-300 Warning hover
--color-wk-warning-fg zinc-900 zinc-900 Text on warning bg
--color-wk-warning-text oklch(47.6% 0.158 65) oklch(85.4% 0.183 81) Warning message text — the readable tone, not the fill. --color-wk-warning is a fill and fails contrast as body text on the page background.
--color-wk-warning-bg oklch(96.4% 0.058 102.1) deep amber Softly tinted warning surface (alert, callout). Pale enough that --color-wk-text stays the body color on top of it, so the tint carries the state and the text carries the reading.

Colors — Neutrals

Variable Light Dark Used for
--color-wk-bg white neutral-950 Page background
--color-wk-bg-elevated white neutral-900 Cards, modals
--color-wk-bg-subtle neutral-50 neutral-900 Hover backgrounds
--color-wk-bg-muted neutral-100 neutral-800 Secondary button bg
--color-wk-bg-input white neutral-950 Input backgrounds
--color-wk-text neutral-950 neutral-50 Primary text
--color-wk-text-muted oklch(47%) oklch(74%) Hint text
--color-wk-text-subtle neutral-500 neutral-400 Prefix/suffix text
--color-wk-text-placeholder neutral-500 neutral-400 Input placeholders
--color-wk-code = text = text Inline <code> text — themeable per preset (Aurora sets it to the brand magenta)
--color-wk-code-bg = bg-muted = bg-muted Inline <code> background — themeable per preset
--color-wk-bg-inverse neutral-950 neutral-50 Background of a surface that deliberately opposes the page — a dark band in a light theme and a light one in a dark theme. It flips with the theme, which is the point: "inverse" is a relationship, not a color. Pair it with --color-wk-text-inverse.
--color-wk-text-inverse white neutral-950 Text on an inverse surface. Always used together with --color-wk-bg-inverse; setting one without the other is how an inverted band ends up with unreadable text.
--color-wk-bg-skeleton oklch(93%) oklch(33%) Resting fill of a loading placeholder (<x-wirekit::skeleton>). Distinct from --color-wk-bg-muted on purpose — a placeholder should read as absent content, not as a quiet surface.

Colors — Info

Variable Light Dark Used for
--color-wk-info-text = accent-content = accent-content Informational message text. Defaults to an alias of --color-wk-accent-content, so an info note inherits your accent's readable tone rather than a second blue you would have to keep in sync.

There is no --color-wk-border-info in the stylesheet, and that is deliberate. No component renders an informational border — a form control is either in its error state or its resting one, with no third — so a token for it would exist only to be overridden into nothing. (--color-wk-info is a different token and does exist: it is the fifth chart dataset color, listed under Chart Theming below, and unrelated to this text token.)

Colors — Borders and Focus

Variable Light Dark Used for
--color-wk-border oklch(91.4%) oklch(32%) Decorative borders (cards, dividers, tables) — WCAG 1.4.11-exempt, kept light
--color-wk-border-strong oklch(66%) oklch(51%) Resting border for every form control — meets WCAG 1.4.11 (3:1) against the input fill
--color-wk-border-strong-hover oklch(58%) oklch(58%) Hover border for every form control — moves further from the fill (4.28:1 light, 4.62:1 dark)
--color-wk-border-hover oklch(80%) neutral-600 Hover state for decorative borders only — does not meet 3:1, never use it on a control
--color-wk-border-subtle oklch(94%) neutral-800 Subtle dividers
--color-wk-border-error = danger-text = danger-text Error-state border on a form control. Deliberately the same value as --color-wk-danger-text: the border and the message below it read as one state, and a divergence looks like a rendering fault rather than a design choice. Re-tint both together.
--color-wk-ring neutral-950 neutral-50 Focus rings
--color-wk-ring-offset white neutral-950 Focus ring offset

Border Radius

All radius values derive from a single base --radius-wk. Change one value, everything scales.

Variable Default Used for
--radius-wk 0.5rem Base value
--radius-wk-sm calc(base * 0.75) Small buttons (xs, sm)
--radius-wk-md base Default buttons, inputs
--radius-wk-lg calc(base * 1.25) Large buttons (xl)
--radius-wk-xl calc(base * 2) Cards, modals
--radius-wk-full 9999px Pills, avatars

Shadows

Variable Default Used for
--shadow-wk-sm Subtle 1px shadow Buttons, inputs
--shadow-wk-md Medium elevation Dropdowns
--shadow-wk-lg Strong elevation Modals
--shadow-wk-none transparent Ghost buttons
--shadow-wk-badge 1px, text-tinted The badge's own lift. Tinted from --color-wk-text via color-mix() rather than from black, so it stays a shadow of the theme instead of a gray smudge on a colored surface

Typography

Variable Default Used for
--font-wk-sans Inter, system-ui All components
--font-wk-mono Fira Code, monospace Code elements
--font-wk-heading-weight 600 Headings
--font-wk-body-weight 400 Body text, buttons
--font-wk-letter-spacing -0.01em All text. Slightly negative because Inter is drawn a touch loose at body sizes; a font preset that is not may want it back at 0em
--font-wk-line-height 1.5 All text

Motion

Variable Default Used for
--transition-wk-duration 150ms All transitions (back-compat name; same value as --motion-wk-duration-fast)
--transition-wk-easing cubic-bezier(0.4, 0, 0.2, 1) All transitions
--motion-wk-duration-fast 150ms Fast animations (<x-wirekit::reveal>, .wk-animate-fast)
--motion-wk-duration-normal 300ms Normal animations (default for <x-wirekit::reveal>)
--motion-wk-duration-slow 600ms Slow animations (.wk-animate-slow)
--motion-wk-easing-out cubic-bezier(0.16, 1, 0.3, 1) Decelerating easing (elements entering the screen)
--motion-wk-easing-in cubic-bezier(0.7, 0, 0.84, 0) Accelerating easing (elements leaving the screen)
--shimmer-wk-duration 2s Travel time of one sweep across <x-wirekit::shimmer>. Overridable per instance through the component's duration prop
--shimmer-wk-band 3ch Half-width of the bright band in that sweep. Smaller reads as a tight glint, larger as a broad wash. In ch so the band scales with the text it travels over rather than with the viewport
--shimmer-wk-angle 105deg Tilt of the band. 90deg gives a vertical sweep
--wk-stagger-step 75ms Delay added per child in a staggered entrance (<x-wirekit::stats stagger>). The n-th child waits n × this, so the number is a rhythm rather than a duration
--motion-wk-easing-spring cubic-bezier(0.5, 1.5, 0.5, 1) Spring/overshoot easing (bounce, spring presets)
--motion-wk-delay-none 0ms <x-wirekit::reveal delay="none">
--motion-wk-delay-sm 75ms <x-wirekit::reveal delay="sm"> (also the default feature-grid stagger step)
--motion-wk-delay-md 150ms <x-wirekit::reveal delay="md">
--motion-wk-delay-lg 300ms <x-wirekit::reveal delay="lg">
--motion-wk-delay-xl 500ms <x-wirekit::reveal delay="xl">

The four shimmer and stagger tokens above are inert under prefers-reduced-motion: reduce, like everything in this section.

Spacing and Layout

These tokens drive the gaps and padding inside the layout primitives (stack, row, grid, section) and component internals. WireKit components carry no outer margins — compose vertical and horizontal rhythm with the layout primitives + their gap prop instead of hand-rolling space-y-* / mb-* utilities.

Variable Default Used for
--space-wk-nav-gap 0.25rem The gap between rows in a navigation column. Read by BOTH the app rail and the sidebar, because a console shell puts the two side by side and a reader sees any difference between them as a fault rather than as a choice
--space-wk-xs--space-wk-2xl 0.25 · 0.5 · 1 · 1.5 · 2.5 · 4rem General spacing scale (xs, sm, md, lg, xl, 2xl) — and what the gap prop of stack / row / grid / bento-grid / feature-grid resolves to by default
--space-wk-section-sm / -md / -lg 3rem / 5rem / 7rem Vertical padding for page sections (section, hero, cta)
--gap-wk-xs-2xl 0.25 / 0.5 / 0.75 / 1 / 1.5 / 2rem Gaps INSIDE a component — icon to label, footer buttons, dropdown items. A layout primitive reads the --space-wk-* ladder above unless you ask for this one: stack, row, grid, bento-grid and feature-grid take scale="gap" for exactly that, which is the only way a gap prop reaches these rungs. Full xs · sm · md · lg · xl · 2xl ladder
--padding-wk-x-xs-xl 0.375 · 0.625 · 0.75 · 1 · 1.5rem Horizontal (inline) padding, axis-split
--padding-wk-y-xs-xl 0.25 · 0.375 · 0.5 · 0.75 · 1rem Vertical (block) padding, axis-split

The padding scale is axis-split (-x- / -y-) with no axis-less shorthand; the gap scale runs the full xs2xl ladder (a reference to an undefined step would silently collapse the gap to 0, so the ladder is complete).

Border Width

Variable Default Used for
--border-wk-width 1px All component borders
--border-wk-badge-width = border-wk-width The badge's ring, as its own knob. It defaults to the global width and exists so a preset can hairline the badge alone — the Brutalist preset thickens every border, and a badge at that weight reads as a button

States

Variable Default Used for
--opacity-wk-hover 0.8 Hover opacity
--opacity-wk-disabled 0.5 Disabled elements
--opacity-wk-loading 0.7 Loading states

Focus Ring

Variable Default Used for
--ring-wk-width 2px Focus ring width
--ring-wk-offset 2px Focus ring offset

Component Sizing

Variable Default Used for
--size-wk-xs 1.5rem (24px) Smallest control box — the checkbox and radio square, a badge dot. Below --size-wk-touch-target by design: the target around it is what has to clear that, not the painted box
--size-wk-sm 2rem (32px) Small button/input height
--size-wk-md 2.5rem (40px) Default button/input height
--size-wk-md-compact 2.25rem (36px) A shade under the default, for a control sitting inside another control — a toolbar button, an input addon — where the full height would crowd its container
--size-wk-lg 3rem (48px) Large button/input height
--size-wk-xl 6rem (96px) Not a control height: the box for a large avatar, an empty-state glyph, a media thumbnail
--size-wk-touch-target 2.75rem (44px) The pointer-target floor. Read it wherever you build a target of your own next to a WireKit control — a small icon button, a chip's remove affordance — so the two agree and keep agreeing. Components apply it as a centered ::before over a smaller painted box, which is why a 14px close glyph is still comfortable to hit
--size-wk-target-min 1.5rem (24px) The other floor, and not interchangeable with the one above: this is what WCAG 2.5.8 asks at level AA, where 44px is 2.5.5 at AAA. Reach for this one where a control has two targets that can come close together — the range slider's handles come within half a pixel of each other, and two oversized targets stacked there are worse than two correct ones
--size-wk-fab 3.5rem (56px) The floating action button's own box. It is a token because you cannot lay out AROUND a control whose size you cannot read: a FAB is position: fixed over whatever scrolls beneath it, so that content has to keep the space free at its end. Use wk-fab-clearance on the scrolling container rather than doing the arithmetic yourself
--size-wk-table-sticky-column-max min(40vw, 16rem) The widest the frozen first column of a sticky-column table gets before its labels wrap. A cap rather than a width: a short label keeps its own width, and a table with room to spare still gives the column its share. Set it on one table with style to change it there
--size-wk-container-sm 40rem Max width of <x-wirekit::container size="sm"> — a reading column
--size-wk-container-md 48rem Container md
--size-wk-container-lg 64rem Container lg
--size-wk-container-xl 80rem Container xl
--size-wk-container-2xl 96rem Container 2xl — the widest step, for dashboards rather than prose
--padding-wk-x-sm 0.625rem Small horizontal padding
--padding-wk-x-md 0.75rem Default horizontal padding
--padding-wk-x-lg 1rem Large horizontal padding
--padding-wk-x-xl 1.5rem Extra-large horizontal padding (overlays)
--padding-wk-y-xs 0.25rem Extra-small vertical padding (tooltip, dropdown)
--padding-wk-y-sm 0.375rem Small vertical padding (textarea)
--padding-wk-y-md 0.5rem Default vertical padding (textarea)
--padding-wk-y-lg 0.75rem Large vertical padding (textarea)
--padding-wk-y-xl 1rem Extra-large vertical padding (overlays)
--gap-wk-xs 0.25rem Extra-small gap (tight groups)
--gap-wk-sm 0.5rem Small gap/spacing (dropdown items)
--gap-wk-md 0.75rem Default gap/spacing (footer buttons)
--gap-wk-lg 1rem Large gap (section groups, sidebars)
--gap-wk-xl 1.5rem Extra-large gap
--gap-wk-2xl 2rem 2x-large gap

Two spacing ladders, same rung names

Two ladders share the xs2xl rung labels and they are not the same values. --gap-wk-* is the tighter one, for space between items inside a component; --space-wk-* is roomier, for space between blocks of a page. Only xs and sm happen to agree — reaching for the wrong one gets you 0.75rem where you expected 1rem, and the gap widens as you go up:

Rung --gap-wk-* --space-wk-*
xs 0.25rem 0.25rem
sm 0.5rem 0.5rem
md 0.75rem 1rem
lg 1rem 1.5rem
xl 1.5rem 2.5rem
2xl 2rem 4rem

Font Sizes

Variable Default Used for
--text-wk-2xs 0.6875rem Micro text (dense secondary labels)
--text-wk-xs 0.75rem Caption / micro-label
--text-wk-sm 0.8125rem Small font size
--text-wk-md 0.875rem Default body font size
--text-wk-lg 1rem Large body / lede
--text-wk-xl 1.25rem Sub-heading
--text-wk-2xl 1.5rem Section heading
--text-wk-3xl 1.875rem Page heading
--text-wk-4xl 2.25rem Display heading — a hero or landing headline, above the page-heading step
--text-wk-5xl 3rem The largest step. Reach for it when a headline IS the page; at body-copy sizes below it, the jump reads as a change of register rather than of level

Every step is calc(<base> * var(--font-scale-wk)), so the whole ladder scales from one number — see --font-scale-wk below.

Variable Default Used for
--font-scale-wk 1 Multiplier on the entire type scale. Set it once — <html style="--font-scale-wk: 1.25"> or in your :root — and every --text-wk-* step grows with it, because each is a calc() against this value. It exists so a reader-facing type-size control changes one number instead of overriding eleven, and so the ratios between steps survive the change.
--text-wk-touch-floor 16px The smallest text a form field shows on a touch screen, because iOS zooms into a field with smaller text the moment it is focused. Every field and the editor read it under pointer: coarse, and so does a button given touch-text-floor, for one that shares a row with a field. A fixed length rather than a step of the ladder: the zoom threshold does not scale with the type, so keep it at 16px or above
--leading-wk-tight 1.25 Line height for headings and other short, large text, where the default 1.5 opens gaps that read as separate lines
--leading-wk-relaxed 1.625 Line height for long-form body copy — the prose register, where a longer measure needs more room between lines to keep the eye on the right one
--font-wk-heading-xl 2.5rem Heading size used by the marketing surfaces (hero, cta) — separate from the --text-wk-* ladder because a landing headline is sized against the section, not against body copy
--font-wk-heading-2xl 3.5rem The larger of the two marketing heading sizes
--font-wk-heading-line-height 1.25 Line height applied to those marketing headings
--measure-wk 65ch Comfortable reading measure — the max line length prose and the reading components hold text to. Around 65 characters is where a line stays scannable without the eye losing its place on the return sweep
--measure-wk-wide 78ch The wider measure, for content that carries code blocks or tables a 65ch column would squeeze

Overlay Tokens

Variable Default (Light) Default (Dark) Used for
--color-wk-overlay oklch(0% 0 0 / 0.5) oklch(0% 0 0 / 0.7) Modal/Drawer backdrop
--z-wk-dropdown 50 Dropdown z-index
--z-wk-tooltip 60 Tooltip z-index
--z-wk-modal 70 Modal z-index
--z-wk-drawer 70 Drawer z-index
--z-wk-toast 80 Toast region z-index. Above the modal on purpose: a toast reports the RESULT of something the reader just did, and half the time they did it inside a dialog — below it, the confirmation of a save is hidden by the form that saved. The ten-point step leaves room for an application to sit between
--size-wk-modal-sm 24rem Small modal width
--size-wk-modal-md 32rem Default modal width
--size-wk-modal-lg 42rem Large modal width
--size-wk-modal-xl 56rem Extra-large modal width
--size-wk-modal-full 100% Full-width modal
--size-wk-drawer-sm 20rem Small drawer width/height
--size-wk-drawer-md 28rem Default drawer width/height
--size-wk-drawer-lg 40rem Large drawer width/height
--size-wk-drawer-inset 3rem The strip of backdrop left showing beside an open drawer. Every width above is wider than a phone, so the panel is clamped against the viewport and this is what stays visible — it is what makes the drawer read as a sheet over the page rather than as a second page. Lower it for a dense console, raise it to show more of the page
--z-wk-sticky 40 Sticky page furniture that must YIELD to an overlay — a sticky table head, a status-matrix row head, a floating scroll-to-top. A dropdown opened over a table has to paint on top of it, which is why this sits below --z-wk-dropdown
--z-wk-chrome 55 Page chrome that must LEAD — the sticky header and navbar bars. Above --z-wk-dropdown so a popover opened in page content cannot paint over the site header, and below --z-wk-modal so a modal still covers everything. A panel anchored in the header opens downward and never overlaps the bar, so nothing is lost
--space-wk-toast-offset 0px Extra inset for the toast region, added on top of its normal edge distance. Defaults to nothing; set it when app furniture (a bottom nav, a cookie bar) would otherwise sit under the toasts
--wk-scrollbar-inset 0px Width a classic scrollbar takes out of the viewport box, folded into the inline edge of every viewport-pinned surface. Already correct at zero for overlay scrollbars; an app that renders a classic one measures innerWidth - clientWidth once and sets it
--wk-sticky-panel-w 20rem Width of <x-wirekit::sticky-panel>, the companion column beside an article
--indicator-wk-offset 0px Pushes an <x-wirekit::indicator> badge further out from its target's corner. Zero means flush; raise it when the badge would otherwise overlap content it is annotating
--wk-image-compare-handle-size 2.5rem Diameter of the drag handle on <x-wirekit::image-compare>
--wk-image-compare-divider-size 2px Width of the divider line that handle rides on
--size-wk-tooltip-max 20rem Tooltip max width
--color-wk-tooltip-bg text color text color Tooltip background (inverted)
--color-wk-tooltip-text bg color bg color Tooltip text (inverted)

Application shell

The shell's chrome reads a set of ROLES rather than the generic neutrals, and each tone on <x-wirekit::app-rail>, <x-wirekit::sidebar> or <x-wirekit::app-shell> re-points that same set. The table below is the roster — it is the count, so this sentence does not carry one. Override them here to change every tone's fallback at once; override them under a tone's own selector to change one.

A toned navigation column also re-points the generic tokens (--color-wk-text, --color-wk-bg-muted, --color-wk-border, …) to these roles for its own subtree. That is how ordinary components inside a dark rail come out legible without any of them knowing that tones exist — and it is scoped to the navigation surfaces, never to the shell root, so a toned shell with a light content panel keeps its content on the normal palette.

Variable Default (Light) Default (Dark) Used for
--size-wk-shell-bar 3.5rem 3.5rem Height of every <x-wirekit::shell-bar>, and therefore the y-coordinate of the horizontal rule across all of a console shell's columns. One token so the segments cannot drift apart
--size-wk-rail-icon 1.25rem 1.25rem The glyph box a rail entry is built around. It sizes the rail's own width below, and it caps the line box a module name sits in — an entry keeps its height whether or not its name is showing
--size-wk-rail derived derived Rail width with labels="tooltip". Computed rather than set: --size-wk-rail-icon plus the small padding on both axes plus one border, which comes to 3.25rem + 1px today. It is a calc() so that re-tuning the padding scale moves the rail with it — matching the sidebar's own collapsed rail, which is derived the same way, so a shell can switch between the two without the content reflowing
--size-wk-rail-labeled 5.5rem 5.5rem Rail width with labels="below" — room for a caption under the icon
--size-wk-rail-expanded 15rem 15rem Rail width with labels="inline", and while expanded
--size-wk-sidebar-drawer 16rem 16rem Width of the app-shell's sidebar as a slide-over, below the breakpoint where it stops being a column. Its own step because neither existing scale reaches it — the drawer widths start at 20rem and the rail widths top out at 15rem
--wk-nav-pad 0px 0px What a container pads its children by, published so a <x-wirekit::shell-bar bleed> inside it can cancel exactly that much. <x-wirekit::sidebar> sets it; zero everywhere else, so bleed is a no-op outside such a container
--radius-wk-nav-item --radius-wk-md --radius-wk-md The corner radius of a navigation item — a sidebar row, a rail module. A rounded column re-points it for its own subtree so the two arcs stay CONCENTRIC: an inner corner that is not (outer radius − the gap between them) makes the space between them pinch at 45°. Measured before it was derived: a flat 8px whichever surface the item sat in — nearly right by coincidence in a 16px rail, more than twice too round in a 10px card
--wk-rail-item-aspect auto auto The shape of a module in the icon-only rail. auto is a pill as tall as its content; 1 makes every module a SQUARE, which is what an app icon is everywhere else. Applied only where nothing shares the box with the glyph — a square with a word under it is not a square
--radius-wk-shell-panel --radius-wk-xl --radius-wk-xl Corner radius of an inset content panel (<x-wirekit::app-shell panel>) and of <x-wirekit::app-rail variant="panel">. Its own token because the panel is the largest rounded surface on the page, and a theme wanting sharp cards with a soft shell has no way to say so if the two share a value
--color-wk-rail-bg bg-elevated bg-elevated Navigation surface
--color-wk-rail-text text text Navigation foreground
--color-wk-rail-muted text-muted text-muted Resting item foreground
--color-wk-rail-hover-bg bg-muted bg-muted Item hover surface
--color-wk-rail-active-bg bg-muted bg-muted Current item's fill, with indicator="pill"
--color-wk-rail-active-text text text Current item's foreground on the COLUMN, and the indicator="edge" bar
--color-wk-rail-hover-fg text text Foreground on a hover FILL. The same color as the one above on a neutral surface, and deliberately not on a colored one
--color-wk-rail-active-fg text text Foreground on the current item's FILL
--color-wk-rail-border border border Column edges, group separators, and the shell rule
--color-wk-rail-ring ring ring Focus ring inside the column. Its own role because a ring tuned for the page background can fall below the 3:1 contrast floor on a dark rail
--color-wk-rail-badge accent accent The counter dot on a module, and the pill it becomes in a wide rail. Its own role because the rail is the one surface whose background is a tone: on a dark column the page accent is near-black on near-black, and the mark whose whole job is to say "there is something here" is the one that disappears
--color-wk-rail-badge-fg accent-fg accent-fg The digits carried on that pill

The tones

Tone Surface Notes
default --color-wk-bg-elevated The roles above, unchanged
muted --color-wk-bg-muted Hover and active are mixes of the tone's own text, so the step is visible in both light and dark; a fixed lighter/darker token only works in one of them
inverse oklch(20.5% 0 0) Deliberately mode-INDEPENDENT, and there is no dark override. --color-wk-bg-inverse cannot be used here because it flips to near-white under .dark, which would turn an "inverse" rail white on a dark page. 20.5% is also dark mode's own elevated surface, so one value is correct in both modes rather than two that must be kept in step. Measured: white on it is ~14.9:1 and the muted step ~7.5:1
accent --color-wk-accent Every role that carries text is a plain alias of --color-wk-accent or --color-wk-accent-fg, with no mix. Muted text equals the full foreground, and hover and the current item INVERT — the fill becomes the foreground color and the label becomes the accent. That is the guaranteed pair read backwards, so the tone's contrast is the accent pair's, which is already verified for every bundled preset in both modes. Tinting was tried in both directions first and neither is safe: a mix toward the foreground measured 1.73:1 to 4.17:1 across five presets, and a mix the other way still failed on one, because the percentage depends on an accent each theme defines

Scrollbar

Variable Default (Light) Default (Dark) Used for
--color-wk-scrollbar-thumb neutral-300 neutral-600 Scrollbar thumb color
--color-wk-scrollbar-thumb-hover neutral-400 neutral-500 Scrollbar thumb on hover
--color-wk-scrollbar-track transparent transparent Scrollbar track background
--size-wk-scrollbar 6px Scrollbar width/height
--fade-wk-size 2rem Depth of the scroll-area edge fade (<x-wirekit::scroll-area fade="…"> / .wk-scroll-fade)

Apply the .wk-scrollbar CSS class to any scrollable element for a slim, themed scrollbar:

<div class="wk-scrollbar overflow-auto max-h-64">
    <!-- long content here -->
</div>

The class uses scrollbar-width: thin for Firefox and ::-webkit-scrollbar pseudo-elements for Chrome/Safari/Edge.

Reading Component Tokens

Tokens for the reading-* component family — six primitives for long-form content pages. Override any of them in your :root {} block to retheme without touching the component source.

Reading Progress

Variable Default Used for
--reading-progress-height-sm 2px Bar height when height="sm"
--reading-progress-height-md 3px Bar height when height="md" (default)
--reading-progress-height-lg 5px Bar height when height="lg"
--reading-progress-dot-size 2.5rem Diameter of the dot indicator (when indicator="dot")
--reading-progress-fill (unset) Developer-side fill override — set to win over the variant-resolved color for theme-wide retheming
--reading-progress-segment (unset) Color of the chapter dividers the segments prop paints. Unset they follow --color-wk-border-strong, so they flip with the theme; set it to retint them alongside --reading-progress-fill

Variant rendering: each variant resolves through var(--reading-progress-fill, var(--color-wk-X)), so the --reading-progress-fill token wins when set. Default variants pull from --color-wk-accent (primary, info), --color-wk-text-muted (neutral), --color-wk-success / --color-wk-warning / --color-wk-danger (semantic). The auto variant falls back to currentColor for embedded contexts.

Reading Spine

Variable Default Used for
--reading-spine-width-collapsed 1.5rem Width of the collapsed (ticks-only) spine
--reading-spine-width-expanded 16rem Width when expanded on hover/focus
--reading-spine-gap 0.125rem Vertical gap between ticks
--reading-spine-tick-height 2px Tick line thickness
--reading-spine-edge-offset 1rem Distance from the viewport edge position chose. Set it here to move every spine in an application, or per call site with the edge-offset prop; 0 sits the spine flush against the window
--reading-spine-color-idle var(--color-wk-text-subtle) Inactive tick / label color
--reading-spine-color-active var(--color-wk-text) Active tick / label color
--reading-spine-bg color-mix(in srgb, var(--color-wk-bg-elevated) 92%, transparent) Spine panel background
--reading-spine-padding-x 0.5rem Inline padding of the spine panel
--reading-spine-padding-y 0.875rem Block padding of the spine panel
--reading-spine-list-padding-x = spine-padding-x Inline padding of the tick list inside the panel. Its own knob so the list can be inset further than the panel without moving the panel's edge
--reading-spine-list-padding-y = spine-padding-y Block padding of that list
--reading-spine-offset-top 1rem Distance from the top of the sticky viewport to the spine
--reading-content-spine-gutter 12rem Space the article reserves beside itself for the spine. It is the article's gutter, not the spine's width — the spine expands on hover, and this is what keeps that expansion from landing on the text
--reading-spine-edge-gradient elevated-bg fade The mask that dissolves the spine's inner edge into the page. A gradient rather than a solid so the panel has no hard seam against the article at any background

Reading Minimap

Variable Default Used for
--reading-minimap-width 60px Column width
--reading-minimap-stripe-height 2px Stripe height per item
--reading-minimap-stripe-gap 1px Vertical gap between stripes
--reading-minimap-color-idle var(--reading-spine-color-idle) Inactive stripe color (reuses spine color for theme-consistency)
--reading-minimap-color-active var(--reading-spine-color-active) Active stripe color (item currently in viewport)
--reading-minimap-viewport-bg color-mix(in oklab, var(--color-wk-accent) 25%, transparent) Viewport-overlay background
--reading-minimap-viewport-border 2px solid color-mix(in oklab, var(--color-wk-accent) 70%, transparent) Viewport-overlay border
--reading-minimap-viewport-radius var(--radius-wk-sm) Viewport-overlay corner radius
--reading-minimap-block-bg tinted from the idle color Fill of one block in the block-texture mode
--reading-minimap-block-gap 2px Vertical gap between those blocks
--reading-minimap-block-radius 2px Corner radius of a block
--reading-minimap-anchor-font-size 0.625rem Size of a section anchor label beside the map
--reading-minimap-anchor-text-color var(--color-wk-text-muted) Resting color of that label
--reading-minimap-anchor-text-color-hover var(--color-wk-text) Its hover color
--reading-minimap-anchor-inboard-bg var(--color-wk-bg) Backdrop of a label that moved inside because the outboard edge had no room. That label lies on the article, so the backdrop covers the text beneath instead of letting the two cross
--reading-minimap-anchor-inboard-padding 0 var(--padding-wk-x-xs) Inline room between that backdrop's edge and its label
--reading-minimap-anchor-inboard-radius var(--radius-wk-sm) Corner radius of that backdrop
--reading-minimap-bookmark-marker-color var(--color-wk-accent) The marker drawn at a bookmarked position
--reading-minimap-bookmark-marker-height 2px Its thickness
--reading-minimap-idle-delay 3s How long the map waits, untouched, before fading toward its idle opacity
--reading-minimap-idle-opacity 0.3 The opacity it fades to. Never 0 by default: a map that disappears entirely cannot be found again by a reader who did not know it was there
--reading-minimap-idle-transition 250ms Duration of that fade, in both directions
--reading-minimap-preview-size 200px Width of the hover preview popped out from the map
--reading-minimap-preview-scale 0.25 Scale the previewed content is drawn at inside it
--reading-minimap-preview-bg var(--color-wk-bg-elevated) Preview background
--reading-minimap-preview-border 1px solid var(--color-wk-border) Preview border
--reading-minimap-preview-shadow var(--shadow-wk-md) Preview elevation
--reading-minimap-rendered-placeholder-bg var(--color-wk-bg-elevated) Backing color shown in mode="rendered" before the canvas has painted
--reading-minimap-rendered-radius var(--radius-wk-sm) Corner radius of that rendered canvas

Rendered-mode canvas colors (mode="rendered" only)

The rendered-mode minimap paints an abstract content-texture map onto a canvas — one rectangle per rendered text line, colored by the source element's role. Override any of these tokens in your :root {} and .dark {} blocks to retheme the canvas without touching JS.

These thirteen are the only reading tokens that carry a raw color literal rather than resolving through a --color-wk-* role, so unlike the rest of the family they do not flip with the theme on their own — each ships an explicit light and dark value. If you override one, override both: a :root-only override leaves your dark canvas painting the light color, and a canvas whose marks match its background still renders, it just shows no hierarchy. The alpha is the density encoding, so keep it the same across the pair and change only the hue.

Variable Default (Light) Default (Dark) Used for
--reading-minimap-color-h1 rgba(15, 23, 42, 0.85) rgba(226, 232, 240, 0.85) h1 lines (densest — top of structural hierarchy)
--reading-minimap-color-h2 rgba(15, 23, 42, 0.75) rgba(226, 232, 240, 0.75) h2 lines
--reading-minimap-color-h3 rgba(15, 23, 42, 0.65) rgba(226, 232, 240, 0.65) h3 lines
--reading-minimap-color-h4 rgba(15, 23, 42, 0.55) rgba(226, 232, 240, 0.55) h4 lines
--reading-minimap-color-h5 rgba(15, 23, 42, 0.48) rgba(226, 232, 240, 0.48) h5 lines
--reading-minimap-color-h6 rgba(15, 23, 42, 0.42) rgba(226, 232, 240, 0.42) h6 lines
--reading-minimap-color-code rgba(99, 102, 241, 0.55) rgba(129, 140, 248, 0.55) <pre>, <code>, <kbd>, <samp>
--reading-minimap-color-table rgba(244, 63, 94, 0.50) rgba(251, 113, 133, 0.50) <table>, <td>, <th>, <caption>
--reading-minimap-color-blockquote rgba(71, 85, 105, 0.55) rgba(148, 163, 184, 0.55) <blockquote>
--reading-minimap-color-prose rgba(71, 85, 105, 0.42) rgba(148, 163, 184, 0.42) <p>, <li>, <dd>, <dt>, <figcaption>
--reading-minimap-color-wirekit rgba(16, 185, 129, 0.50) rgba(52, 211, 153, 0.50) Any WireKit component ([class*="wk-"], excluding the minimap's own wk-reading-* siblings)
--reading-minimap-color-image rgba(245, 158, 11, 0.55) rgba(251, 191, 36, 0.55) <img>, <picture>, <figure>, <svg>, <video>, <canvas> (drawn as block rectangles at natural element bounds)
--reading-minimap-color-default rgba(71, 85, 105, 0.32) rgba(148, 163, 184, 0.32) Anything else (fallback)

Reading TOC

Variable Default Used for
--reading-toc-bg var(--color-wk-bg-elevated) Strip background. It was documented here as a 92% color-mix — the sibling --reading-spine-bg is one, and this is not; the strip is opaque
--reading-toc-color-idle var(--reading-spine-color-idle) Inactive link color (reuses spine color for theme-consistency)
--reading-toc-color-active var(--reading-spine-color-active) Active link color (the section the reader is in)
--reading-toc-padding-y 0.5rem Vertical padding inside the strip
--reading-toc-padding-x 1rem Horizontal padding inside the strip
--reading-toc-gap 1rem Gap between adjacent links
--reading-toc-link-max-width 24ch Per-link max-width — long heading text gets ellipsis-truncated rather than overflowing the strip

Reading Bookmark

Variable Default Used for
--reading-bookmark-pill-bg var(--color-wk-bg-elevated) "Resume reading?" pill background
--reading-bookmark-pill-radius var(--radius-wk-full, 9999px) Pill border radius
--reading-bookmark-pill-shadow var(--shadow-wk-md) Pill drop shadow

Reading Meta

Variable Default Used for
--reading-meta-text-size 0.875rem Time-to-read text size
--reading-meta-color var(--color-wk-text-muted) Time-to-read text color
--reading-meta-paragraph-color var(--color-wk-text-subtle) Per-paragraph annotation color (perParagraph mode)
--reading-meta-paragraph-spacing 0.25em Gap between annotation and the paragraph below it (perParagraph mode)

Reading Skeleton

Variable Default Used for
--reading-skeleton-pulse-opacity 0.5 Opacity the reading placeholder pulses down to while content loads. It is the floor of the pulse, not its resting value, so a lower number reads as a stronger heartbeat. Inert under prefers-reduced-motion — see below

Reduced Motion

All reading-* components honor prefers-reduced-motion: reduce via the global @media block in dist/wirekit.css. Every transition (bar fill transform: scaleX, dot stroke dashoffset, spine width / label opacity / tick color, bookmark pill enter/leave, minimap stripe color transitions, smooth-scroll on link click) collapses to 1ms — values still update on scroll, just without easing.

The system preference is not the only way in. An application that offers the choice in its own settings puts data-reduce-motion="reduce" (or "no-preference") on <html> and these same rules follow it — see the Integration guide for reading it off the signed-in reader, and Theming for the rest of the motion surface.

All five UI primitives (reading-progress, reading-spine, reading-minimap, reading-bookmark, reading-meta) carry a @media print { display: none !important } rule scoped via marker classes (.wk-reading-progress, .wk-reading-spine, .wk-reading-minimap, .wk-reading-bookmark, .wk-reading-meta). Print-friendly for blog-to-PDF workflows — only the article body prints, not the reading chrome.

Chart Theming

When charts are enabled, the <x-wirekit-chart> component automatically reads WireKit CSS variables for consistent theming:

Variable Chart Usage
--color-wk-accent Primary dataset color
--color-wk-danger Second dataset color
--color-wk-success Third dataset color
--color-wk-warning Fourth dataset color
--color-wk-info Fifth dataset color — a fixed cyan (#0891b2 light, #a5f3fc dark) rather than an alias, so it does not follow your accent. Override it in your @theme block to re-tone it.
--color-wk-text Legend text color
--color-wk-text-muted Axis tick labels
--color-wk-border Grid line color
--font-wk-sans Chart font family

Overriding these tokens in your @theme block automatically updates chart colors. See the Chart documentation for details.

See Also

  • Theming — setup guide, theme presets, accent-color, accessibility guarantees
  • Customization — when to override tokens vs. tweak PHP defaults vs. apply scope-based personalization
  • Variants & Intents — cross-component reference for color/severity props

Was this page helpful?

Thank you for your feedback!

Voting requires cookies or local storage. What we store