Skip to main content
Sriram RavipatiSenior UX Engineer

Design system

system.

This portfolio is its own design system — the same token architecture, accessibility standards, and component governance applied at enterprise scale across 200+ AEM templates. This page shows the system working.

2-layer

Token architecture

WCAG AA

All components

0

Axe violations

100%

:focus-visible coverage

The problem

Without a shared language, every team solves the same problems differently. Inconsistency compounds. Accessibility drifts. The codebase becomes a record of individual decisions rather than a system.

The approach

A two-layer token system: raw palette values in one layer, semantic purpose in another. Components reference only the semantic layer — the theme swap happens in the token definitions, nowhere else.

The outcome

Zero axe-core violations. WCAG 2.1 AA on every component. Light and dark mode via a single token layer — no per-component dark: overrides needed.

Architectural decisions

Three decisions that shaped the system.

01

Semantic tokens over direct palette references

Token architecture

Components reference purpose, not value. --color-accent maps to --brand-500 in light mode and a softer value in dark mode. The dark mode swap happens in one definition — nothing else changes.

02

Native HTML semantics before ARIA attributes

Accessibility

The first rule of ARIA is don't use ARIA if a native element provides the semantic. Every component in this system starts from the correct element — button, a, input. ARIA is used for gaps, not to compensate for wrong elements.

03

Bounded variation — fewer options, stronger consistency

Governance

Five spacing sizes, four button variants, three surface levels. The constraint isn't a limitation — it's what makes the system feel like a system and not a collection of components.

"A design system is not a component library. It is a set of decisions that compounds — every team that adopts it, every product that uses it, every engineer who follows its patterns instead of inventing their own."

Foundation

Design system philosophy.

A design system is not a component library. It is a shared language — a set of decisions that compounds across every team, every product, and every engineer who touches the codebase.

Composition over configuration

A Button with an asChild prop is more useful than a Button with twenty variant props. Fewer, more composable primitives produce better outcomes than comprehensive single-component APIs.

Semantic HTML first, ARIA second

The first rule of ARIA: don't use it if a native element provides the semantic. Getting to a correct baseline means starting with the right element, not adding attributes to compensate for using the wrong one.

Constraints are features

Unlimited flexibility produces inconsistency at scale. Five named sizes and four button variants aren't limitations — they're the mechanism that makes a system legible to the next engineer who uses it.

Tokens everywhere, magic numbers nowhere

Every hardcoded value is a future inconsistency. Every token reference is a future-proofed decision. The discipline of never using arbitrary values is what makes a design system maintainable across years and teams.

Token architecture — two-layer semantic system

Brand values
Raw token
Raw token
Semantic alias
Semantic alias
Tailwind utility
Tailwind utility
CSS output
Two-layer token architecture — semantic aliases decouple purpose from value

Token architecture — two-layer system

Layer 1

Raw values

Immutable palette. Never referenced directly in components.

--brand-500: #8C82FF

Layer 2

Semantic aliases

Named by purpose, not value. Dark mode swaps these — not the raw palette.

--color-accent: var(--brand-500)

Layer 3

Component tokens

Components reference semantic tokens. Tailwind @theme maps them to utilities.

bg-accent

Color system

Single-accent, warm-tinted palette.

One accent prevents competition. Warm-tinted neutrals feel more human than cool grays. Every pairing meets WCAG 2.1 AA contrast requirements.

Brand palette

Brand 50

#EEEEF8

background only

Brand 100

#CECBF6

tint/muted

Brand 200

#AFA9EC

decorative

Brand 300

#9490E0

large text on white

Brand 400

#7B7BC8

3.7:1 on white

Brand 500

#4B4B8F

AA on white ✓

Brand 600

#3A3A72

AA on white ✓

Brand 700

#2D2D52

AAA on white ✓

Brand 800

#1E1E38

AAA on white ✓

Brand 900

#0B0B1A

AAA on white ✓

Neutral palette — warm-tinted

Neutral 50

#FAFAF8

page background

Neutral 100

#F5F4F0

surface

Neutral 150

#ECEAE4

border subtle

Neutral 200

#E2E0D9

border default

Neutral 300

#C8C5BC

border strong

Neutral 500

#888480

muted text

Neutral 700

#3D3A36

AA body text ✓

Neutral 900

#0F0E0D

AAA heading text ✓

Theme-aware semantic tokens

--color-bg
--color-surface
--color-surface-raised

Toggle light/dark to see theme adaptation

Semantic color tokens — components reference only these, never raw values

TokenValueUsage
--color-bg
var(--neutral-50)
--color-surface
var(--neutral-100)
--color-border
var(--neutral-200)
--color-border-strong
var(--neutral-300)
--color-text-primary
var(--neutral-900)
--color-text-secondary
var(--neutral-700)
--color-text-tertiary
var(--neutral-500)
--color-accent
var(--brand-500)
--color-accent-hover
var(--brand-600)
--color-accent-subtle
var(--brand-50)

Typography system

Editorial serif meets engineering sans.

Fraunces (display) for headlines — craft and editorial weight. Outfit (sans) for UI and body — legibility and precision. Geist Mono for code and annotations.

Display / Fraunces / 72px

Aa

Heading / Outfit / 30px / medium

Senior UX Engineer

Body / Outfit / 17px / regular

Specializing in design systems, accessible interfaces, and frontend architecture at enterprise scale.

Mono / Geist Mono / 11px

Design Systems · AEM · WCAG 2.1 · TypeScript

Live type specimen — no screenshots

Type scale — 1.25× modular ratio (Major Third)

text-display
72px
text-hero
60px
text-4xl
48px
text-3xl
36px
text-2xl
30px
text-xl
24px
text-lg
20px
text-base
16px
text-sm
14px
text-xs
12px
text-2xs
10px

Spacing + shape

4px base grid. Named radius scale.

All spacing is a multiple of 4px. No magic numbers. The radius scale maps to semantic use cases — chips, buttons, cards, containers — so the right radius is always obvious.

Spacing scale

--space-14px
--space-28px
--space-312px
--space-416px
--space-624px
--space-832px
--space-1248px
--space-1664px
--space-2496px
--space-32128px

Radius scale

--radius-xs2px
--radius-sm4px
--radius-md8px
--radius-lg12px
--radius-xl16px
--radius-2xl20px
--radius-full9999px

Component ecosystem

Live interactive primitives.

Correct semantics, keyboard navigation, focus management, and ARIA only where native HTML falls short. These run in the browser — not screenshots.

Buttons — 4 variants

Keyboard accessible · :focus-visible · active:scale(0.97)

Badges — status variants

AvailableIn progressReviewWCAG AADraft

Semantic color — status only, never decorative

Form inputs — all states

Enter a valid email address

Label association · :focus-visible · aria-invalid

Tabs — keyboard navigable

Overview panel — accessible, keyboard navigable, ARIA correct.

role=tablist · aria-selected · ← → keyboard

Card — hover elevation

Design system

Token-driven, theme-aware, accessible by construction.

shadow-xs → shadow-lg · border transition · -translate-y-0.5

Focus states — :focus-visible only

Tab to see focus rings · Mouse clicks never show ring

Accessibility standards

WCAG 2.1 AA — every component, by construction.

Accessibility is an engineering responsibility, not a design review checklist. Every component is built accessible — not retrofitted.

Accessibility validation pipeline — per-component protocol

Build
axe-core CI
~35%
Build
TypeScript types
Structural
QA
Keyboard traversal
All states
QA
NVDA / Chrome
All components
QA
VoiceOver / Safari
All components
Release
Regression gate
Full suite
Accessibility validation pipeline — per-component testing protocol
WCAG 1.4.3Contrast (Minimum)
Level AA

All text meets 4.5:1 ratio. Headings meet 3:1. Verified with brand-500 (#4B4B8F) at 5.2:1 on white.

WCAG 1.4.11Non-text Contrast
Level AA

Focus indicators and interactive UI components meet 3:1 against adjacent colors.

WCAG 2.1.1Keyboard
Level A

All interactive components reachable and operable via keyboard without mouse dependency.

WCAG 2.4.7Focus Visible
Level AA

2px outline with 3px offset applied globally via :focus-visible. Never outline: none without replacement.

WCAG 2.3.3Animation from Interactions
Level AAA

prefers-reduced-motion respected globally in CSS and in Framer Motion via useReducedMotion().

WCAG 4.1.2Name, Role, Value
Level A

All interactive components have accessible names. ARIA used only where native HTML semantics are insufficient.

WCAG 1.3.1Info and Relationships
Level A

Semantic HTML throughout. <nav>, <main>, <article>, <section> landmarks. <dl> for key-value content.

WCAG 2.4.1Bypass Blocks
Level A

Skip navigation link as first focusable element on every page. Targets #main-content with tabIndex={-1}.

Motion system

Purpose-driven motion. Reduced-motion first.

Every animation answers 'what changed?' not 'isn't this cool?' Duration tokens prevent arbitrary timing. The toggle simulates prefers-reduced-motion: reduce.

prefers-reduced-motion: no-preference
Hover lift

Card elevation on hover · var(--duration-normal)

Entrance

Section scroll reveal · var(--duration-slow)

Press

Button press feedback · var(--duration-instant)

Motion tokens — duration and easing

TokenValueUsage
--duration-instant
80ms
--duration-fast
150ms
--duration-normal
250ms
--duration-slow
400ms
--duration-crawl
600ms
--ease-out
cubic-bezier(0,0,0.2,1)
--ease-in
cubic-bezier(0.4,0,1,1)
--ease-inout
cubic-bezier(0.4,0,0.2,1)

The system doesn't just look consistent. It behaves consistently — accessible by construction, responsive by default, themeable with a single token swap.

WCAG AA

Every component

0

Axe violations

100%

:focus-visible coverage

2-layer

Token architecture