Skip to content
ShineUI
Install

Theming

Every element paints itself from one set of color tokens. Change the tokens and the whole library follows. Type, spacing and radii stay put; shadows follow the ground, so a panel still lifts in dark.

The palette

The roles a theme fills, painted from the theme in force. Pick a preset or a mode in the header and every chip follows; the pick is saved in this browser. Click a chip to copy its value.

Readability checks

Each row is a text color measured against the ground it sits on, with the two token names under it. The bar is 4.5:1, WCAG AA for text at normal size; the engine walks a derived pair darker or lighter until it clears, and says below the list what it moved.

One pair does not move and does not clear: on the shipped light theme --accent-ink reads 4.3:1 on --accent-soft. Both are fixed brand values, so the answer is a second ink. Write small text on soft accent fills in --accent-soft-ink, 5.3:1, and keep --accent-ink for the larger sizes AA measures at 3:1. Every other preset derives its accent ink and clears 4.5:1.

Every token

The tokens the library reads, with each one's role and its value under the theme in force. Click a row to copy the name. Each component page lists the tokens that element reads.

The eight --palette-* tokens are the raw colors under the semantic ones: deep blue, orange, deep orange, blue-gray, slate, link blue, white and black. Elements paint from the semantic tokens, such as --ink, --brand and --accent. They take a palette token only where a color must hold in every theme, as white does behind a QR code. A custom theme fills the palette from its own ink, accent, border and link.

Every theme meets WCAG 2.1 AA. Text comes in three tiers: ink, muted and faint. Muted reads at least 7:1, faint at least 4.8:1 in light and 5.4:1 in dark, on a card, a well, the page and a raised panel, and a field's placeholder 4.5:1. The edge of a field and the chart axis read 3:1, and no chart series reads lighter than its axis. Accessibility has the figures.

Loading the token index.

Theming from code

The engine behind the picker ships as @shineui/core/theme: derive, tokensToCss, the preset and neutral tables, applyTheme and readTheme. applyTheme takes an element or a selector (html by default) and a choice, and writes what the picker writes: the data-sui-* attributes, and a <style data-sui-custom-theme> sheet with both modes when the pair is not a shipped preset. It returns the tokens it derived.

This call sets data-sui-preset="custom" and data-sui-status="semantic" on the document, sets data-sui-theme="dark" while the operating system asks for dark, and appends one sheet with the light tokens under html[data-sui-preset="custom"] and the dark tokens under data-sui-theme="dark". theme.light and theme.dark hold the tokens, theme.css the sheet, and theme.dispose() stops it following the system. readTheme returns the choice in force, mode: "system" and what it resolved to included. A shipped pair such as { preset: "evergreen" } writes the attribute alone, because the token sheet already carries it. The picker calls the same function, so a page can mix the two.

For a build step, derive(primary, accent, neutral, status, dark) returns the tokens of one mode and tokensToCss(selector, tokens) prints them.

Download the theme

Save the file below as theme.css and load it after shineui.css.

It carries both modes, light on :root and dark under data-sui-theme="dark", and both code pane ramps, so data-sui-code keeps working.