Drupalwoo ☉

Building a Drupal 10 Theme Using Component-Based Architecture

Drupal 10 introduced Single Directory Components, a feature that quietly transformed how front-end teams structure themes. Rather than scattering templates across dozens of files, developers can now group markup, styles, JavaScript, and configuration into self-contained units that mirror the components a designer hands over from Figma or Sketch.

For Australian digital agencies juggling government tenders, university projects, and small business clients, this shift delivers practical value. The same card, form field, or navigation block used on a Services Australia-style portal can be dropped into a Melbourne brewery site or a Brisbane council page without rewriting markup. Component-based theming aligns Drupal with the workflow that most Australian front-end studios already follow, while remaining compatible with the strict accessibility and security expectations set by the Digital Service Standard and the Australian Cyber Security Centre.

Why Component Architecture Matters for Drupal 10

Component architecture treats every interface element as a reusable building block. A button is not a template file buried deep in a theme directory; it is a folder containing its Twig markup, scoped CSS, optional JavaScript hook, and metadata describing the slots it accepts. This mental model is borrowed from frameworks like React and Vue, and it lands naturally on Drupal's templating layer.

In a traditional theme, a developer might modify node--article.html.twig, field--node--title.html.twig, and a custom block template to change the appearance of a card. Repeating that pattern across a content type, a view, and a paragraph reference quickly becomes fragile. A component-based approach removes the guesswork: there is exactly one canonical definition of the card, and any consumer instantiates it.

Australian teams that contribute to community platforms, from local Drupal Sydney meetups to open-source university research sites, have started sharing component libraries in GitLab repositories hosted on local infrastructure. The reusable, version-controlled nature of single directory components makes that collaboration safer. When a designer in Perth updates the call-to-action design, the change ripples consistently across every site consuming the library.

Theme Scaffolding and File Layout

Start by creating a custom theme inside themes/custom/. A sensible name such as drupalwoo_components keeps it recognisable in multisite deployments. The minimum required files are drupalwoo_components.info.yml, drupalwoo_components.libraries.yml, and a templates/ directory containing html.html.twig and page.html.twig.

To enable the feature, add allow_single_directory_components: true inside the .info.yml file. Without this flag, Drupal ignores the new structure entirely. Once enabled, you can begin placing components inside a top-level components/ directory, each in its own subfolder matching the component name.

The .component.yml file describes the props the component accepts, the slots available, and whether the component is restricted to certain contexts such as the front-end theme or administrative views. Treating each component as a directory encourages designers and developers to think of UI as discrete, swappable units rather than page-level concerns.

Building Single Directory Components from Scratch

Consider a simple teaser card used across blog listings and editorial landing pages. The Twig template receives a heading, a body, an optional image, and a link. Inside card.twig, the markup is written using semantic HTML that satisfies WCAG 2.2 expectations required by Australian government accessibility audits.

<article class="card" aria-labelledby="card-{{ id }}">
  {% if image %}
    <div class="card__media">{{ image }}</div>
  {% endif %}
  <div class="card__body">
    <h3 id="card-{{ id }}">{{ heading }}</h3>
    <div class="card__text">{{ body }}</div>
    {% if link %}
      <a class="card__cta" href="{{ link['#url'] }}">{{ link['#title'] }}</a>
    {% endif %}
  </div>
  <style>{{ attach_library('drupalwoo_components/card') }}</style>
</article>

The component loads its own library automatically through attach_library, scoping styles to this single template. JavaScript behaviour, when needed, lives inside card.js and follows the same scope. Drupal handles asset aggregation, deduplication, and ordering, so the developer never worries about double-loading jQuery or a CSS reset. The accompanying card.component.yml declares the schema:

name: Card
props:
  type: object
  required: [heading, body]
  properties:
    id:
      type: string
    heading:
      type: string
    body:
      type: string
    image:
      type: string
    link:
      type: object
slots:
  media:
    title: Media
    description: Optional image or icon area.

With this declaration, site editors can drop the component into Layout Builder, place it inside a paragraph type, or invoke it from another Twig template using {% include 'drupalwoo_components:card' with { ... } %}. The structure becomes self-documenting, which is valuable when handing a project to an in-house team in Adelaide or a regional university media department.

Composing Components with Slots and Embeds

Slots are the secret weapon that elevates component-based theming beyond simple includes. Instead of passing every piece of content through a long list of props, you can leave defined regions inside the component and let the consumer fill them. A modal component, for example, exposes a default slot for body content, plus named slots for header, footer, and action buttons.

Embedding one component inside another creates a composition tree. A search results page might compose a filter sidebar from three smaller components, then nest each result inside the card component described earlier. Because each layer is fully documented in its own YAML schema, the editor experience in Layout Builder stays predictable.

Local government websites, such as those built for Brisbane or Hobart councils, frequently need deeply nested structures: a hero block containing a search component, which itself renders a list of cards with optional badges. Slots and embeds handle these scenarios cleanly. They avoid the trap of building monolithic templates that no one wants to modify after the first review cycle.

Design Systems, Caching, and Component Patterns

A component library is only as useful as the design system that surrounds it. Australian studios that already maintain a Figma library for clients in financial services or higher education can map each Figma variant to a Twig component, with shared design tokens flowing through CSS custom properties or SCSS variables.

Storybook integration is straightforward. By pointing Storybook at the components/ directory and registering the Twig renderer, designers in your Sydney or Melbourne office can browse the live library without spinning up a Drupal instance. Changes previewed in Storybook mirror what editors see in the CMS, so the contract between design and code stays intact.

For styles, Tailwind, Bootstrap 5, or a handcrafted SCSS pipeline all work well. The decision often comes down to team familiarity and project constraints. Government tenders sometimes prefer plain CSS to satisfy procurement reviewers; marketing sites often demand Tailwind for its rapid iteration cycle. Choosing the pipeline early keeps token names consistent and prevents the entropy that creeps into large Drupal estates managed across multiple Australian states.

Performance depends on disciplined asset aggregation and cache metadata. Drupal aggregates and caches assets per page request, and components ship with their own CSS and JavaScript through the asset library system. When a component performs logic or fetches data, the YAML configuration must declare appropriate cache contexts, tags, and max-age values. Missing metadata causes stale content during high-traffic events such as a federal election night or a university open day. Different component patterns suit different situations, and choosing between them shapes long-term maintainability.

Pattern Best suited for Skill level required Maintenance burden
Single Directory Components Reusable UI building blocks, design system alignment Intermediate Low once conventions are set
Paragraphs with custom bundles Editor-driven layouts with rich configuration Intermediate to advanced Medium, scales with bundle count
View modes and display suites Content presentation variations per entity Beginner to intermediate Low, mostly administrative
Custom block plugins Highly interactive widgets with PHP logic Advanced Medium to high
Twig includes without SDC Quick templates shared within one site Beginner High when reused widely

For most projects aiming at long-term reuse across multiple Australian properties, Single Directory Components strike the best balance of flexibility, governance, and ease of handover.

Recommendations for a Sustainable Component Library

A few habits tend to separate sustainable component libraries from fragile ones. Treating the following as non-negotiable practices saves hours of remediation later.

A well-built component-based theme ages gracefully. Editors gain autonomy, designers gain consistency, and developers spend less time on repetitive markup. For Australian teams working on everything from small business sites in regional Queensland to federal agency portals, that combination of speed and predictability is hard to beat.