The starting point
Brand drift everywhere: hardcoded hex values, three versions of the same button, heroes that
behaved differently per section, !important fighting !important.
Every new page made it worse. Fifteen years of "just ship it" had compounded into a design
debt that editors could feel but nobody could name.
Tokens first, then components, then rules
The foundation is a single design-token file — color, spacing, type as CSS custom
properties. The normalization pass that followed is the unglamorous work that makes
everything after it cheap: I removed every hardcoded color and every !important
site-wide, collapsed three button systems into one, and unified the hero and CTA grammar
across all five page types. When the brand shifts now, one file changes.
On top of the tokens sit 30+ Drupal Single Directory Components — markup,
styles, behavior, and a props.json schema in one directory. The schema is the
contract: misuse fails loudly in development instead of quietly in production. And there's a
trap here I'd flag for any Drupal team adopting SDC: the js.* and
sdc.* input source types look interchangeable and are not. Mixing them throws
InvalidComponentInputsPropSourceException at runtime. I found that the hard way
so my team — and you — don't have to.
Performance is a design-system feature
- Per-variant library loading through Drupal's
libraries.yml: each of the five page experiences ships only the CSS and JavaScript it uses. No global bundle bloat. - Edge-cached static assets on Cloudflare with selective bypass for editor-bound paths.
- Every interactive behavior — carousel, FAQ filter, mobile nav, scroll-spy — is vanilla JavaScript with an explicit no-JS fallback, tested with the framework absent. A CDN failure degrades the experience; it never kills it.
Accessibility as a build gate
Retrofitting empathy is more expensive than designing with it.
Semantic structure, keyboard-reachable navigation and accordions, visually-hidden H1s where design wants a logo but screen readers need a heading, ARIA where it earns its place. Then the part most teams skip: an automated audit that sweeps the entire content tree for missing and placeholder alt text, continuously. WCAG 2.1 compliance you sample once is a snapshot; compliance you audit continuously is a property of the system.
I came to this before engineering: I taught special education and implemented assistive technology for students who depended on it. Accessibility is not a checklist item to me. It has names and faces.
AI in the loop, with a gate
New components are often AI-drafted now — that's real velocity. What makes it safe is
governance: my /validate-component command checks every component, human or
AI-authored, against its props schema and the system's conventions before it lands. Editors
also work through CKEditor 5, where there's another production trap worth naming: custom
classes survive the editing round-trip only if the filter format's allowed tags are mirrored
into the sourceEditing plugin config. Toolbar alone isn't enough. Two lines of
config, hours of mystery if you don't know them.
What it adds up to
One design language across five page experiences, brand consistency at a million visits a season, accessibility as a continuous property, and a component system that both people and AI agents can extend without breaking. Design systems earn their keep in year two — this one is built for that.
Stack: Drupal 11 Single Directory Components, CSS design tokens / custom properties, Twig, Bootstrap 5, vanilla JavaScript, libraries.yml, CKEditor 5, WCAG 2.1, Cloudflare edge caching.