Design Principles

The four non-negotiable rules that govern every Byteion component.

1. Tokens First

Every visual property — color, spacing, radius, shadow — must come from a defined token. Tokens are the single source of truth. They live in two places: JavaScript modules (packages/tokens/) for build-time consumption and CSS variables (packages/core/theme/variables.css) for runtime theming.

When you change --primary in variables.css, every button, link, badge, and focus ring in the system updates simultaneously. This is not possible when colors are hardcoded as raw Tailwind utilities like bg-blue-500.

Correct — uses the primary token, adapts to theme changes

<button class="bg-primary text-primary-foreground">Save</button>

Incorrect — hardcoded color, does not respond to theming

<button class="bg-blue-500 text-white">Save</button>

Why it matters: When every visual comes from a token, rebranding is a CSS variable change, not a search-and-replace across 50+ components. Tokens also enable automated contrast validation — a script can check every theme × surface combination in CI.

2. Semantic Usage

Use semantic tokens (bg-background, text-foreground, border-border) instead of direct color references. Semantic tokens describe purpose, not appearance. A surface token tells you "this is a background" — not "this is white."

This distinction is critical for dark mode. When the theme switches from light to dark, --background changes from a light value to a dark one, but the Tailwind class bg-background stays the same. Every component using semantic tokens adapts automatically. Components using hardcoded bg-white would render as white-on-white in dark mode.

Correct — semantic token works in light and dark mode

<div class="bg-background text-foreground">...</div>

Incorrect — literal color breaks in dark mode

<div class="bg-white text-black">...</div>

Why it matters: Semantic tokens make dark mode automatic. Every component that uses bg-background instead of bg-white works in both themes without modification. This also enables data-theme brand switching — the same classes render in any brand color without markup changes.

3. No Arbitrary Values in Core Components

Avoid arbitrary Tailwind values like w-[200px], p-[13px], or text-[#abc123] in core components. Arbitrary values bypass the token system. They cannot be themed, they cannot be audited by validation scripts, and they create visual inconsistency across components.

If a core component needs a value that does not exist in the token scale, add it to the token system first, then consume it through the Tailwind preset. This keeps the design system governed and the token scale intentional.

The one approved exception is app-level one-off layout. In your application code, a w-[240px] on a sidebar that is never shared is acceptable. In a published component that ships to thousands of projects, the same value would be a maintainability problem.

Correct — uses token values or approved scale

<!-- button/component.config.json — uses tokens -->
<button class="rounded-lg px-4 py-2 text-sm">Save</button>

<!-- app-level one-off layout (approved exception) -->
<aside class="w-[240px]">...</aside>

Incorrect — arbitrary value inside a shared component

<!-- core component — this value cannot be themed or audited -->
<button class="rounded-[11px] px-[13px]">Save</button>

Why it matters: Every arbitrary value in a core component is a theming blind spot. When a client requests a radius change, values like rounded-[11px] are invisible to search and impossible to update systematically. Adding the value to the token system first makes it auditable, themeable, and documented.

4. Composition Over Configuration

Components are composable primitives, not configurable widgets. A Byteion Card does not accept a headerTitle prop or a showFooter boolean. Instead, you compose standard HTML elements inside a card container:

<!-- Composition: you control the structure inside the card -->
<div class="rounded-xl border border-border bg-card shadow-card">
  <div class="border-b border-border p-4 flex items-center justify-between">
    <h3 class="font-semibold">Card title</h3>
    <button class="text-sm text-primary">Edit</button>
  </div>
  <div class="p-4">
    <p class="text-muted-foreground">Card body content here.</p>
  </div>
</div>

In React, this maps naturally to children and className. In Vue, it maps to slots. The framework wrapper does not invent a configuration layer — it passes through HTML structure:

// React — composition via children
<Card className="p-6">
  <CardHeader>
    <h3>Card title</h3>
  </CardHeader>
  <CardBody>
    <p>Card body content here.</p>
  </CardBody>
</Card>
<!-- Vue — composition via slots -->
<Card class="p-6">
  <template #header>
    <h3>Card title</h3>
  </template>
  <template #body>
    <p>Card body content here.</p>
  </template>
</Card>

Because the framework wrappers use the same HTML structure as the core primitives, the React version and the Vue version produce identical markup. The HTML is the API.

Why it matters: Composition means components never need a breaking API change. The HTML contract is always the same — a container with Tailwind classes. What goes inside is your choice. This also makes the system framework-agnostic: the same mental model works for HTML, React, and Vue.

Why these rules matter

These four rules exist because of a single goal: white-labeling must be a token change, not a code refactor. When a client wants their dashboard in their brand colors, you change three CSS variables and every component — buttons, inputs, cards, modals, alerts — updates consistently. Without these rules, you would be hunting for hardcoded bg-blue-500 or rounded-[11px] classes across 50 components, one at a time.

The same discipline that enables white-labeling also enables accessible contrast validation, automated theme generation, and predictable component composition. These four rules are the foundation that makes the rest of the system work.

Do and Don't

Do

  • Use bg-primary, text-foreground, border-border in core components
  • Add new visual values to the token system before using them
  • Compose components with HTML structure — not JSON config
  • Override variables.css for re-theming
  • Use semantic tokens to get dark mode for free
  • Use arbitrary values only for app-specific one-off layouts

Don't

  • Use bg-blue-500, text-gray-900, border-gray-200 in components
  • Use arbitrary values like w-[200px] or rounded-[11px] in core components
  • Build monolithic components with configuration objects
  • Modify component CSS directly — change the token instead
  • Hardcode colors expecting them to work in dark mode
  • Assume a value only used once does not need to be a token

Developer tips

• Audit for hardcoded values. Search for bg-zinc-, text-gray-, and border-gray- in the core components directory — these are token violations. • If it is not a token, it is not themeable. Before adding any color, spacing, radius, or shadow value to a component, check whether it exists in the token system. • Start from the component pages. Each component page shows variants, states, and composition patterns using only token values. • Use npm run validate:packages before committing. The validation scripts catch token violations, missing schemas, and contrast issues across all packages.

Unlock Premium Patterns

Get access to copy-paste ready Pro blocks, SaaS templates, and advanced component patterns.

Explore Pro Components