Skip to main content

Honest Design System

Case StudyDesign SystemsDesign Technologist

Honest Design System

Self-initiated · 2025–2026

Most portfolio sites are built on templates. This one is built on a design system — 39 components, a two-layer token architecture, and a Figma library that matches production code 1:1.

Honest Design System — component library overview showing cards, navigation, and tag components in Figma

39

Components

WCAG 2.1 AA

Accessibility standard

100

Lighthouse score

1:1

Figma-to-code parity

My Role

Designer and engineer

Stack

Next.js, React, TypeScript, CSS custom properties, Storybook

Timeline

2025–2026

Status

Deployed to production

A portfolio that needed to mean something

When I decided to rebuild my portfolio from scratch, the question was never what to show. The question was whether the portfolio itself would hold up as a piece of craft. Most designer portfolios are built on templates — fine for shipping quickly, not so useful when the portfolio is supposed to demonstrate exactly what you can do.

I wanted the site to feel like me: warm but not precious, structured but not rigid, and honest about what it is. A template couldn't get there. A design system built specifically for this context could.

Why build a system instead of a site

Building a design system for a portfolio is, on its face, overkill. But the alternative — designing components ad hoc and hoping they cohere — produces exactly the kind of inconsistency I spend my professional life trying to fix for other teams.

More practically: I wanted the site's code and Figma documentation to match 1:1. That only works if the design decisions are made deliberately, captured as tokens, and implemented consistently. That's a design system, whether you call it one or not.

The name Honest came from my design philosophy: I build trust through evidence, not aesthetics. The system should be exactly what it claims to be. No decorative tokens. No components that exist for appearance only. Everything earns its place.

The constraint that sharpened every decision: if a component doesn't have a live instance on this site, it doesn't exist in the system.

Two layers: primitives and semantics

The token architecture has two layers. Primitive tokens define the raw values: hex colors, rem sizes, numeric weights. Semantic tokens map those primitives to intent: --text-muted is a semantic token that resolves to #6B6560. Components always reference semantic tokens, never raw values.

This separation means that if the palette changes, the swap happens in one place. It also makes Figma documentation straightforward: every token in the Figma library maps directly to a CSS custom property, by name.

/* Primitives */
--red-800: #89181A;
--warm-50: #FAF8F5;

/* Semantics */
--color-accent:  var(--red-800);
--color-bg:      var(--warm-50);

All spacing, typography, color, motion, and radius values are tokenized. There are no magic numbers in component code.

Honest Design System token architecture in Figma — primitive and semantic layers side by side

Primitive tokens (left) and semantic tokens (right) in the Figma library. Every CSS custom property has a matching Figma variable by name.

Rem-based, predictable, and purposeful

The type scale is rem-based with a 16px root. Every size from --text-xs (12px) to --text-5xl (48px) is a named token. This makes the type scale accessible — it inherits user browser preferences rather than overriding them — and consistent across every component.

Two typefaces: DM Serif Display for headings, Inter for UI text. The pairing was chosen for contrast and warmth. Serif headings carry weight without formality. Inter handles small sizes and data cleanly without drawing attention to itself.

Letter spacing is one of the details that most design systems underspecify. Honest has three explicit values: sm (0.02em, nav links), md (0.08em, tags and callout titles), and lg (0.12em, eyebrows and section labels). Each scale value is tied to a specific use case, not used interchangeably.

--letter-spacing-sm

Sample

0.02em · Nav links

--letter-spacing-md

Sample

0.08em · Tags, callout titles

--letter-spacing-lg

Sample

0.12em · Eyebrows, section labels

39 components, each with a reason to exist

The component inventory came from the site itself, not from a wishlist. Every component in the system has a live instance somewhere on the site. If a component was proposed during build and couldn't be placed, it was cut.

The system started with a core set of layout and content components and grew as the site's needs grew. When the AI Interface Pattern Library needed demos, pattern-specific components were added. When the portfolio chatbot was built, Chat UI components followed. Each addition came with a live consumer — the rule held throughout.

Two components are worth calling out because the decisions behind them reflect the system's philosophy:

ContactModal

The contact flow uses a modal with form fields rather than a mailto link. Mailto opens a local email client — a reasonable assumption in 2012, not in 2026, when a growing percentage of people have no default mail client configured. A modal keeps the interaction in-context, works on every device, and gives me control over the experience. The tradeoff is complexity; the reason to accept that tradeoff is user reliability.

ContactModal component in its open state, showing the get in touch form with email copy and social links

ContactModal in its open state. Form fields and direct contact options replace a mailto link so the interaction stays in-context on every device.

PasswordGate

Several case studies contain work done under NDA or for clients whose data is sensitive. Rather than omit this work entirely or publish it without protection, PasswordGate provides controlled access. The pattern is intentionally low-friction for people with the password and appropriately blocked for those without one. It's a designed decision about information architecture, not just a lock on a door.

PasswordGate component in Figma showing the locked state with password input and access request link

PasswordGate in Figma. The component exposes a title, description, bullet list of contents, and password field — all configurable per case study.

WCAG 2.1 AA across every component

Accessibility was a first-class requirement, not a post-build audit. All 35 WCAG 2.1 Level AA criteria pass. Lighthouse scores 100 on both desktop and mobile across all pages. Zero axe-reported errors. A full VoiceOver and keyboard audit was completed and documented.

One known gap: SideNavigation does not currently implement an aria-live region for active section announcements to screen reader users. This is documented, de-prioritized (the component is decorative navigation, not primary wayfinding), and on the backlog.

WCAG 2.1 AA
35/35 criteria pass
100
Lighthouse, desktop and mobile
Zero
axe-reported errors
Complete
VoiceOver + keyboard audit
Lighthouse audit showing 100 scores across Performance, Accessibility, Best Practices, and SEO

Lighthouse 100 across all four categories. Scores are consistent across desktop and mobile on every page.

Documentation as a live artifact

Every component in the system has a corresponding Storybook story. Stories document the component's props, variants, states, and intended use cases. The Storybook instance is deployed publicly at honest-design-system.vercel.app.

The Storybook serves a specific purpose for this project: it lets a hiring manager or collaborator inspect the system in isolation, separate from the portfolio site. You can see how each component behaves across its states without navigating the site to find an instance. That's the difference between documentation and evidence.

Storybook showing a component story with controls panel open — props, variants, and states documented

The Storybook instance at honest-design-system.vercel.app. Every component has a story; every story has documented controls.

Design leads code, not the other way around

The Figma component library matches the production codebase 1:1. Token names, component names, prop names, and variant names are identical across both environments. This isn't just for neatness — it removes ambiguity in handoff and makes the Figma library useful as a reference for development, not just a source of screenshots.

One deliberate constraint: Figma design decisions lead code changes, not the reverse. When design specs change, code is updated to match. This preserves Figma as the source of truth and prevents the library from drifting from what's actually on the screen.

Honest Design System Figma component library showing navigation components with variants and states

The Figma component library. Component names, variant names, and token references match production code exactly.

What a design system built for one teaches you

Building a design system at enterprise scale means negotiating with constraints you didn't set — existing codebases, engineering capacity, legacy decisions, competing roadmap priorities. Building one for a single site means every constraint is your own. That's clarifying.

The decisions I made under pressure in larger systems — skipping token naming conventions, treating accessibility as a phase rather than a property, letting Figma and code drift — I avoided here because there was no one to negotiate with. It's easier to hold the line when you're the only person in the room.

The takeaway I'd bring back to a team: most design system debt isn't from bad decisions. It's from deferred decisions. The token architecture, the accessibility baseline, the Figma-to-code parity — none of it is hard to establish on day one. It's very hard to retrofit on day three hundred.

Interested?

Interested in how this came together?

Next Project

Vivio Clinical App

View project