Lab 12: Component API Design

Time: 60 minutes | Level: Architect | Docker: node:20-alpine

Overview

Component API design principles: CSS custom property API surface with @property, variant systems using data-variant + :is(), compound component patterns, CSS-only state machines via :has(), and slot-based composition strategies.


Step 1: CSS Custom Property API — @property

/* Document the component's CSS API surface via @property */
/* This makes the API explicit, type-checked, and animatable */

@property --ds-btn-bg {
  syntax: '<color>';
  initial-value: #3b82f6;
  inherits: false;  /* Component-scoped, not inherited */
}

@property --ds-btn-color {
  syntax: '<color>';
  initial-value: #ffffff;
  inherits: false;
}

@property --ds-btn-radius {
  syntax: '<length>';
  initial-value: 0.375rem;
  inherits: false;
}

@property --ds-btn-padding {
  syntax: '<length>{1,4}';
  initial-value: 0.5rem 1rem;
  inherits: false;
}

@property --ds-btn-font-size {
  syntax: '<length>';
  initial-value: 1rem;
  inherits: false;
}

@property --ds-btn-border {
  syntax: '<length> || <line-style> || <color>';
  initial-value: none;
  inherits: false;
}

/* Component uses its own API */
.btn {
  background: var(--ds-btn-bg);
  color: var(--ds-btn-color);
  border-radius: var(--ds-btn-radius);
  padding: var(--ds-btn-padding);
  font-size: var(--ds-btn-font-size);
  border: var(--ds-btn-border);

  /* Internal use only (--_*) — NOT in public API */
  --_focus-ring: var(--ds-btn-bg);
}

/* Consumers set the API */
.hero .btn {
  --ds-btn-radius: 9999px;    /* Pill button in hero */
  --ds-btn-bg: white;
  --ds-btn-color: #1e293b;
}

💡 Prefix public API vars with --ds-component- and internal-only vars with --_. The leading underscore signals "don't override this externally."


Step 2: Variant System — data-variant + :is()


Step 3: Compound Components


Step 4: CSS-Only State Machines with :has()

💡 :has() is a parent selector in disguise — it reads child state and applies styles to any ancestor. CSS state machines without JavaScript are now production-ready.


Step 5: Slot-Based Composition Strategies


Step 6: Component Contract Documentation


Step 7: Variant Resolution Algorithm


Step 8: Capstone — API Documentation Generator

📸 Verified Output:


Summary

Pattern
Implementation
Benefit

API surface

@property declarations

Type-safe, animatable

Variant system

data-variant + :is()

Clean HTML API

Compound components

BEM + slot names

Composable structure

CSS state machines

:has() selectors

Zero JS needed

Slot composition

Web Component slots

Flexible content

Private vars

--_ prefix convention

Clear API boundary

Contract docs

TypeScript interface

Self-documenting

Last updated