Quickstart

Last updated on
7 October 2025

In web development, a component is a part of a web page or application that is modular and reusable, with a specific functionality or purpose. It's like a building block that can be used to create more complex interfaces. Drupal's Single-Directory Components consist of metadata that describe the component, HTML markup, and, optionally, CSS and JavaScript, which are all located in the same directory. Hence, the name, Single-Directory Components.

Learn more about what components are and why they are important for Drupal.

To demonstrate how Single-Directory Components work, we're going to walk through creating an example 'chip' component and use it in a theme.

Prerequisites to working with components

  • You must be using Drupal 10.1 or greater
    • If using a version prior to Drupal 10.3, you must have the Single-Directory Components module enabled (at admin/modules)
  • You must have a theme (or module) that you want to add components to. The theme must be installed (at admin/appearance)
  • You must know where in the filesystem the theme's code is located. (We'll be using a custom theme, located in the custom directory at themes/custom/MY-THEME in this example.  Learn more about generating a custom theme with the Starterkit theme script.)

Define a component

Every component requires a single directory for its assets to reside in. This directory must exist in a components/ subdirectory of your theme (so that Drupal can find it). A {NAME}.component.yml file with metadata about the component is required.

Pick a name for your component. We'll use "chip" for our example. It should be unique within the theme. Components are namespaced, so multiple different themes could declare a "chip" component.

Create the directory themes/custom/MY-THEME/components/chip/. Then, in that directory, create a file starting with your component name, followed by .component.yml. For example, chip.component.yml.

Populate the chip.component.yml file with metadata that describes the component:

name: Chip
props:
  type: object
  required:
    - color
  properties:
    # Can the chip be dismissed by clicking on it?
    dismissable:
      type: boolean
      title: Dismissable
      description: If true users can dismiss the chip by clicking on it.
    # One of 'primary', or 'secondary'.
    color:
      type: string
      title: Color
      description: "Background color to use for the chip, one of 'primary' or 'secondary'."
      # The enum directive restricts the possible values in the element to our list.
      enum: ['primary', 'secondary'] 
slots:
  # Content to display in the chip.
  content:
    title: Content
    description: Content of the chip

The data in this file describes your component to Drupal and to anyone who wants to make use of it. This one includes a human-readable name for the component. Definitions of the component’s inputs in the form of props (for data whose type and structure is well defined) and slots (for data with an unknown structure, like nested components). These act as an API or contract for the component, and is like saying, "We promise to always accept and use these inputs."

Props, and slots, are declared using JSON Schema syntax, and null, boolean, object, array, number, and string are valid types. The top level props key is always an object that contains the properties which are mapped to variables in the component's template file.

Learn about additional metadata values.

Add some markup

A component that doesn't output anything isn't that useful. So let’s add some markup via a Twig file. Within the component’s directory, create a .twig file using the name of your component.

For example, in components/chip/chip.twig, add the following:

{%
  set classes = [
  'chip',
  'chip--color-' ~ color|clean_class,
  dismissable ? 'chip--dismissable',
]
%}
<div{{ attributes.addClass(classes) }}>
   {{ content }}
</div>

The above code contains some HTML markup and Twig expressions that make use of component inputs in order to output dynamic content.

The Twig variables available to the template, which in the above example are colordismissable, and content, are the keys of the props.properties and slots arrays defined in the [COMPONENT].component.yml file. The attributes variable that is automatically added to all component templates is also available.

Note: There is an alternative syntax for printing slots using Twig block tag. See Learn more about using your components in render element and template files for more information.

Add some style

Let's add some CSS and make that chip look a little more attractive. This requires creating a CSS file with the name of your component in the component directory, and well, ...that's it!

Create the file, themes/custom/MY-THEME/components/chip/chip.css, with the following contents:

.chip {
  display: inline-block;
  padding: 0.25rem;
}

.chip--color-primary {
  background-color: darkblue;
  color: white;
}

.chip--color-secondary {
  background-color: lightgray;
  color: black;
}

.chip--dismissed {
  display: none;
}

If the component’s {NAME}.css file exists, Drupal will automatically find it, and include it on the page. In the case of our chip component, since the chip.css file exists, Drupal will use it whenever the chip component is used in a template file.

Finally, add some interaction with JavaScript

Adding some JavaScript to our component isn't any harder. Let's add some JavaScript that will make it so the chip can be dismissed (hidden) when a user clicks on it. This requires creating a {NAME}.js file with the component name in the component’s directory.

Create the file, themes/custom/MY-THEME/components/chip/chip.js, with the following JavaScript code:

((Drupal) => {
  Drupal.behaviors.chip = {
    attach(context) {
      context.querySelectorAll('.chip--dismissable').forEach((chip) => {
        chip.addEventListener('click', () => {
          chip.classList.toggle('chip--dismissed');
        })
      });
    },
  };
})(Drupal);

Refresh the page and Drupal should automatically locate this new JavaScript file and include it whenever the chip component is used. You can test that it's working by setting the dismissable prop of your component to true, and then clicking on the chip element. (It should disappear.) Now set it to false, and clicking should have no impact.

Note: this ties together code in CSS where we have classes to show/hide the chip and the Twig file where we dynamically decide whether or not to add the .chip--dismissable class depending on the dismissable prop's value.

Take it further

Components can do a lot more. Now that you understand this brief example, check out the complete annotated example to learn more. Here are a few things to experiment with:

  • You can include other assets in the directory, too, like images, but they won't be automatically loaded. You'll need to reference them via your Twig, CSS, or JavaScript files. Can you add an icon to your chip component?
  • Use the libraryOverrides in your {NAME}.component.yml file to require additional JavaScript libraries like drupal/once or jQuery. Can you rewrite the JavaScript so that it uses the drupal/once library?

Use your component

In order to use the markup generated by your component, you'll need to "use" it into:

  • a render element on PHP code
  • a Twig template file in your theme. 

Learn more about using your components in render element and template files.

With the rise of design system methodology and display building tools, render elements are the way to go, but in the context of this tutorial, let's try to use ours  in the node template file to display the node type (bundle) as a chip.

Edit the themes/custom/MY-THEME/templates/content/node.html.twig template file and add the following (where you want the chip to display):

{% set chip_content %}
Type: <span>{{ node.bundle() }}</span>
{% endset %}

{{ include('MY-THEME:chip', {
  color: 'primary',
  dismissable: true,
  content: chip_content,
}, with_context = false) }}

This Twig uses the standard Twig include function to include the chip component (with a twist: the namespacing of the component MY-THEME:chip resolves to the 'chip' component in the MY-THEME theme) and pass the expected values:

  • color and dismissable are  props defined the component’s definition file ({NAME}.component.yml).
  •  content is a  slot, also defined in the component’s definition file

Clear the cache and view a node on your site. You should see the node type output as a chip on the page where you included the component in the node template file.

Help improve this page

Page status: No known problems

You can: