Foundations

Tokens and themes

The palette, semantic and component CSS variables, light, dark and auto themes, and overrides from a root or one element.

Token layers

Every data-plf-root element declares the full set of public --plf-* variables in three layers; override the highest layer that fits.

Layer Example Role
Palette --plf-blue-600 Raw colors, the same in every theme
Semantic --plf-color-primary, --plf-space-4 Meaning; themes remap colors to palette values
Component --plf-button-bg One component’s override, with a semantic fallback; listed in each component guide

Variables named --_plf-* are internal and are not a public contract.

Themes and cascade

Set data-plf-theme on a root:

data-plf-theme Theme
No value Light
dark Dark
auto Follows the device’s setting

The root sets the matching native color-scheme (light dark for auto), and each semantic color holds a light and a dark value through light-dark(), which takes the one the scheme names. A script that needs a color sets the variable as an element’s color and reads getComputedStyle(element).color, the value in that element’s theme; reading the variable itself gives the light-dark() text.

Light
Dark
System

An unrecognized value falls back to light. A root sets the text color and font for its content but does not paint a page background, and the theme is not stored; Theme Switch changes it from a menu or toggles. A nested root restores the default tokens instead of inheriting its outer root’s.

Overrides

Load your stylesheet after the library CSS and target the root you mean; a value set there reaches light, dark and auto roots alike. A brand is primary and on-primary, as the hover and accent text derive from primary; light-dark() gives each a light and a dark value, as Core’s colors have, and every root picks one by its theme.

CSS
.my-plugin[data-plf-root] {
  --plf-color-primary: light-dark(#15803d, #4ade80);
  --plf-color-on-primary: light-dark(#fff, #052e16);
  --plf-radius-lg: 0.25rem;
}

The class names the theme, such as a client’s: combine it with data-plf-theme on the root, and give a nested root the class too, as a nested root restores the default tokens. A value for one theme only goes in a [data-plf-theme="dark"] rule.

Every color in Semantic colors is overridden the same way, and the derived colors follow it. A color brings the text on it, and a status color its soft fill:

You set Set with it Follows it
--plf-color-primary, the fill of buttons, solid badges and checkboxes and the focus ring --plf-color-on-primary, the text on a primary fill The hover; primary-text, its text on the page, such as a link, a checkmark or an outline badge; the primary-subtle and primary-border fills and the focus ring
--plf-color-success, -warning, -danger or -info, the fill of buttons, solid badges and progress bars and the border of an invalid field on-{color}, the text on its fill; {color}-text, its text on the page and on the soft fill, such as an alert’s text or an error message; {color}-bg, the soft fill of soft badges and buttons The button hover and {color}-border (danger-subtle too)

primary-text mixes 80% of primary into the text, which suits a primary with a light and a dark shade, as above. One color for both themes, such as #0ea5e9, sets it with a 50% mix, which reads at 4.5:1 or more for Tailwind CSS’s 400 to 950 colors: --plf-color-primary-text: color-mix(in srgb, var(--plf-color-primary) 50%, var(--plf-color-text)). A status color’s text and soft fill can follow the color, mixed into the root’s text and surface, which keeps the text readable on light and dark roots (6.5:1 or more for Tailwind CSS’s 500 and 600 colors):

CSS
.my-plugin[data-plf-root] {
  --plf-color-success: light-dark(#15803d, #4ade80);
  --plf-color-on-success: light-dark(#fff, #052e16);
  --plf-color-success-bg: color-mix(in srgb, var(--plf-color-success) 15%, var(--plf-color-surface));
  --plf-color-success-text: color-mix(in srgb, var(--plf-color-success) 40%, var(--plf-color-text));
}

One element

Set a semantic or component variable on one element, usually inline. Components read their variables through fallbacks rather than assigning them, so root and element overrides both reach them.

Tokens the root computes from others keep the root’s values on an element: the derived colors, focus-color, space-*, font-size-*, radius-* and the control heights. Set --plf-rem, --plf-spacing and --plf-radius-lg on a root, and with primary on one element, set the colors derived from it there too, such as focus-color, primary-hover and primary-text.

Check every custom color pair for contrast in its theme and host page; the library’s contrast checks cover only the defaults.

Palette

Each suffix expands to --plf-{suffix} and holds Tailwind CSS v4’s value of that color, in oklch(); white is #fff.

  • white
  • neutral-50
  • neutral-400
  • neutral-500
  • neutral-600
  • neutral-900
  • neutral-950
  • blue-400
  • blue-600
  • green-100
  • green-300
  • green-500
  • green-800
  • green-900
  • green-950
  • amber-100
  • amber-300
  • amber-400
  • amber-800
  • amber-900
  • amber-950
  • red-100
  • red-300
  • red-500
  • red-700
  • red-900
  • red-950
  • sky-100
  • sky-300
  • sky-800
  • sky-900
  • sky-950

Semantic colors

Each one can be overridden, as Overrides shows. Color utilities name them as daisyUI does:

  • surface, surface-raised and surface-muted are base-100, base-200 and base-300.
  • text is base-content.
  • danger is error.
  • Each on-{color} is {color}-content.
Variable Light Dark
--plf-color-primaryblue-600blue-400
--plf-color-on-primarywhiteneutral-950
--plf-color-surfacewhiteneutral-950
--plf-color-surface-raisedneutral-50neutral-900
--plf-color-textneutral-950neutral-50
--plf-color-text-mutedneutral-600neutral-400
--plf-color-borderneutral-500neutral-500
--plf-color-backdroprgb(0 0 0 / 50%)Same
--plf-color-success, --plf-color-on-successgreen-800, whitegreen-300, green-950
--plf-color-success-bg, --plf-color-success-textgreen-100, green-900green-950, green-300
--plf-color-warning, --plf-color-on-warningamber-800, whiteamber-300, amber-950
--plf-color-warning-bg, --plf-color-warning-textamber-100, amber-900amber-950, amber-300
--plf-color-danger, --plf-color-on-dangerred-700, whitered-300, red-950
--plf-color-danger-bg, --plf-color-danger-textred-100, red-900red-950, red-300
--plf-color-info, --plf-color-on-infosky-800, whitesky-300, sky-950
--plf-color-info-bg, --plf-color-info-textsky-100, sky-900sky-950, sky-300

Derived colors

These are built from the colors above, so theme and root overrides carry through; an element override does not recompute them (One element). The subtle colors mix with transparent, so they take the surface beneath them: on a card in dark mode they come out a step lighter than on the page.

VariableLightDark Mix Use
--plf-color-primary-hover 90% primary, 10% text Hover fills: darker in light, lighter in dark
--plf-color-primary-text 80% primary, 20% text Primary as text: links, checkmarks, a current page, a pressed toggle, and soft and outline badges
--plf-color-border-subtle 30% border Decorative borders and dividers
--plf-color-input 88% border; the full border in dark mode Editable field boundaries, kept at 3:1 contrast with the field and the surface
--plf-color-surface-muted 20% border Neutral fills such as skeletons, item hover and hovered input group addon buttons
--plf-color-primary-subtle 10% primary Soft selected or current fills
--plf-color-danger-subtle 10% danger Destructive item hover
--plf-color-primary-border, --plf-color-success-border, --plf-color-warning-border, --plf-color-danger-border, --plf-color-info-border 40% of the accent Colored decorative outlines, such as outline Badges
--plf-color-surface-elevated surface; surface-raised in dark mode Cards and floating surfaces: popovers, menus, lists, Command, Hover Card and toasts, a step above the page in dark mode, as on shadcn/ui
--plf-color-surface-hover surface-raised; surface-muted in dark mode Hover and soft fills that also show on a card: outline and ghost Buttons, Choice Cards, muted Items and striped rows
--plf-color-field surface; 4.5% text in dark mode Fields, outline Buttons and the selected tabs-box tab, as shadcn/ui’s dark fill
--plf-color-input-hover border; 80% border, 20% text in dark mode Hovered field boundaries, stronger than input in both themes

Typography

Each suffix expands to --plf-{suffix}. The Typography guide covers prose, including the --plf-prose-mark-bg and --plf-prose-mark-color highlight overrides.

Suffix Default
font-family system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif
font-family-mono ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace
font-size-xs, font-size-sm, font-size-body, font-size-lg, font-size-xl, font-size-2xl, font-size-3xl 0.75rem, 0.875rem, 1rem, 1.125rem, 1.25rem, 1.5rem, 1.875rem (12–30px at a 16px root)
font-size-4xl to font-size-9xl 2.25rem, 3rem, 3.75rem, 4.5rem, 6rem, 8rem
font-weight-normal, font-weight-medium, font-weight-semibold, font-weight-bold 400, 500, 600, 700
line-height, line-height-tight, line-height-relaxed 1.5, 1.25, 1.625
Suffix Default
rem 1rem; every size below is a multiple of it, so 1.6rem restores them on a host whose root font size is 62.5%
spacing 0.25rem; spacing utilities multiply it by their step, as Tailwind CSS’s --spacing
space-0 to space-12 spacing times 0 to 12, for component CSS
radius-xs, radius-sm 0.125rem, 0.25rem
radius-md 0.75 × radius-lg, 0.375rem (6px); inner items such as menu items, tabs, chips and keys
radius-lg 0.5rem (8px); controls and overlays; radius-md and radius-xl follow it
radius-xl 1.5 × radius-lg, 0.75rem (12px); cards and dialogs
radius-2xl, radius-3xl, radius-4xl 1rem, 1.5rem, 2rem
radius-full calc(infinity * 1px); pills
border-width 1px

Sizes are Tailwind CSS’s rem values, as multiples of --plf-rem, so they follow the reader’s browser font size. On a host page whose root font size is not 100%, such as html { font-size: 62.5% }, set --plf-rem on the root to 1rem divided by that factor (Installation).

Suffix Default
control-font-size, control-font-weight font-size-sm (14px), font-weight-medium (500)
input-font-weight font-weight-normal (400), for text typed into fields
control-icon-size calc(1em * 8 / 7), 16px at a 14px control font
control-height-sm, control-height-md, control-height-lg 8, 9 and 10 × spacing: 2rem, 2.25rem, 2.5rem minimum heights
Suffix Light Dark
shadow-2xs to shadow-2xl Tailwind CSS’s shadows: xs for controls and cards, md for popovers, lg for menus, dialogs, sheets and toasts The same geometry with three times the alpha (0.15, 0.3; 0.5 for 2xl)
focus-color, focus-width, focus-offset color-primary, 2px, 2px Same

Every control shows one focus outline from the focus variables; fields use an offset of focus-offset − focus-width (0px) so the ring meets their border.

Motion and layers

Durations become 0ms under prefers-reduced-motion: reduce.

Suffix Default
duration-fast, duration-normal, easing 120ms, 180ms, ease-out
duration-enter, easing-enter 200ms, cubic-bezier(0.16, 1, 0.3, 1), for opening dialogs, sheets and toasts; closing is immediate
z-index-base, z-index-sticky, z-index-overlay, z-index-modal 0, 900, 1000, 1100; native modal dialogs use the browser top layer instead
Suffix Default
sticky-offset 0px; the sticky header’s block size, see Sticky and skip links
scroll-offset sticky-offset plus 1rem, where a link target stops; set sticky-offset on the root

Built with Pelatform UIv0.1.0

Documentation

Getting started

Foundations

Components

Actions

Data display

Navigation

Feedback

Data input

Layout

Advanced

Integrations

Blocks

Application

Authentication

Icons