zudo-css

Type to search...

to open search from anywhere

Component Tokens & Arbitrary Values

CreatedMar 13, 2026UpdatedMar 26, 2026Takeshi Takatsudo

The Problem

When building components with a tight token strategy, teams encounter a recurring question: “The value I need isn’t in our token set — should I add a new token?”

This question arises constantly. A button needs to be exactly 28px wide for its icon. A grid layout requires 120px and 1fr columns. A decorative gradient uses a specific red that doesn’t match any brand color. If the answer is always “add a token,” the token set grows until it’s no longer tight — you’re back to the unconstrained mess the strategy was designed to prevent.

But if the answer is always “use only existing tokens,” developers are forced to use poorly fitting values, creating visually awkward components. Neither extreme works. The missing piece is a clear framework for deciding when a value belongs in the system and when it belongs in the component.

The Solution

The tight token strategy is built on a component-centric philosophy. This aligns closely with Tailwind CSS’s own approach:

  1. Design tokens define the system vocabulary — spacing, colors, typography scales that ensure consistency across all components
  2. Components are built using those tokens — for all standard, reusable spacing and colors
  3. But not everything fits into the system — component-specific details use arbitrary values

The key insight: adding a token is a system-level decision, not a component-level one. When a particular value is unique to a single component’s layout or decoration, it should stay as an arbitrary value (Tailwind’s bracket syntax like w-[28px]), not be promoted to the token set.

When to Use Arbitrary Values

Use Tailwind’s bracket syntax for values that are structural details of individual components, not system-wide patterns:

  • Component-specific sizing — A small icon button that needs exactly w-[28px] p-[6px] for visual balance
  • Grid template columns — Layouts like grid-cols-[120px_1fr] that define one component’s structure
  • Unique icon dimensions — An icon sized to w-[18px] for optical alignment within its context
  • One-off decorative values — A gradient from-[hsl(0_60%_20%)] to-[hsl(0_60%_8%)] used only in one hero section
  • Mathematically calculated values — Offsets like top-[calc(100%-2px)] for precise positioning

When to Use System Tokens

Use tokens from the project’s @theme definition for values that represent shared design decisions:

  • Standard component spacingpx-hsp-sm py-vsp-xs for card padding, section margins
  • Colors with semantic meaningbg-primary text-text-muted for brand and text
  • Gaps between repeated elementsgap-x-hsp-xs gap-y-vsp-sm for grids and flex layouts
  • Any value referenced by name in design specs — If a designer says “use section gap,” that’s a token

Decision Framework

When deciding between a token and an arbitrary value, use this decision tree:

SituationAction
Value represents a design decision (e.g., “section gap”, “icon size”)Add a system token
Value is a structural detail of one component (e.g., grid columns, button padding)Use arbitrary value
Value is mathematically calculated or decorativeUse arbitrary value

Whether to create a token is an architectural and design judgment, not a usage-count threshold. You don’t wait for three components to use a value before tokenizing it — you ask whether the value represents a deliberate design decision. A content column width of 800px is worth tokenizing the moment you decide “our layout is 800px wide,” even if only one page template uses it today. This is the same kind of judgment as “should we extract this function into a utility?” — the answer depends on whether the concept deserves a name in the system, not on how many call sites exist.

Signs You Should Add a Token

  • A designer references the value as a named step (a spacing level, an icon size, a layout width)
  • The value represents a design decision — a deliberate choice about how the UI is structured
  • Changing this value should update the entire system, not one component

Signs You Should NOT Add a Token

  • It’s a structural or layout detail specific to one component’s internal arrangement
  • Adding it would clutter the token set without adding clarity
  • The value has no meaning outside its component context (e.g., a calc() offset for alignment)

Component-First Projects

In projects that combine a component framework (React, Vue, Svelte) with Tailwind CSS, component-tier CSS custom properties are unnecessary. The component architecture itself provides scoping — each component’s template contains its styling directly:

<!-- ProfileCard.tsx — the component file IS the scope -->
<section class="px-hsp-sm py-vsp-sm">
  <div class="grid grid-cols-[80px_1fr] gap-x-hsp-sm">
    <div class="w-[64px] h-[64px] rounded-full" />
  </div>
</section>

There is no separate CSS file where --card-sidebar-width: 80px or --card-avatar-size: 64px would be defined. The arbitrary values live in the JSX as bracket syntax, and the component file boundary provides all the scoping needed.

Component-scoped CSS custom properties become relevant in general CSS approaches — BEM, CSS Modules, or any architecture where components have dedicated CSS files separate from their markup. The guidance about component-level variables in this article applies specifically to those contexts.

Naming Convention for Component-Scoped Variables

When defining component-scoped CSS custom properties in general CSS, use an underscore prefix to signal local scope:

.accordion {
  --_accordion-max-height: 200px;
  --_accordion-speed: 300ms;
  max-height: var(--_accordion-max-height);
  transition: max-height var(--_accordion-speed);
}

.dialog {
  --_dialog-side-spacing: 24px;
  padding-inline: var(--_dialog-side-spacing);
}

The leading underscore (--_) tells readers “this variable is locally scoped to this component.” It distinguishes component-level variables from global theme tokens like --color-primary or --spacing-sm.

Both single underscore (--_) and double underscore (--__) conventions exist. Choose one and apply it consistently across the project. The single underscore (--_) is more common.

/* Single underscore — more common */
.menu { --_menu-gap: 8px; }

/* Double underscore — also valid */
.menu { --__menu-gap: 8px; }

Demos

System Tokens Mixed with Arbitrary Values

This card component uses system tokens for its standard spacing and colors, but arbitrary values for its component-specific grid layout and decorative icon sizing. Comments show which values come from the token system and which are arbitrary.

System Tokens + Arbitrary Values in a Component

In the code, system tokens appear where the value follows the project’s spacing vocabulary — hsp-sm (20px) for horizontal padding, vsp-xs (8px) for vertical padding, hsp-xs (12px) for gaps. Arbitrary values appear for component-specific details: the icon is 18px for optical balance, the grid uses 120px for its sidebar width, and the stat number uses 22px for visual impact. None of these arbitrary values belong in the system token set because they’re meaningful only inside this component.

Token Promotion: Before and After

When the same arbitrary value keeps appearing across components, it’s a signal to promote it to a system token. This demo shows a pricing layout where a frequently-used card width has been promoted from an arbitrary value to a named token.

Before and After Token Promotion

In the “before” version, three developers each picked slightly different padding and font sizes for the same pricing card component. The cards look subtly uneven — 18px vs 14px vs 16px vertical padding, 28px vs 32px vs 26px price font size. Once the team noticed this pattern recurring across pricing, feature cards, and testimonial cards, they promoted the values to system tokens: vsp-sm / hsp-sm for padding and heading for the price font size. Now every card automatically stays consistent.

Mixing System Tokens and Arbitrary Values in a Real Layout

This demo simulates a realistic component from a production project. System tokens handle all the standard spacing, colors, and typography. Arbitrary values handle the component-specific layout grid and decorative details.

Production Component: Tokens + Arbitrary Values

In a real Tailwind project, this component’s classes would look like:

<!-- System tokens for standard spacing and colors -->
<section class="px-hsp-sm py-vsp-sm">
  <!-- ARBITRARY for component-specific grid layout -->
  <div class="grid grid-cols-[80px_1fr] gap-x-hsp-sm">
    <!-- ARBITRARY for avatar dimensions -->
    <div class="w-[64px] h-[64px] rounded-full" />
    <div class="flex flex-col gap-y-vsp-2xs">
      <!-- System tokens for tag spacing -->
      <span class="px-hsp-xs py-vsp-2xs bg-success/10 text-success">Active</span>
    </div>
  </div>
</section>
<!-- ARBITRARY for icon button, system tokens for primary button -->
<button class="w-[32px] h-[32px] p-[6px]">Edit</button>
<button class="px-hsp-sm py-vsp-xs bg-primary text-text-inverse">View Profile</button>

Common AI Mistakes

Mistake 1: Creating Tokens for Every Value

<!-- BAD: Polluting the token set with one-off values -->
<!-- Adding --spacing-avatar: 64px to @theme is wrong -->
<div class="w-avatar h-avatar" />

<!-- GOOD: Use arbitrary for component-specific sizes -->
<div class="w-[64px] h-[64px]" />

One-off values clutter the token set. A 64px avatar size is meaningful only within the profile component. If it were promoted to a token, other developers might use it for unrelated purposes, diluting its intent.

Mistake 2: Using Arbitrary Values for Everything

<!-- BAD: Ignoring system tokens entirely -->
<div class="p-[20px] gap-[12px] bg-[hsl(221_83%_53%)]">

<!-- GOOD: Use system tokens for shared design values -->
<div class="px-hsp-sm gap-x-hsp-xs bg-primary">

If a value exists in the token set, always use the token. Arbitrary values should only appear when the token set genuinely doesn’t cover the need.

Mistake 3: Adding Tokens Preemptively

<!-- Structural detail: stays arbitrary -->
<!-- Design decision (e.g., "our icons are 18px"): becomes a token -->

The distinction is not about usage count — it’s about whether the value represents a design decision or a structural detail. If the design says “icons are 18px,” that’s a token from day one, even if only one component uses it. If 18px is just the padding that makes one specific button look balanced, it stays arbitrary forever.

This is the same judgment as “should we extract this function to a utility?” in application architecture. The answer depends on whether the concept deserves a name in the system, not on how many call sites exist.

When to Use

This component-centric approach applies whenever you work with the tight token strategy:

  • Building new components — Default to system tokens for spacing and colors, use arbitrary for layout-specific details like grid columns and decorative values
  • Reviewing component code — Check whether arbitrary values represent design decisions that should be tokens, or structural details that should stay local
  • Defining the token set — Tokens come from design decisions (icon sizes, layout widths, avatar dimensions), not from counting how many components share a value
  • Refactoring existing components — Look for hardcoded values that match existing tokens and replace them

The goal is a token set that stays small and meaningful. Every token should earn its place by representing a genuine design decision. Everything else stays at the component level as an arbitrary value.

For a detailed look at how this applies specifically to width/height sizing — where the abstract scale layer is intentionally skipped — see Two-Tier Size Strategy.

Revision History