Theme system

Themes.

Choose one of three production-ready visual flavours, then control its force with coordinated strength and radius settings. BRUT/UI preserves shadcn's semantic colour contract throughout.

Light mode only. The default combination is Paper, Soft, and Cut.

Live theme

Tune the whole system live.

Changes apply across the app until the browser reloads.

Flavour
Brutalism
Radius

01 / Flavours

Three identities. One reliable system.

Paper, Signal, and Sky each remap the familiar shadcn semantic variables into a coherent production theme. Components reference roles—not hard-coded colours—so an entire application can change flavour without changing its composition.

Paper

data-brut-palette="paper"
Flavour

Warm off-white canvas, near-black structure, yellow primary, and blue secondary.

Background
Foreground
Primary
Secondary

Signal

data-brut-palette="signal"
Flavour

Yellow canvas, pitch-black structure, red secondary, and cool blue accent.

Background
Foreground
Primary
Secondary

Sky

data-brut-palette="sky"
Flavour

Light sky-blue canvas, ink-blue structure, saturated blue primary, and yellow secondary.

Background
Foreground
Primary
Secondary

02 / Strength

One dial, coordinated force.

Soft, Solid, and Loud scale border width, slider thickness, shadow depth, tactile movement, and interactive type weight together. The hierarchy stays intentional at every level.

ModeBorderControl shadowPanel shadowSliderHoverPressWeight
Soft1px2px4px2px-1px1px600
Solid2px4px7px4px-1px2px700
Loud3px6px9px6px-2px3px800

03 / Radius

Corners stay coordinated.

Sharp, Cut, and Chunky coordinate component shells with their internal parts. Semantic circles—such as radio indicators and avatars—remain circular.

Sharp

0rem · sharp

Cut

0.375rem · cut

Chunky

0.875rem · chunky

04 / Custom tokens

The brutalist layer.

A compact set of project-wide tokens adds brutalist structure without replacing shadcn's theme contract. Shared utilities keep those measurements consistent across components.

--brut-borderShared border widthComponent boundaries, dividers, radio indicators, and slider thumbs.
--brut-slider-trackSlider track thicknessKeeps sliders restrained while scaling from 2px to 6px by strength.
--brut-shadow-xControl shadow X offsetButtons, inputs, and normal surfaces.
--brut-shadow-yControl shadow Y offsetKeep paired with the X offset for hard shadows.
--brut-panel-shadow-xPanel shadow X offsetCards, dialogs, and high-level containers.
--brut-panel-shadow-yPanel shadow Y offsetUse only for visually important surfaces.
--brut-shadow-colorHard-shadow colorUsually follows the active flavour's foreground or border color.
--brut-hoverHover translationMoves tactile controls up and left.
--brut-pressPressed translationMoves controls into their hard shadow.
--brut-weightInteractive font weightScales label weight with brutalism strength.
--radiusShared corner radiusControlled by Sharp, Cut, or Chunky.

05 / Semantic colors

The shadcn contract, preserved.

BRUT/UI keeps shadcn's semantic variables as its foundation and maps every flavour onto those established roles. Familiar shadcn compositions therefore remain compatible while Paper, Signal, and Sky can restyle the complete interface consistently.

--background / --foreground

Page canvas and default text.

--card / --card-foreground

Cards and elevated content surfaces.

--popover / --popover-foreground

Menus, popovers, dialogs, and floating content.

--primary / --primary-foreground

Primary actions and strongest emphasis.

--secondary / --secondary-foreground

Supporting actions and contrasting regions.

--muted / --muted-foreground

Quiet surfaces, metadata, and supporting copy.

--accent / --accent-foreground

Highlights and temporary interaction states.

--destructive

Irreversible or dangerous actions and invalid states.

--border / --input / --ring

Structure, form boundaries, and keyboard focus.

06 / Utilities

Build hierarchy, not repetition.

Controls, surfaces, panels, and overlays deliberately carry different visual weight. Choose the utility that matches the component's role instead of applying the same hard shadow everywhere.

.brut-panelHigh-emphasis containerLarge cards, dialogs, showcase sections
.brut-surfaceStandard hard-shadow surfaceCards and grouped content
.brut-controlTactile interactive surfaceButtons and clickable controls
.brut-quietBorder-on-hover interactionNavigation and low-priority actions
.brut-focusVisible keyboard outlineCustom interactive elements
.brut-inputTactile form fieldInputs and textareas
.brut-input-groupGrouped field boundaryInput addons and compound fields
.brut-chip / .brut-toggleFlat compact boundaryBadges, toggles, and dense controls
.brut-popoverFloating hard-shadow surfaceMenus, hover cards, and popovers
.brut-dialogHigh-emphasis overlayDialog and alert-dialog content

07 / Guidelines

Use force with intent.

A brutalist interface still needs hierarchy, predictable interaction, and accessible focus.

Separate hierarchy

Use panel shadows for overlays and major containers, normal shadows for controls, and border-only styling for compact items.

Preserve tactile motion

Interactive controls move up on hover and collapse into their shadow when pressed. Static surfaces should not move.

Never hide focus

Use --ring and .brut-focus for a visible outline. A hard shadow is not a replacement for keyboard focus.

Compose with semantic roles

Use bg-card, bg-popover, border-border, and text-muted-foreground so flavours remain interchangeable.

08 / Configuration

Set the theme at the root.

The three data attributes form the public configuration API. Change them together on the document root; every registry component reads the resulting CSS variables.

HTML
<html
  data-brut-palette="paper"
  data-brut-strength="soft"
  data-brut-radius="cut"
>
Component CSS
.custom-surface {
  border: var(--brut-border) solid var(--border);
  border-radius: var(--radius);
  background: var(--card);
  box-shadow: var(--brut-shadow-x)
    var(--brut-shadow-y) 0
    var(--brut-shadow-color);
}