githubEdit

Components

This guide outlines the standard file structure and characteristics for CivicTheme components, based on the established patterns in the codebase.

Overview

Each component follows a consistent file structure with specific purposes for each file type. This ensures maintainability, reusability, and proper integration with the CivicTheme design system.

File Types and Purposes

*.component.yml - Component Metadata and Schema (SDC)

Purpose: Defines the component's properties, validation rules, and documentation as a Drupal Single Directory Component (SDC).

CivicTheme components are SDCs — each component lives in its own directory with all related files (Twig, SCSS, JS, stories, and this metadata file). Drupal's SDC system uses the .component.yml file to register the component and validate the props passed to it at render time.

Characteristics:

  • Uses JSON Schema format with Drupal's metadata schema for prop validation

  • Defines all available props with types, descriptions, and validation rules

  • Includes enums for constrained values (e.g., theme options, size variants)

  • Provides default values where appropriate

  • Serves as the single source of truth for component configuration

  • Enables automatic form generation in Storybook and Drupal

  • Drupal validates incoming props against this schema at render time — missing required props or invalid types will raise errors

Key sections:

  • $schema: References Drupal's metadata schema (https://git.drupalcode.org/...metadata.schema.json)

  • name: Human-readable component name

  • status: Component stability status (e.g., stable, experimental)

  • description: Component purpose and usage

  • props: Detailed property definitions with JSON Schema validation (types, enums, defaults)

  • slots: Named content areas that accept rendered markup (used instead of props for rich content)

To see how CivicTheme structures its components, examine the CivicTheme UI Kit SDC componentsarrow-up-right.

Standard enums: CivicTheme defines standard enum values for commonly used props such as theme (light, dark), spacing (top, bottom, both, none), and other widely shared properties. When creating or overriding components in your sub-theme, use the same enum values to ensure your component schemas remain compatible with CivicTheme's base components. Mismatched enums may cause incompatibilities with CivicTheme and Drupal. Review the base theme's .component.yml files to see which standard values are expected.

SDC component referencing: Components are referenced by their namespace and machine name (e.g., civictheme:button). In sub-themes, use the replaces key to override a base theme component:

*.twig - Template File

Purpose: Defines the HTML structure and logic for rendering the component.

Characteristics:

  • Contains comprehensive documentation in the header comment block

  • Lists all available props with types and descriptions

  • Implements conditional logic for different component states

  • Uses Twig's template inheritance and includes

  • Handles multiple component variants (e.g., different types, sizes, themes)

  • Includes accessibility attributes and ARIA labels

  • Supports both static and dynamic content rendering

Key patterns:

Prop validation — validate props at the top of the template using ternary operators:

Class construction — build modifier classes dynamically:

Nested component includes — use only to limit the scope of variables passed to child components:

Blocks for extensibility — use Twig blocks to allow further overriding by child templates:

*.stories.js - Storybook Configuration

Purpose: Creates interactive documentation and testing environment for the component.

Characteristics:

  • Defines Storybook metadata and component configuration

  • Maps component props to Storybook controls

  • Provides default values for all component variants

  • Enables interactive testing of different prop combinations

  • Imports constants and design tokens for consistent options

  • Supports component categorisation in Storybook navigation

Key features:

  • Control types (radio, text, boolean, select) for different prop types

  • Default story with sensible fallback values

  • Integration with design system constants

  • Component organisation in Storybook hierarchy

*.js - JavaScript Functionality

Purpose: Provides interactive behaviour and event handling for the component.

Characteristics:

  • Implements component-specific functionality and interactions

  • Handles user events (click, focus, keyboard navigation)

  • Manages component state and lifecycle

  • Provides accessibility enhancements

  • Uses vanilla JavaScript for broad compatibility

  • Includes comprehensive event handling and error prevention

  • Uses data- attributes for element selection to ensure HTML changes don't break functionality

  • Avoids dependencies on jQuery, using standard DOM APIs

  • Automatically wrapped with Drupal behaviours at build time

Key patterns:

  • Constructor pattern for component initialisation

  • Event delegation and proper cleanup

  • Accessibility support (keyboard navigation, ARIA)

  • State management and visual feedback

  • Integration with design system classes

  • Data attribute-based element selection for reusability

  • Standard DOM methods (querySelector, addEventListener, etc.)

  • Proper error handling and validation

Implementation approach:

  • Common utilities are managed in /components/00-base

  • Element connections use data- attributes instead of classes, IDs, or element tags

  • Ensures minimal impact on JS when HTML structure changes

  • Promotes reusability across different HTML structures

  • Build process automatically wraps with Drupal.behaviors.attach functions

*.scss - Source Styles

Purpose: Defines the component's visual styling using SCSS.

Characteristics:

  • Uses SCSS features (variables, mixins, nesting)

  • Implements BEM methodology for class naming

  • Integrates with design system tokens and variables

  • Provides responsive design support

  • Includes focus states and accessibility styling

  • Uses mixins for consistent styling patterns

  • Supports light and dark theme variants

  • Uses CivicTheme's color palette system for consistent theming

Key patterns:

BEM naming — all classes use the pattern ct-<component>__<element>--<modifier>:

Design tokens — use token functions instead of hardcoded values:

Theme support — use the component theme mixin for light/dark theme support:

Key features:

  • Design system integration via variables and mixins

  • Responsive breakpoints and media queries

  • State-based styling (hover, focus, active, disabled)

  • Theme support (light/dark variants)

  • Modular and maintainable structure

  • Color palette integration using $ct-colors variable map

  • BEM naming convention for maintainable CSS architecture

Implementation approach:

  • Most styles managed within components in /components directory

  • /assets/sass reserved for Drupal-specific styles (admin blocks, CKEditor, Layout Builder)

  • Color application via /subtheme/components/variables.base.scss using $ct-colors

  • Fine-tuning colors in /subtheme/components/variables.components.scss

  • Default color map reference: civictheme/components/00-base/_variables.base.scss

  • Component color variables reference: civictheme/components/00-base/_variables.components.scss

  • Encouraged to support both light and dark themes for new components

  • Particularly important for giveback components

*.css - Compiled Styles

Purpose: Generated CSS file for production use.

Characteristics:

  • Automatically generated from SCSS source files

  • Contains vendor-prefixed and optimised CSS

  • Includes responsive design rules

  • Provides fallback values and browser compatibility

  • Optimised for performance and file size

Important notes:

  • Do not edit directly - changes will be overwritten

  • Generated via build process (npm run dist)

  • Contains design system variables and custom properties

  • Includes comprehensive state styling and accessibility features

Development Guidelines

File Naming Convention

  • All files use the same base name as the component

  • Follow kebab-case for component names

  • Maintain consistent file extensions

Component Structure

  1. Start with the *.component.yml to define the component's interface

  2. Create the *.twig template with proper documentation

  3. Add *.stories.js for interactive documentation

  4. Implement *.js for any required interactivity

  5. Style with *.scss using design system patterns

  6. Build generates the final *.css file

Best Practices

  • File header documentation is generated from the *.component.yml document

  • Use design system tokens and variables consistently

  • Implement proper accessibility features

  • Test all component variants in Storybook

  • Follow established naming conventions and patterns

  • Ensure responsive design support

  • Include proper error handling and validation

This structure ensures components are maintainable, reusable, and properly integrated with the CivicTheme design system while providing excellent developer experience through comprehensive documentation and testing tools.

Common Pitfalls

Forgetting to rebuild

Changes to SCSS, JavaScript, or Twig files require running npm run dist. Storybook's watch mode handles this automatically, but if you are testing in Drupal you need to rebuild and clear caches.

Namespace conflicts

Your overridden component must use replaces: 'civictheme:component_name' in its .component.yml file. Without this, Drupal will see two components with conflicting names.

Breaking the prop schema

When overriding a component's .component.yml, ensure existing props remain compatible. Adding new props is safe; removing or changing the type of existing props will break templates that depend on them.

Preprocess hook dependencies

Some components receive their data from preprocess hooks in the base CivicTheme theme's includes/ directory. If your override adds new props, you will need to provide data for them through your sub-theme's own preprocess hooks. The mapping system explains how Drupal entities are connected to component templates through preprocess functions.

Last updated

Was this helpful?