This is the full developer documentation for Wire Drupal.
# Start of Wire documentation
# Quickstart
Get started with Wire Drupal quickly
## Install Wire Drupal
Install the modules
```bash
composer require wire-drupal/wire
```
Enable the module
```bash
drush en wire
```
## Create a component
A new component can be generated with a Drush command
```bash
drush generate wire
```
Assuming all needed prompts have been answered and the ID has been set as `counter`, the following two files are going to be generated:
`../wiredemo/src/Plugin/WireComponent/Counter.php`
```php
namespace Drupal\wiredemo\Plugin\WireComponent;
use Drupal\wire\Plugin\Attribute\WireComponent;
use Drupal\wire\WireComponentBase;
use Drupal\wire\View;
#[WireComponent(id: 'counter')]
class Counter extends WireComponentBase {
public function render(): ?View {
return View::fromTpl('counter');
}
}
```
`../wiredemo/templates/wire/counter.html.twig`
```html
...
```
A boiler plate twig file has been created so let's add some content
```html
Hello World!
```
> Worth noting that each Wire component must have a single root element.
## Include the component
A Wire component can be included anywhere throughout your app with `wire()` Twig function
```twig
...
{{ wire('counter') }}
...
```
It can also be included in any render-able array via `wire` render element. E.g:
```php
namespace Drupal\wiredemo\Controller;
use Drupal\Core\Controller\ControllerBase;
class CounterController extends ControllerBase {
public function content(): array {
return [
'#type' => 'wire',
'#id' => 'counter',
];
}
}
```
Visit the page where Wire Component has been included in the browser and you should see "Hello World!".
> **Note**: Ensure that the module in which the component has been generated is enabled
## Add "counter" functionality
Replace generated content of the `counter` component class and template with the following
`../wiredemo/src/Plugin/WireComponent/Counter.php`
```php
namespace Drupal\wire\Plugin\WireComponent;
use Drupal\wire\Plugin\Attribute\WireComponent;
use Drupal\wire\WireComponentBase;
use Drupal\wire\View;
#[WireComponent(id: 'counter')]
class Counter extends WireComponentBase {
public int $count = 0;
public function increment() {
$this->count++;
}
public function render(): ?View {
return View::fromTpl('counter');
}
}
```
`../wiredemo/templates/wire/counter.html.twig`
```twig
{{ count }}
```
## View it in the browser
Now reload the page in the browser, you should see the counter component rendered.
If you click the "+" button, the page should automatically update without a page reload.
> This is the most basic example to give you an idea of what is going on here. Check other Docs pages to see what Wire can do and what problems it can solve.
## Credits
WireDrupal is inspired by [Livewire](https://livewire.laravel.com/) and uses [Alpine.js](https://alpinejs.dev/) to deliver DOM diffing and client-side functionality.
It integrates these tools into the [Drupal](https://drupal.org) ecosystems, building on the foundational work of [Caleb Porzio](https://calebporzio.com/).
# Essentials
Learn the fundamental concepts of Wire including components, properties, actions, and events.
Welcome to the Wire Drupal essentials section. Here you'll learn the fundamental concepts and building blocks of Wire components.
## What You'll Learn
This section covers the core concepts you need to understand to work effectively with Wire:
- **Installation** - Get Wire up and running in your Drupal project
- **Making Components** - Create your first Wire components
- **Rendering Components** - Display components in your templates
- **Properties** - Manage component state and data
- **Actions** - Handle user interactions and events
- **Events** - Communicate between components
- **Hooks** - Use lifecycle methods
- **Nesting Components** - Build complex UIs with component composition
## Getting Started
If you're new to Wire, we recommend starting with the [Installation](/docs/installation) guide and then working through each topic in order. Each guide builds on the concepts from the previous ones.
## Prerequisites
Before diving into these guides, you should have:
- A working Drupal installation
- Basic knowledge of PHP and Drupal module development
- Familiarity with HTML and JavaScript
## Installation
Complete installation guide for Wire Drupal
## Requirements
1. PHP 8.1 or higher
2. Drupal ^10.2
3. Drush ^12 (optional)
Visit the [composer.json](https://github.com/wire-drupal/wire/blob/main/composer.json) for the complete list of package requirements.
## Install Wire Drupal
Install the module
```bash
composer require wire-drupal/wire
```
Enable the module
```bash
drush en wire
```
Wire doesn't need any other config at this point.
## Making Components
Learn how to create Wire components
## Introduction
Run the following Drush command to create a new Wire component
> We'll assume you entered the Wire Label as "Articles" in a module with "wiredemo" machine name
```bash
drush generate wire
```
> **Note:** Drush ^12 is required for the generate command to work
Two new files were created in your chosen module:
```
../wiredemo/src/Plugin/WireComponent/Articles.php
../wiredemo/templates/wire/articles.html.twig
```
## Inline Components
If you wish to create an Inline component (without `.twig` files), you can answer the "Inline" prompt as "Yes" and only the PHP class will be created:
```
../wiredemo/src/Plugin/WireComponent/Articles.php
```
Here's what it would look like:
```php
namespace Drupal\wiredemo\Plugin\WireComponent;
use Drupal\wire\Plugin\Attribute\WireComponent;
use Drupal\wire\WireComponentBase;
use Drupal\wire\View;
#[WireComponent(id: 'articles')]
class Articles extends WireComponentBase {
public function render(): ?View {
$twig = <<<'TWIG'
TWIG;
return View::fromString($twig);
}
}
```
## Rendering Components
How to render components in templates
## The Basics
To render a Wire component on a page use the `wire()` Twig function:
```twig
...
{{ wire('related_articles') }}
...
```
Or, if you're in the context of a renderable array (e.g. Form, Controller), you can use the `wire` render element:
```php
$build['related_articles'] = [
'#type' => 'wire',
'#id' => 'related_articles',
];
```
> **Note**: Ensure that the module in which the component has been generated is enabled
## Parameters
### Passing Parameters
You can pass data into a component by passing additional parameters into the `wire()` function.
For example, let's say we have a "related_articles" component we want to include via Node's `node.html.twig` template. Here's how you would pass in the ID of the Node entity object:
```twig
{{ wire('related_articles', {'nodeId': node.id}) }}
```
When using `wire` render element you would do:
```php
$build['related_articles'] = [
'#type' => 'wire',
'#id' => 'related_articles',
'#context' => ['nodeId' => 999],
];
```
### Receiving Parameters
Wire will automatically assign parameters to matching **public** properties.
Make sure to read the [Properties](/docs/properties#important-notes) section to align your expectations.
For example, in the case of `wire('related_nodes', {'nodeId': node.id})`, if the respective component has a public property named `$nodeId`, it will be automatically assigned and persist between Wire updates:
```php
use Drupal\wire\Plugin\Attribute\WireComponent;
use Drupal\wire\WireComponentBase;
#[WireComponent(id: 'related_articles')]
class RelatedArticles extends WireComponentBase {
public ?int $nodeId;
...
}
```
If for whatever reason, this automatic behavior doesn't work, you can intercept parameters using the `mount()` method:
```php
use Drupal\node\Entity\Node;
use Drupal\wire\Plugin\Attribute\WireComponent;
use Drupal\wire\WireComponentBase;
#[WireComponent(id: 'related_articles')]
class RelatedArticles extends WireComponentBase {
public ?int $nodeId;
public string $label;
public function mount($nodeId) {
$this->label = 'Related articles for: ' . Node::load($nodeId)->label();
}
}
```
The `mount()` method is only called when the component is first mounted and will NOT be called again when the component is refreshed or re-rendered. Think of it as a class `__construct()` method.
At this point you might wonder if you can pass in the whole Node entity object.
The answer is yes, but with a caveat. When you pass any unsupported [property](/docs/properties), it can be intercepted in the `mount()` method but it won't persist during Wire updates.
```twig
{{ wire('related_articles', {'node': node}) }}
```
In the PHP class:
```php
use Drupal\wire\Plugin\Attribute\WireComponent;
use Drupal\wire\WireComponentBase;
use Drupal\wire\View;
#[WireComponent(id: 'related_articles')]
class RelatedArticles extends WireComponentBase {
protected ?Node $node;
public string $label;
public function mount(?Node $node) {
$this->node = $node;
}
public function render(): ?View {
// $this->node is available here but only on the initial load.
}
}
```
## The Render Method
A Wire component's `render` method gets called on the initial page load and every subsequent component update.
### Returning Template
The `render()` method is expected to return an instance of `Drupal\wire\View` which has a few different ways to get its HTML.
Here is an example using `View::fromTpl()`:
> Make sure your Twig template only has ONE root element.
```php
public function render(): ?View {
return View::fromTpl('articles', [
'articles' => Node::loadMultiple(),
]);
}
```
`/wiredemo/templates/wire/articles.html.twig`
```twig
{% for article in articles %}
{{ article.label }}
{% endfor %}
```
The `::fromTpl()` method expects the filename without its extension part, which must be located in a `templates/wire/` directory of a module or theme. The priority of loading the template is: active theme → parent/base theme(s) → module.
### Returning String
If you don't want to use a Twig file at all, you can return a template string directly from `render()` method:
```php
public function render(): ?View {
$twig = <<<'TWIG'
{% for article in articles %}
{{ article.label }}
{% endfor %}
TWIG;
return View::fromString($twig);
}
```
### Returning anything Renderable
You might want to render using Theme Implementations (`hook_theme`), [Render elements](https://www.drupal.org/docs/drupal-apis/render-api/render-elements), etc.
This can be achieved with the [render_var](https://www.drupal.org/docs/theming-drupal/twig-in-drupal/functions-in-twig-templates#s-render-vararg) function.
Example:
```php
public function render(): ?View {
$rendarableEl = [
'#type' => 'theme',
'#theme' => 'my_theme_accepting_dynamic_value',
'#my_dynamic_value' => $this->dynamicValue,
];
$twig = <<<'TWIG'
{{ render_var(rendarableEl) }}
{{ my_dynamic_value }}
TWIG;
return View::fromString($twig, [
'my_dynamic_value' => $this->count,
'rendarableEl' => $rendarableEl,
]);
}
```
## Properties
Working with component properties
# Properties
## Introduction
Wire components store and track data as public properties on the component class.
```php
class HelloWorld extends WireComponentBase {
public string $message = 'Hello World!';
public function render(): ?View {
$twig = <<<'TWIG'
{{ message }}
TWIG;
return View::fromString($twig);
}
}
```
No need to explicitly pass them into the view although you can if you want or maybe you need to to modify it, in which case it will be:
```php
...
return View::fromString($twig, ['message' => strtolower($this->message)]);
```
### Important Notes
Essential things to note about public properties:
- Property names can't conflict with property names reserved for Wire (e.g. id)
- Data stored in public properties is made visible to the front-end JavaScript. Therefore, you SHOULD NOT store sensitive data in them.
- Properties can ONLY be either JavaScript-friendly data types (string, int, array, boolean), OR one of the following PHP types: Stringable, Collection, DateTime.
> `protected` and `private` properties DO NOT persist between Wire updates. Generally, you should avoid using them for storing state.
> Also, note that while `null` data type is JavaScript-friendly, public properties set to `null` DO NOT persist between Wire updates.
## Initializing Properties
Properties can be initialized by using the `mount` method of the component.
```php
class HelloWorld extends WireComponentBase {
public string $message;
public function mount() {
$this->message = 'Hello World!';
}
}
```
Additionally, a `$this->fill()` method is available for cases where you have to set lots of properties.
```php
public function mount() {
$this->fill(['message' => 'Hello World!']);
}
```
Also, Wire offers `$this->reset()` and `$this->resetExcept()` to programmatically reset public property values to their initial state. This is useful for cleaning input fields after performing an action.
```php
public function resetFilters() {
// Reset the search property only.
$this->reset('search');
// Reset both, search AND tags properties.
$this->reset(['search', 'tags']);
// Reset everything but the search property.
$this->resetExcept('search');
}
```
## Data Binding
Wire can "bind" (or "synchronize") the current value of some HTML element with a specific property in your component.
```php
class HelloWorld extends WireComponentBase {
public string $message;
}
```
```twig
{{ $message }}
```
When a user types something into the text field, the value of the `$message` property will automatically update.
Internally, Wire will listen for an `input` event on the element, and when triggered, it will send an AJAX request to re-render the component with the new data.
> You can add `wire:model` to any element that dispatches an `input` event. Even custom elements, or third-party JavaScript libraries.
Common elements to use `wire:model` on include:
- ``
- ``
- ``
- `