PHPackages                             redant/twig-components - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Templating &amp; Views](/categories/templating)
4. /
5. redant/twig-components

ActiveLibrary[Templating &amp; Views](/categories/templating)

redant/twig-components
======================

Define reusable components in Twig.

1.2.2(7mo ago)3819.8k↓33.3%31MITPHPPHP &gt;=8.0

Since Feb 28Pushed 7mo ago3 watchersCompare

[ Source](https://github.com/redantnl/twig-components)[ Packagist](https://packagist.org/packages/redant/twig-components)[ Docs](https://github.com/redantnl/twig-components)[ RSS](/packages/redant-twig-components/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (2)Dependencies (2)Versions (12)Used By (1)

Twig Components
===============

[](#twig-components)

Twig Components are robust, reusable and automatically documented elements you can use in your Twig templates using the new `component` tag. Twig components allow you to quickly build and maintain your own UI toolkit, where each button, table or card has to be designed only once and can be used throughout your entire application.

This approach improves the developer experience in key ways:

- Easy syntax for rendering (using) a component;
- Notifications when a required parameter is missing;
- Useful suggestions when making a typo in a parameter name;
- Alerting when supplying the wrong type of data;
- Flexibility with parameter ordering.

There's also a nifty [Symfony bundle](https://github.com/redantnl/twig-components-bundle) available.

Quick start
-----------

[](#quick-start)

### Installation

[](#installation)

The extension is installable via Composer:

```
$ composer require redant/twig-components
```

or directly in your `composer.json`:

```
{
    "require": {
        "redant/twig-components": "~1.0"
    }
}
```

### Setup

[](#setup)

You can add the extension to Twig like this:

```
use RedAnt\TwigComponents\Registry as ComponentsRegistry;
use RedAnt\TwigComponents\Extension as ComponentsExtension;

// Initialize Twig
$loader = new \Twig\Loader\FilesystemLoader($templateDir);
$loader->addPath($componentsDir, 'Ui'); // Creates a @Ui namespace for the specified dir
$twig = new \Twig\Environment($loader);

// Initialize Twig Components registry
$componentsRegistry = new ComponentsRegistry($twig);
$componentsRegistry->addComponent('ui.button', '@Ui/elements/button');
// ... add more components here

// Add the extension to your Twig environment
$componentsExtension = new ComponentsExtension($componentsRegistry);
$twig->addExtension($componentsExtension);
```

What is a component?
--------------------

[](#what-is-a-component)

Components are, in a way, inspired by plain ol' programming language functions. Components have a fixed list of parameters, so you can't use parameters that haven't been defined on the component. All parameters are type checked and self-documenting. The full component documentation can then be automatically assembled into a folder of Markdown files. Every component must supply a nested hash with configuration options, similar to the macro definition we've used before.

Why be so strict on type checking in a template? One of the reasons is that we want to be able to use these components (and their documentation, as you will see) as a means of communication between technically involved component designers and front-end oriented developers.

Twig is, by design, very forgiving in many aspects, which is great if you have complete knowledge, but may get in the way of that communication between people of different skill or information levels. We don't want a component user to have to dig into the specific component implementation every time---we want them to be able to draw from something like the public API of our regular code. That's why we enforce a more stricter use: now we're able to help users with small typos or type mismatches.

But enough words, let's look at an example component definition: for a button.

A Twig component defines a number of properties with strict typing, default values, and comments for these properties, and specifies which properties are required. Each property can be rendered to an attribute when implementing your component. A property is only required if you mark it required. You can set default values otherwise.

```
{% component button {
    container:           { type: 'string', default: 'button', comment: 'HTML element, e.g. "button" (default) or "a"' },
    label:               { type: 'string', required: true, comment: 'Button text (rendered as raw HTML)' },
    classes:             { type: 'string[]', default: [ 'small' ], comment: 'Additional button classes'},
    some_object:         { type: 'Some\\Namespace\\SomeObject', comment: 'An implementation of a component' },
    absent_object:       { type: '?Some\\Namespace\\AbsentObject', comment: 'An implementation of a component which can be absent at any point' }
} with options %}
```

You'll notice how this file starts with a comment, which is optional. When present, it will be used when rendering documentation for this component. Right after is the actual component definition in the `{% component %}` tag. Three parameters for this button component are defined, all of type `string`, with only one of them required (the button's `label`). We can document each property by providing a short description (`comment`), and an example value in the `preview` argument.

In addition, Twig Components enforce some best practices to promote consistency between components, such as:

1. The name of the file must equal the name of the component (i.e., `button.html.twig` must define a component called `button`);
2. Only use snake case (`snake_case`) variable names;
3. Do not end comments with a period.

Okay, that last one might feel a bit arbitrary or strict but believe me, it looks way better in your documentation if there's some consistency in your parameter descriptions.

This button component will generate a Twig variable `button` that contains all properties, with the value from the `options` variable or the specified default value.

Every value inside `options` will be checked for its name, type and, for required properties, whether it's defined or not. The value can be of a type referencing an object. If the object is not always available like `absent_object` you can prefix it with a `?` to mark the type as nullable, in which case an error will be avoided.

### Usage

[](#usage)

Every defined component is accessible through a Twig global that references the Twig component service, effectively putting the components in the `component`namespace. For example, the `button` component can be accessed as `component.button()`inside any Twig template.

If you don't like the name 'component', we've got you covered! See the next section.

```
{{ component.button({
    container: 'a',
    label: 'Click me',
    classes: [ 'large' ]
}) }}
```

Since all specified properties will be checked, a typo such as `{{ component.button({ lable: 'Click me' })` will be detected. Also, `{{ component.button({}) }}` will throw a runtime error, because the `label` property is required.

The hash you give to the component is first checked for name consistency with the component definition. For instance, if you would accidentally type `lable`instead of `label`, Twig Components would give you a nice runtime error message: `Component "button" does not contain property "lable". Did you mean "label"?`.

Also, it does type-checking: when you supply an array as the `url`, it fails. Every parameter is checked using the `is_string`, `is_bool`, `is_int`, `is_float`, and `is_array` checks. Parameters can also enforce a specific PHP class, in which case the `instanceof` check is used. This ensures you will actually notice when you're not using a component correctly.

**Note**: In reusable bundles, always use the `render_component()` function, because a user may have defined a different component global variable (see below).

```
{{ render_component('button', {
    container: 'a',
    label:     'Click me',
    classes:   [ 'large' ]
}) }}
```

A few examples are included in the `doc` folder.

### Global variable

[](#global-variable)

If you don't like the name of the global variable that defines the components, use the `$globalVariable` parameter of the Extension to change this:

```
$componentsExtension = new ComponentsExtension($twig, 'ui');
```

This will register the button component as `ui.button()`.

**Note**: If you set the prefix to `false`, no Twig global will be registered for defined components. You can then only use the `render_component` function to render components.

License
-------

[](#license)

This library is licensed under the MIT License - see the LICENSE file for details.

Twig Components were conceived by Gert Wijnalda  and were inspired by [this post](https://voices.basedesign.com/dry-templating-with-twig-and-craft-cms-543292d114aa)by Pierre Stoffe.

Parts of this documentation were first featured in the article ['Taming Twig'](https://www.phparch.com/article/taming-twig-crafting-high-quality-dry-templates/), originally published in the April 2019 issue of php\[architect\] magazine.

Both the Twig Components code and this documentation were greatly enhanced by the invaluable feedback from my colleagues at RedAnt, notably Vincent Vermeulen, Rico Humme, Florian Käding, and Martijn van Beek. Thank you so much, guys!

###  Health Score

50

—

FairBetter than 96% of packages

Maintenance62

Regular maintenance activity

Popularity36

Limited adoption so far

Community17

Small or concentrated contributor base

Maturity72

Established project with proven stability

 Bus Factor1

Top contributor holds 50% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~266 days

Recently: every ~327 days

Total

10

Last Release

235d ago

Major Versions

0.1.1 → 1.0.02020-01-10

PHP version history (3 changes)0.1PHP &gt;=7.0

1.0.0PHP &gt;=7.2

1.2.0PHP &gt;=8.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/3b256428c169532f2326e30a442c7f0238f164a146e59b365db4ffceb4b98eff?d=identicon)[cinamo](/maintainers/cinamo)

---

Top Contributors

[![ricohumme](https://avatars.githubusercontent.com/u/11029998?v=4)](https://github.com/ricohumme "ricohumme (14 commits)")[![cinamo](https://avatars.githubusercontent.com/u/7139230?v=4)](https://github.com/cinamo "cinamo (12 commits)")[![fey](https://avatars.githubusercontent.com/u/697178?v=4)](https://github.com/fey "fey (1 commits)")[![zackad](https://avatars.githubusercontent.com/u/10742906?v=4)](https://github.com/zackad "zackad (1 commits)")

---

Tags

twig-extensiontwigcomponentsextension

### Embed Badge

![Health badge](/badges/redant-twig-components/health.svg)

```
[![Health](https://phpackages.com/badges/redant-twig-components/health.svg)](https://phpackages.com/packages/redant-twig-components)
```

###  Alternatives

[symfony/ux-twig-component

Twig components for Symfony

21814.8M162](/packages/symfony-ux-twig-component)[symfony/ux-live-component

Live components for Symfony

1635.6M72](/packages/symfony-ux-live-component)[symfony/ux-toolkit

A tool to easily create a design system in your Symfony app with customizable, well-crafted Twig components

1432.0k](/packages/symfony-ux-toolkit)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
