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
# 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
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.
Token Dark Value Preview
--border-default rgba(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
Border Radius
Breakpoints
Token Value Usage
screen.mobile 320px Small phones
screen.tablet 768px Tablets, large phones
screen.laptop 1024px Laptops, small desktops
screen.desktop 1280px Standard desktops
screen.wide 1536px Wide / 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)
{
"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
: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
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
Home
›
Components
›
Navigation
›
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
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
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
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
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
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
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 }
}