The Reva layer

How the design system extends shadcn/ui with structured styling and layout primitives.

What this adds to shadcn

shadcn/ui gives you copy-paste components and Tailwind CSS. You own the code, you customize everything. This is great for speed, but it's intentionally unopinionated — no layout primitives, no structure beyond what you bring yourself.

This design system adds two things on top of shadcn:

  1. Layout & typography primitivesFlex, Stack, Grid, Container, Text, Heading. Typed props instead of raw <div className="flex ...">.
  2. AI agent rules — AGENTS.md and Cursor rules that enforce these patterns when building with AI.

Everything stays in the shadcn ecosystem. The CLI, blocks, registry, and templates all work. These additions are purely additive.


Layout Primitives

Why not just Tailwind classes?

Writing <div className="flex items-center justify-between gap-4"> works, but:

  • It's verbose and error-prone
  • No type safety on values
  • AI agents generate inconsistent patterns
  • Responsive direction changes need manual breakpoint classes

Layout primitives give you typed props that map to Tailwind classes:

{/* Before */}
<div className="flex flex-col gap-4 md:flex-row">...</div>

{/* After */}
<Flex direction={{ default: "column", md: "row" }} gap={4}>...</Flex>

Component overview

ComponentPurposeDefault element
FlexUn-opinionated flex container. No default gap or alignment.<div>
StackOpinionated flex wrapper. Default gap-2, vertical direction, cross-axis defaults.<div>
HStackStack with direction="horizontal"<div>
VStackStack with direction="vertical"<div>
GridCSS Grid with responsive columns/rows<div>
ContainerMax-width wrapper with centering and responsive padding<div>

Stack vs Flex

  • Stack uses friendly direction names: "vertical" / "horizontal". Has default gap (2), default alignment (vertical → stretch, horizontal → start). Use for everyday stacking.
  • Flex uses CSS-native direction names: "row" / "column". No defaults. Use when you need full control, responsive direction, or reverse.

Stack is implemented as a thin wrapper around Flex.

Responsive props

Flex, Stack, and Grid accept responsive objects for direction/columns:

<Grid columns={{ default: 1, md: 2, lg: 3 }} gap={4}>
<Stack direction={{ default: "vertical", md: "horizontal" }} gap={4}>
<Flex direction={{ default: "column", md: "row" }} gap={4}>

Breakpoints: default (base), sm, md, lg, xl, 2xl.


Typography Primitives

ComponentPurposeDefault elementDefault font
TextBody text, labels, captions<p>Inter Variable (font-sans)
HeadingSection headings and display type<h2>Inter Tight (font-heading)

Both are polymorphic via the as prop. Heading accepts h1h6 plus non-heading tags (p, span, div, strong, em, small, mark, label, figcaption, blockquote, legend) — useful when heading typography is wanted without a heading landmark (e.g. display numbers in a card with as="p").

Heading auto-scales its font size from the heading level (h1 → 4xl, h2 → 3xl, etc.); for non-heading as values it falls back to xl. You can override with the size prop. Default weight is semibold, default leading is tight.


Theme & Tokens

The theme system is CSS-native (Tailwind v4 — no tailwind.config.ts). Tokens aren't authored here — they come from @reva/design-tokens, the platform-agnostic source of truth: W3C DTCG JSON compiles through Style Dictionary to web CSS, a flat TypeScript table, and a Figma variables manifest, so web, mobile, and Figma stay in sync.

@reva/ui layers three CSS files over those token outputs:

FilePurpose
color-palettes.cssImports the package foundation (OKLCH ramps + scales), pins the web breakpoint / radius / font-stack scale, and carries the Tailwind-palette overrides/disables plus brand-1brand-5
tokens.cssImports color-palettes.css plus the package semantic layer (intent families, light/dark modes)
theme.cssConsumer entry point — imports tokens.css, adds animations, custom variants, squircle corners, and base styles

Consumer apps import @reva/ui/theme.css and get everything. See the Design tokens section for the full token reference.

Font system

TokenFontUsage
--font-sansInter VariableBody text, UI labels
--font-headingInter Tight VariableHeadings
--font-monoGeist Mono VariableCode
--font-brandPlayfair Display VariableBrand/marketing

Where this deviates from shadcn

Areashadcn defaultThis systemWhy
Button sizessm, default, lg, iconxs, sm, default, lg (no icon — use IconButton)Cleaner separation of text vs icon buttons
Semantic intentsdestructive onlydestructive + constructive on Button; destructive / constructive / warning / caution / info on BadgeNamed intents over arbitrary colour utilities
LayoutRaw div + TailwindFlex, Stack, Grid, Container primitivesType safety, consistency, AI guidance
TypographyRaw p/h* + TailwindText, Heading primitivesConsistent sizing, font, color
Red color scaleTailwind defaultMulberry (custom OKLCH)Brand-aligned warm red
Green color scaleTailwind defaultFern (custom OKLCH)Brand-aligned green
Yellow color scaleTailwind defaultGold (custom OKLCH)Brand-aligned warm yellow
Disabled palettesAll available11 palettes disabled (lime, fuchsia, etc.)Reduce noise, enforce brand palette
Brand colorsNonebrand-1 through brand-5White-label ready
Disabled cursorpointer-events-none (no visible affordance)pointer-events-none + cursor-not-allowed on form controls (Input, Select, etc.)Visible disabled state on inputs; buttons follow shadcn
Corner shapePlain border-radiusProgressive squircle (superellipse) corners via CSS corner-shape where supportedSofter corners on modern browsers; pixel-identical fallback elsewhere

Working with AI agents

AGENTS.md and Cursor rules enforce these conventions:

  • Use Text / Heading instead of raw <p> / <h*> with className
  • Use Stack / Flex / Grid / Container instead of <div className="flex ...">
  • Use a semantic intent variant (destructive, constructive, warning, caution, info) instead of ad-hoc color classes on Badge or Button
  • After installing a shadcn component, refactor its internals to use layout primitives

AI agents following these rules will produce consistent, structured output that aligns with the system's conventions.

On this page