Developer Journal

Intermediate 3 min read

Creating a Custom Drupal Theme From Scratch

How this portfolio’s theme organizes libraries, Twig, responsive behavior, accessibility, and performance.

Last updated August 8, 2026

A maintainable Drupal theme is a translation layer between render arrays and a coherent design system. This portfolio began with semantic landmarks and content regions, then added tokens, components, and progressive JavaScript.

Define the theme contract

The info file declares regions and global libraries. Libraries keep CSS and JavaScript dependencies explicit, cacheable, and attachable only where needed. Twig templates should shape markup without querying storage or implementing business rules.

Build from tokens outward

Colors, spacing, typography, surfaces, and focus treatment belong in shared custom properties. Components consume those tokens, which is why the accent picker can change the whole visual system without duplicating selectors.

Responsive design starts with flexible grids and readable measures. Breakpoints should respond to layout pressure rather than a list of devices.

Performance and accessibility are features

Avoid shipping JavaScript for behavior CSS already handles. Preserve visible focus, reduced-motion preferences, semantic headings, and sufficient contrast in every color mode. Version libraries when assets change so Drupal and downstream caches agree.

Working example

global:
  version: 1.0.0
  css:
    theme:
      css/style.css: {}
  js:
    js/site.js: {}
  dependencies:
    - core/drupal
    - core/once

Attach assets where they are used

A global library is convenient for typography, layout primitives, navigation, and other behavior every page needs. Page-specific CSS and JavaScript should usually live in smaller libraries that are attached by the component, template, preprocess layer, or render array that actually requires them. That reduces payload and makes dependencies easier to understand.

Drupal's library system also gives those assets cacheable identities. When a library version changes, browsers and downstream caches can distinguish the new asset from the old one. That is much safer than scattering script or stylesheet tags directly through Twig templates.

Keep application logic out of Twig

Templates should receive variables that already represent the presentation decision. If a template is loading entities, calculating access rules, performing storage queries, or deciding business policy, the theme layer has taken ownership of work that belongs somewhere else.

Preprocess functions are useful for presentation-specific transformations, while controllers, plugins, and services should supply the underlying data. Keeping that boundary clear makes redesigns much less likely to alter application behavior.

Design for editorial change

A custom theme should not require a developer every time normal content changes. Repeated content belongs in entities or Paragraph components, headings and copy belong in fields, and Twig should define how those values are arranged. The result is still a purpose-built frontend, but editors can manage the material without editing templates.

Key Takeaways

  • Treat regions and libraries as the public contract of the theme.
  • Use design tokens to keep variants consistent.
  • Design responsive and accessible behavior before decoration.

Further Reading