An image of a jellyfish in the dark

Photo by @and_machines,on Unsplash

Building a Design System: UI Components for danieljoffe.com

When building this portfolio, I wanted more than hastily assembled components—I wanted a design system that would scale. Here's what I built and why it matters.

The Component Library

I created 6 foundational components that form the backbone of this application:

First: Button

A flexible button with three variants (primary, secondary, icon) and three sizes. Uses React.forwardRef for proper ref forwarding and includes built-in accessibility with ARIA attributes and keyboard navigation.

Second: Container

A simple but essential wrapper that centers content and provides consistent spacing. Used on almost every page.

Third: TextInput

A polymorphic form component that renders as either <input> or <textarea>. Handles validation states, error messages, and success feedback with proper ARIA relationships using React.useId().

Fourth: InputLabel

Handles proper HTML label association, required field indicators (red asterisk), and consistent typography.

Fifth: InputFeedback

Validation messages with proper ARIA roles and live regions for screen readers.

Sixth: LinkHint

A small arrow icon indicating external links, using Lucide React for consistency.

Design Principles

Accessibility First
Every component starts with accessibility: ARIA attributes, keyboard navigation, screen reader compatibility. These aren't afterthoughts—they're the foundation.

Type Safety
Full TypeScript support catches errors at compile time. Proper prop interfaces and strict type checking have saved countless debugging hours.

Consistency via Tailwind
Tailwind CSS provides a consistent design language—neutral palette with blue accents—so I don't have to think about spacing or typography choices.

Key Takeaways

  • Always use labels—it's essential for accessibility
  • Meaningful error messages help users understand what went wrong
  • Test keyboard navigation—if you can't use it with a keyboard, it's broken
  • Semantic HTML matters—use the right elements for the right purposes

What's Next

  • Dark mode support
  • Animation integration
  • More input types (select, checkbox, radio)
  • Storybook documentation
  • Expanded test coverage

These 6 components taught me that the best design systems get out of your way and let you focus on creating great user experiences.