Component Reusability & Design Systems

Build every visual element once, use it across every page. This isn't just clean code — it's the foundation of design consistency, faster delivery, and lower maintenance costs.

See the component library
Mpheroane Harrison
· 9 min read · About Harrison

If you've ever updated a button style on one page and then spent an hour hunting down every other page where that button appears, you already understand why component reusability matters. The pain you felt is the pain of a page-based approach meeting reality.

System intelligence demands that every repeated visual pattern be extracted into a reusable component — a single source of truth that renders consistently everywhere it's used.

What components actually are

A component is a self-contained piece of UI with defined inputs (props), consistent styling, and predictable behaviour. It's not a template — it's more like a LEGO brick. You don't rebuild the brick each time you use it; you connect it to other bricks in different configurations.

In practice, for a static or light-dynamic site, components are typically:

You don't need React, Vue, or a component library framework to have components. You need discipline.

The component audit

Before building anything, audit every planned page and catalogue every repeated visual pattern. For a typical South African business site, here's what you'll find:

Section Headers
Used 12–18× across site
Service Cards
Used 4–8× across site
Testimonial Blocks
Used 3–6× across site
CTA Sections
Used 4–7× across site
Image + Text Rows
Used 6–10× across site
Team Member Cards
Used 3–5× across site
FAQ Accordions
Used 2–4× across site
Contact Form
Used 1–2× across site

That's 8 components handling 35–60+ instances across a 10–15 page site. Without components, that's 35–60 separate HTML blocks to build and maintain. With components, it's 8 templates you build once.

Core component library

Here's the minimal component library I use for every project, with the key design decisions for each:

Section Header

Accepts: label (mono uppercase), heading (H2), description (paragraph), optional alignment prop (left/center). Every section on every page uses this instead of ad-hoc heading markup. This alone enforces visual consistency.

Service Card

Accepts: icon, title, description, link URL, link text. Used on the services hub page, in homepage service previews, and in sidebar "related services" blocks. One component, three contexts.

Testimonial Block

Accepts: quote text, author name, author title, company, optional photo URL. Same component renders identically whether it's in a testimonials page grid, a sidebar, or a homepage highlight section.

CTA Section

Accepts: headline, description, button text, button URL, variant (primary/secondary). The "primary" variant uses the gradient background. The "secondary" variant uses a bordered style. Same logic, different visual weight.

Image + Text Row

Accepts: image URL, image alt, heading, body text, optional bullet list, image position (left/right), optional link. This is the most-used component on most sites — the classic two-column layout that appears on service pages, about sections, and blog posts.

Before vs. after

Without components

  • Service card HTML copy-pasted 6 times
  • Each copy has slightly different padding/margin
  • Changing the card style means editing 6 files
  • Blog has a completely different card style
  • New service page takes 4 hours to build
  • Design drift accumulates over months

With components

  • Service card defined once as a partial
  • All instances render identically
  • Changing the card style means editing 1 file
  • Blog uses the same card with different props
  • New service page takes 45 minutes to build
  • Design consistency is automatic

Props, not copies

The key distinction: a component is not a copy-paste template. It accepts props — data that customises its output without changing its structure.

In a static site generator like Astro, this looks like:

<!-- Component definition: ServiceCard.astro -->
<div class="service-card">
  <i class="fas fa-{icon}" aria-hidden="true"></i>
  <h3>{title}</h3>
  <p>{description}</p>
  <a href="{link}">{linkText}</a>
</div>

<!-- Usage on services page -->
<ServiceCard
  icon="laptop-code"
  title="Web Design"
  description="Custom websites built as systems, not pages."
  link="/services/web-design"
  linkText="Learn more"
/>

<!-- Usage on homepage with different data -->
<ServiceCard
  icon="search"
  title="SEO"
  description="Rank on Google without paying for ads forever."
  link="/services/seo"
  linkText="See our SEO approach"
/>

Same component. Different props. Identical visual output. Zero duplication.

Design tokens, not magic numbers

Components are only as consistent as the design values they reference. If one component uses padding: 1.5rem and another uses padding: 24px, they're technically the same but practically fragile.

Design tokens solve this by defining every visual value once:

:root {
  /* Spacing scale */
  --space-xs: 0.25rem;
  --space-sm: 0.5rem;
  --space-md: 1rem;
  --space-lg: 1.5rem;
  --space-xl: 2rem;
  --space-2xl: 3rem;
  --space-3xl: 4rem;

  /* Typography scale */
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-xl: 1.25rem;
  --text-2xl: 1.5rem;
  --text-3xl: 1.875rem;
  --text-4xl: 2.25rem;

  /* Border radius */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;
  --radius-full: 9999px;

  /* Shadows */
  --shadow-sm: 0 2px 8px rgba(0,0,0,.15);
  --shadow-md: 0 8px 24px rgba(0,0,0,.2);
  --shadow-lg: 0 16px 48px rgba(0,0,0,.3);
}

Every component references tokens, never raw values. If you decide all cards should have slightly more rounded corners, you change --radius-md in one place and every card on the site updates.

When component thinking fails

Component reusability isn't always the answer. There are three failure modes:

The rule: extract a component when a pattern appears three or more times, and design its props to cover the actual variations you need — not hypothetical future variations.

Scaling without breaking

Here's where component thinking pays dividends: when the client comes back in 6 months wanting to add a new service, a blog category, or a landing page.

Without components, that new page requires designing from scratch, writing new HTML, creating new CSS, and hoping it's consistent with the rest of the site. Estimated time: 4–8 hours.

With components, you compose existing pieces: section header + image-text row + CTA section + testimonial block. The only new work is the content. Estimated time: 45–90 minutes.

That's not just faster — it's guaranteed consistent. The new page can't look different from existing pages because it uses the same building blocks.

Next: Data Flow Integrity and CMS Architecture — how the content behind your components should be structured for resilience and scalability.