3 Topics
Chapter•55 Minutes

Arbitrary Values and Custom Utilities

Use one-off values, custom properties, selector variants, and custom CSS without undermining consistency.

Arbitrary values and properties

When a design requires a value outside the standard scale, Tailwind supports bracket notation for many utilities, such as w-[37rem], grid-cols-[220px_minmax(0,1fr)], or top-[var(--header-height)]. Arbitrary values are useful for precise exceptions, but frequent one-off values may indicate a missing design token.

Spaces in arbitrary values often use underscores in class syntax. Follow the exact syntax supported by your Tailwind version, especially for CSS functions and custom properties. Avoid placing user-controlled input directly into class names.

A custom grid track and CSS variable
<div style="--sidebar-width: 14rem" class="grid grid-cols-1 gap-5 lg:grid-cols-[var(--sidebar-width)_minmax(0,1fr)]">
  <aside class="rounded-xl border p-4">Sidebar</aside>
  <main class="min-w-0 rounded-xl border p-4">Main content</main>
</div>
đź’ˇ The custom grid template gives the sidebar a variable width and lets the main content consume the remaining space. The single-column base layout remains usable on small screens. For repeated use, define the variable in a stable design-token layer rather than repeating inline styles.
Key Takeaways
  • Use arbitrary values for real exceptions, not every value.
  • Use underscores where arbitrary-value syntax needs spaces.
  • Promote repeated one-off values into reusable design tokens.

CSS variables and design tokens

CSS custom properties let you express design decisions by role. A variable can hold a brand color, header height, spacing value, or surface color. Tailwind utilities can reference CSS variables, allowing a token to be changed centrally while components retain their structure.

A good token system separates raw palette values from semantic roles. For example, a blue palette may contain several shades, while --color-action represents the shade chosen for primary actions. This makes future rebranding and theme changes easier.

Choose semantic names

--color-action explains the role; --blue-700 describes the current color. Semantic tokens make theme changes easier to reason about.

Semantic token example
:root {
  --color-action: #1d4ed8;
  --color-surface: #ffffff;
  --color-text: #0f172a;
  --radius-card: 1rem;
}

[data-theme="dark"] {
  --color-surface: #0f172a;
  --color-text: #f1f5f9;
}
đź’ˇ This illustrates semantic CSS variables independent of any particular Tailwind config. Components can consume the variables using supported arbitrary-value syntax or project-level theme definitions. Check contrast when changing token values.

When to write custom CSS or extract components

Tailwind is not a rule that forbids CSS files. Use custom CSS for complex pseudo-elements, intricate animations, third-party overrides, or selectors that become awkward as utilities. Use components for repeated UI structures with meaningful behavior or API boundaries.

In React, extract a component when repetition, semantic meaning, behavior, or testing needs justify it—not merely because a class string has many tokens. A PrimaryButton can centralize interaction states and accessibility; a generic wrapper with dozens of boolean props can become harder to maintain than the original markup.

React component with a class map
const buttonVariants = {
  primary: "bg-blue-600 text-white hover:bg-blue-700 focus-visible:outline-blue-600",
  secondary: "border border-slate-300 bg-white text-slate-900 hover:bg-slate-50 focus-visible:outline-slate-500",
};

export function Button({ variant = "primary", children, ...props }) {
  return (
    <button
      {...props}
      className={`inline-flex items-center justify-center rounded-lg px-4 py-2.5 text-sm font-semibold focus-visible:outline-2 focus-visible:outline-offset-2 ${buttonVariants[variant]}`}
    >
      {children}
    </button>
  );
}
đź’ˇ The variant map contains complete class candidates. The component shares structure and focus behavior while keeping the visual difference explicit. For production TypeScript, constrain variant to the supported keys and merge caller classes with a deliberate class-merging strategy if overrides are allowed.
Knowledge Check

When is extracting a Tailwind pattern into a component most useful?