Design System · 2026

Verdant
Design System

A production-ready, accessible design system built on organic green foundations — scalable from startup to enterprise.

200+ Tokens
40+ Components
AA+ WCAG 2.2
2 Themes

What's included

01
Color System

Complete semantic scales with dark/light mode tokens

02
Typography

Syne display + Instrument Serif + DM Mono

03
Design Tokens

JSON & CSS variable token architecture

04
Components

Fully interactive, accessible UI components

05
Accessibility

WCAG 2.2 AA compliant with contrast analysis

06
Code Arch

React + TypeScript + CSS variables structure


Quick Start

bash
# Install the design system npm install @verdant/design-system # Import tokens in your entry point import '@verdant/design-system/tokens.css' # Use components import { Button, Input, Card } from '@verdant/design-system'
Philosophy

Design
Principles

Four principles guide every decision in Verdant — from token naming to component behavior.

🌱
Organic Clarity

Interfaces breathe. Generous spacing, deliberate hierarchy, and purposeful negative space create focus — not noise.

Accessibility First

WCAG 2.2 AA is the floor, not the ceiling. Every interactive element is keyboard-navigable and screen-reader ready.

Purposeful Motion

Animation communicates — not decorates. Every transition has intent, duration, and respects reduced-motion preferences.

🔧
Scalable by Design

Token-first architecture means one change propagates everywhere. From 5 components to 500 — the system stays coherent.

Foundations

Colors

A semantic color system derived from the brand's forest-green DNA, built for both light and dark environments.

Primary Scale

Derived from brand primary #1AAC1A. Used for interactive elements, accents, and status indicators.

Secondary Scale

Derived from brand secondary #032A03. Deep forest tones for backgrounds and depth layers.

Neutral Scale

Semantic Colors

Success
#1AAC1A
Warning
#D97706
Error
#DC2626
Info
#0EA5E9

Theme Tokens

🌗
Automatic Light & Dark Mode
All semantic tokens automatically swap values between themes. Toggle the ☀ button in the header to preview both modes. Tokens use CSS custom properties that change per [data-theme] attribute.
TokenDark ValuePreview
--bg-primary#0a0d0a
--bg-surface#161d16
--text-primary#e8f0e8
--text-accent#1AAC1A
--border-defaultrgba(26,172,26,.12)
Foundations

Typography

Three typefaces — each with a distinct voice — form the typographic system.

Font Families

Syne
Display / UI
font.family.primary
Instrument
Editorial / Serif
font.family.serif
DM Mono
Code / Labels
font.family.mono

Type Scale

font.size.6xl 4rem · 800 weight · −0.03em tracking
The quick fox
font.size.4xl 2.25rem · 700 weight · −0.02em tracking
Page Heading H1
font.size.2xl 1.5rem · 600 weight · −0.01em tracking
Section Heading H2
font.size.md (body) 1rem · 400 weight · 1.75 line height
The design system uses a semantic type scale with clear hierarchy. Body text is optimized for readability at 16px base size with a comfortable 1.75 line height for long-form content.
font.size.sm (caption) 0.875rem · 400 weight · var(--text-muted)
Caption text, helper text, and secondary labels use this scale.
font.family.mono (label) DM Mono · 0.75rem · uppercase · 0.1em spacing
API KEY · TOKEN NAME · STATUS · VERSION 1.0
Foundations

Spacing
& Layout

An 8-point grid system ensures consistent rhythm across every screen size and component.

Spacing Scale

space.2
0.25rem · 4px
space.4
0.5rem · 8px
space.8
1rem · 16px
space.12
1.5rem · 24px
space.16
2rem · 32px
space.24
3rem · 48px
space.32
4rem · 64px
space.48
6rem · 96px
space.64
8rem · 128px

Border Radius

radius.sm
4px
radius.md
8px
radius.lg
12px
radius.xl
20px
radius.full
9999px

Breakpoints

TokenValueUsage
screen.mobile320pxSmall phones
screen.tablet768pxTablets, large phones
screen.laptop1024pxLaptops, small desktops
screen.desktop1280pxStandard desktops
screen.wide1536pxWide / ultrawide monitors
Foundations

Motion

Motion communicates hierarchy, state changes, and spatial relationships. Every animation in Verdant has a reason to exist.

Respect prefers-reduced-motion
All animations check @media (prefers-reduced-motion: reduce) and fall back to immediate transitions. This is non-negotiable.

Duration Tokens

motion.duration.fast
120ms — hover states, micro-interactions
motion.duration.normal
220ms — component reveals, page elements
motion.duration.slow
400ms — page transitions, theme switches

Easing Curves

motion.easing.standard
cubic-bezier(0.4, 0, 0.2, 1)

General-purpose. Accelerates then decelerates.

motion.easing.decelerate
cubic-bezier(0, 0, 0.2, 1)

Enter animations. Elements arrive and settle.

motion.easing.accelerate
cubic-bezier(0.4, 0, 1, 1)

Exit animations. Elements leave quickly.

Reference

Token
Reference

All design decisions are expressed as named tokens. Change a token, change the whole system.

JSON Tokens (excerpt)

tokens.json
{ "color": { "primary": { "50": "#f0fdf0", "100": "#dcfcdc", "500": "#1AAC1A", "900": "#0f4a0f" }, "background": { "primary": { "dark": "#0a0d0a", "light": "#ffffff" }, "surface": { "dark": "#161d16", "light": "#f0f4f0" } }, "text": { "primary": { "dark": "#e8f0e8", "light": "#0f140f" }, "muted": { "dark": "#5a6e5a", "light": "#6b786b" } } }, "font": { "family": { "primary": "'Syne', sans-serif", "mono": "'DM Mono', monospace" }, "size": { "xs": "0.75rem", "sm": "0.875rem", "md": "1rem", "lg": "1.125rem", "xl": "1.25rem", "2xl": "1.5rem", "3xl": "1.875rem", "4xl": "2.25rem" } }, "space": { "2": "0.25rem", "4": "0.5rem", "8": "1rem", "16": "2rem", "32": "4rem", "64": "8rem" }, "motion": { "duration": { "fast": "120ms", "normal": "220ms", "slow": "400ms" } } }

CSS Variable Definitions

tokens.css
:root { /* Colors */ --color-primary-500: #1AAC1A; --color-secondary-500: #032A03; /* Typography */ --font-primary: 'Syne', sans-serif; --font-mono: 'DM Mono', monospace; --font-size-md: 1rem; /* Spacing */ --space-8: 1rem; --space-16: 2rem; /* Motion */ --motion-fast: 120ms; --motion-normal: 220ms; --motion-ease-standard: cubic-bezier(0.4, 0, 0.2, 1); } [data-theme="dark"] { --bg-primary: #0a0d0a; --text-primary: #e8f0e8; --text-accent: #1AAC1A; --border-default: rgba(26, 172, 26, 0.12); } [data-theme="light"] { --bg-primary: #ffffff; --text-primary: #0f140f; --text-accent: #147314; --border-default: rgba(3, 42, 3, 0.12); } /* Respect reduced motion */ @media (prefers-reduced-motion: reduce) { * { transition-duration: 0.01ms !important; } }
Components

Buttons

Six variants, three sizes, five states. Every button is keyboard-accessible and WCAG compliant.

Variants
Sizes
States

Button.tsx

typescript
import React from 'react' type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'text' | 'destructive' type ButtonSize = 'sm' | 'md' | 'lg' interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { variant?: ButtonVariant size?: ButtonSize loading?: boolean icon?: React.ReactNode } export function Button({ variant = 'primary', size = 'md', loading = false, children, disabled, ...props }: ButtonProps) { return ( <button className={clsx('btn', `btn-${variant}`, `btn-${size}`)} disabled={disabled || loading} aria-busy={loading} {...props} > {loading && <Spinner />} {children} </button> ) }
Components

Form Controls

Every form control supports validation states, helper text, and accessible labeling.

Text Inputs
🔍
Please enter a valid email address
✓ Email verified
Selection Controls
Option A
Option B
Choice 1
Choice 2
Enabled
Disabled
Components

Navigation

Tabs, breadcrumbs, and pagination components help users orient themselves and move through your product.

Tabs

Overview
Components
Settings
Analytics
The Overview tab displays summary information and key metrics at a glance.

Breadcrumbs

Pagination

1–10 of 248 items
Components

Feedback

Alerts, toasts, and status indicators communicate system state to users without interrupting their flow.

Alert Banners

Deployment successful
Your changes have been deployed to production. All 3 regions are healthy.
⚠️
Usage limit approaching
You've used 85% of your monthly API quota. Consider upgrading your plan.
🚨
Build failed
TypeScript compilation error in src/components/Button.tsx at line 42.
ℹ️
Scheduled maintenance
The system will be unavailable March 15, 02:00–04:00 UTC.

Toast Notifications

Changes saved successfully
Undo
Failed to connect to server
Retry
Session expires in 5 minutes
Extend

Badges & Tags

● Live ● Degraded ● Outage ● Beta Archived
React ×
TypeScript ×
Design System ×
WCAG 2.2 ×
Components

Data Display

Cards, stat blocks, avatars, and tables for presenting information with clarity.

Stat Cards

Total Users
48.2k
↑ 12.4% this month
Revenue
$91k
↑ 8.1% this month
Uptime
99.9%
30-day average

Content Cards

Getting Started
Learn the fundamentals of the Verdant design system and how to install it.
Token System
Explore the complete token architecture and how to customize the system.
Accessibility
WCAG compliance guidelines and tools to test your implementations.

Avatars

AJ
KL
MN
OP
A
B
C
+5

Data Table

Component Version Status Coverage
Button 1.4.0 Stable 100%
Input 1.3.2 Stable 98%
Modal 1.2.0 Beta 87%
DataGrid 0.8.1 Alpha 61%
Components

Overlays

Modals, drawers, tooltips, and popovers — each with accessible focus trapping and keyboard dismissal.

Modal

Dialog Preview
typescript · Modal.tsx
import { useEffect, useRef } from 'react' interface ModalProps { open: boolean onClose: () => void title: string children: React.ReactNode footer?: React.ReactNode } export function Modal({ open, onClose, title, children, footer }: ModalProps) { const ref = useRef<HTMLDialogElement>(null) useEffect(() => { if (open) ref.current?.showModal() else ref.current?.close() }, [open]) return ( <dialog ref={ref} onClose={onClose} aria-labelledby="modal-title"> <header> <h2 id="modal-title">{title}</h2> <button onClick={onClose} aria-label="Close">×</button> </header> <div role="document">{children}</div> {footer && <footer>{footer}</footer>} </dialog> ) }
Guidelines

Accessibility

WCAG 2.2 AA compliance is built into every token, component, and interaction pattern in Verdant.

Contrast Analysis

Aa
7.2:1 ✓ AAA
Primary on Secondary
Aa
14.8:1 ✓ AAA
Text on Dark BG
Aa
6.1:1 ✓ AA
Accent on Dark BG
Aa
5.4:1 ✓ AA
Green-700 on White
Aa
4.6:1 ✓ AA
Neutral-500 on White
Aa
2.8:1 ✗ fail
Neutral-400 on White

Compliance Checklist

Color contrast — text
All body text ≥ 4.5:1 · Large text ≥ 3:1
Keyboard navigation
All interactive elements reachable via Tab · Logical focus order
Focus indicators
2px outline with 2px offset on all focusable elements
Touch targets
Minimum 44×44px touch area · WCAG 2.5.5
ARIA roles & labels
Semantic HTML first · ARIA only when needed
Reduced motion
prefers-reduced-motion: reduce supported globally
!
Color alone never conveys information
Status badges use both color + text/icon — review custom implementations
Implementation

Code
Architecture

React + TypeScript + CSS variables. Zero runtime dependencies for styling. Tree-shakeable exports.

Directory Structure

file tree
verdant-design-system/ ├── tokens/ │ ├── tokens.json # Source of truth │ ├── tokens.css # CSS custom properties │ └── tokens.ts # TypeScript exports │ ├── components/ │ ├── Button/ │ │ ├── Button.tsx │ │ ├── Button.test.tsx │ │ └── index.ts │ ├── Input/ │ ├── Modal/ │ ├── Card/ │ └── index.ts # Barrel export │ ├── hooks/ │ ├── useTheme.ts │ ├── useFocusTrap.ts │ └── useReducedMotion.ts │ ├── utils/ │ ├── clsx.ts │ ├── contrast.ts │ └── a11y.ts │ └── docs/ # Next.js MDX docs site ├── pages/ ├── components/ └── content/

Card.tsx Example

typescript · Card.tsx
import React from 'react' import styles from './Card.module.css' import { clsx } from '../utils/clsx' interface CardProps { variant?: 'default' | 'elevated' | 'outlined' padding?: 'sm' | 'md' | 'lg' hoverable?: boolean children: React.ReactNode className?: string } export function Card({ variant = 'default', padding = 'md', hoverable = false, children, className, }: CardProps) { return ( <div className={clsx( styles.card, styles[`variant-${variant}`], styles[`padding-${padding}`], hoverable && styles.hoverable, className, )} > {children} </div> ) } // Subcomponents Card.Header = ({ children }: { children: React.ReactNode }) => <div className={styles.header}>{children}</div> Card.Body = ({ children }: { children: React.ReactNode }) => <div className={styles.body}>{children}</div> Card.Footer = ({ children }: { children: React.ReactNode }) => <div className={styles.footer}>{children}</div>

useTheme Hook

typescript · hooks/useTheme.ts
import { useState, useEffect } from 'react' type Theme = 'light' | 'dark' export function useTheme() { const [theme, setTheme] = useState<Theme>(() => { if (typeof window === 'undefined') return 'dark' return (localStorage.getItem('verdant-theme') as Theme) || (window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark') }) useEffect(() => { document.documentElement.setAttribute('data-theme', theme) localStorage.setItem('verdant-theme', theme) }, [theme]) const toggle = () => setTheme(t => t === 'dark' ? 'light' : 'dark') return { theme, toggle, setTheme } }