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: - `` - `` - `` - `