Install
This page is how you add Wire to an Adonis app after the overview has explained the round trip. It is not the admin-panel installer. You make a class, a view, and a tag. The provider finds the class when the app boots. You do not register a route per component.
Install @shamar/adonis. It depends on @shamar/wire, so you get the kernel with the panel. Install @shamar/wire on its own only when a page has no admin panel.
Later versions are published from GitHub Actions. npm trusts the publish.yml workflow in coolsam726/shamar as the publisher for @shamar/wire. A GitHub release runs that workflow.
The files live in three places. The left column is the same idea in Livewire, only if that comparison helps.
| Livewire | Wire |
|---|---|
app/Livewire/Counter.php |
app/wire/counter.ts |
resources/views/livewire/counter.blade.php |
resources/views/wire/counter.edge |
<livewire:counter /> |
<wire:counter /> or @wire('counter') |
The provider registers every class it finds. You do not write a kernel file, and you do not add routes for the browser script.
1. Add the provider
Section titled “1. Add the provider”pnpm add @shamar/adonis@shamar/adonis already depends on @shamar/wire. In adonisrc.ts:
providers: [ () => import('@adonisjs/core/providers/app_provider'), () => import('@adonisjs/core/providers/edge_provider'), () => import('@adonisjs/shield/shield_provider'), () => import('@shamar/adonis/provider'),]If this app already hosts a Shamar panel, the provider is already in that list. Stop here and generate a component.
Boot does four things:
- Imports every class under
app/wire(an empty folder is fine). - Mounts
resources/views/wireso Edge can renderwire::counter. - Registers
<wire:counter />,@wire(),@persist(), and thewire()helper. - Registers
GET /wire.jsandPOST /wire, and signs snapshots withAPP_KEY.
No config/shamar.ts means there is no admin panel. /wire is still registered.
2. Make a component
Section titled “2. Make a component”node ace make:wire counternode ace make:wire posts/form| File | Tag |
|---|---|
app/wire/counter.ts |
@wire('counter') |
app/wire/posts/form.ts |
@wire('posts.form') |
app/wire/posts/create_form.ts |
@wire('posts.create-form') |
The class default-exports public fields as state and methods as actions. The view sits next to it, with the same path under resources/views/wire.
import { Wire } from '@shamar/adonis'
export default class Counter extends Wire { count = 0
increment() { this.count++ }}<button type="button" wire:click="increment">{{ count }}</button>{{ count }} is the public field. Edge escapes it. @wire is one component per line, the same way @include is. Restart the dev server after adding a class: discovery runs at boot, not on every request.
3. Put it on a page
Section titled “3. Put it on a page”<!doctype html><html> <head> <meta charset="utf-8" /> <title>Counter</title> <meta name="csrf-token" content="{{ csrfToken }}" /> <script defer src="/wire.js"></script> </head> <body> <wire:counter /> </body></html>router.get('/counter', async ({ view }) => view.render('pages/counter'))<wire:counter /> and @wire('counter') render the same island. @wire is one component per line. The element form can sit in markup:
<wire:counter /><wire:counter :count="4" /><wire:posts.form title="Hello" :open="canEdit" />A plain attribute is a string. :count is JavaScript, and count="{{ starting }}" is the same expression. Number and boolean fields are coerced from those strings, so count="4" still fills a count = 0 field. Unknown keys are ignored. <wire:counter></wire:counter> is the same as the self-closing tag when the body is empty.
@wire('counter', { count: 3 }) passes a props object directly. Inside the provider’s islands, the browser posts to /wire.
The playground serves this at /counter, with a second page at /counter/about linked by wire:navigate.
@persist('nav') <a href="/counter" wire:navigate>Counter</a>@end@persist wraps a region in wire:persist so SPA navigation keeps that DOM node. The full behavior is SPA navigation.
What you can skip
Section titled “What you can skip”Without Adonis is the kernel used by itself: you construct WireKernel, return HTML from render, and serve /wire.js. Components documents that object API. A normal Adonis app stays on this page.