Skip to main content
An image of a jellyfish in the dark

@and_machines,

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. This is the first installment documenting the foundational components.

Form Components

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.

Input

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().

Layout Components

Container

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

Grid

A responsive grid layout for displaying content cards. Automatically adjusts columns based on viewport size.

Utility Components

Loading

A loading spinner component for async states. Provides visual feedback during data fetching or processing.

Modal

A portal-based modal component controlled via global state. Renders content above the main application with proper focus management.

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

  • ~~More input types (select, checkbox, switch)~~ Done! See Part 2
  • ~~Feedback components (alerts, tooltips, badges)~~ Done! See Part 2
  • ~~Layout primitives (cards, tabs, stacks)~~ Done! See Part 2
  • ~~Dark mode support~~ Done!
  • Animation integration
  • Expanded test coverage

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