-
Notifications
You must be signed in to change notification settings - Fork 3
For Developers
This section is for developers building or extending the theme. While the rest of the wiki documents components for content editors, these pages explain how the design system works under the hood and how to build a new component from scratch so it matches the rest of the system automatically.
If you only configure components in the Layout Builder, you don't need this section. If you write Twig, CSS, or .component.yml files, start here.
Everything in the theme is built on a strict separation of concerns. There are three layers, and styling flows in one direction only:
-
Layer 1 — Primitives. Raw values defined once as CSS custom properties in
css/base.css(:root): the Maryland color palette (--maryland-red, the gray ramp) and the spacing scale (--space-xs…--space-3xl). The.dark-themeclass re-maps these same token names to inverted values. -
Layer 2 — Semantic utility classes. The "design system surface" that you actually write in markup. Four clean namespaces in
base.css:c-*(color roles),t-*(typography ramp),s-*(spacing steps), andani-*/i-*(animation and icons). Each one references a Layer 1 token viavar()— never a hard-coded value. -
Layer 3 — Components (SDC). Drupal Single Directory Components under
components/. Their*.twigfiles apply the Layer 2 utility classes to express design intent, and their*.cssfiles contain only structural layout (flex, grid, positioning, aspect-ratio) — usingvar(--token)primitives on the rare occasion they must set a color or spacing value directly.
:root primitives → c-/t-/s-/ani- utilities → components apply utilities in Twig
(--maryland-red, (the design-system (structural layout only
--space-md, …) surface you write) stays in component CSS)
Express the role, not the raw value.
When you style a component, you never pick a hex color, a pixel measurement, or a font size. You pick a color role (c-content-secondary), a spacing step (s-stack-small), and a type ramp slot (t-body-small). The system decides the actual value — and that is exactly what makes three things work for free:
-
Dark mode — flipping
.dark-themeon an ancestor recolors the whole subtree, because every utility resolves throughvar(--token). -
Brand/theme changes — update a token in
base.cssonce, and every component follows. - Responsiveness — the type ramp and spacing utilities already step up at the breakpoints (mainly 768px), so you don't write media queries for them.
The theme has no build tooling — no Sass, no webpack, no npm scripts. css/base.css is the hand-maintained, precompiled stylesheet, and JavaScript libraries ship pre-minified. Drupal's own library aggregation (umdlib_umdds.libraries.yml) loads everything. You edit CSS and Twig directly and clear the Drupal cache to see changes.
-
Design Tokens and Utility Classes — the full reference for the
c-*,t-*,s-*, andani-*classes you write in markup, plus the ready-made.button.umd-libbase class. - Building a Component — the fast recipe: SDC anatomy, the spacing/color/type rules, the non-negotiable house rules, a worked example, and a 60-second checklist for shipping a component that matches the system.
- Design Tokens, Color, Spacing — the Foundations pages documenting the underlying Layer 1 token values.
The canonical source these pages are derived from is
DESIGN-SYSTEM.mdin the theme repository, generated by readingcss/base.cssend-to-end and auditing every component.