Nitro

Essentials

Methods

A component's methods run in the browser. A click changes the state and the page at once, without a request. Only the methods you mark #[Server] go to the server.

On this page

You write methods the same way you write any PHP method. Nitro compiles them to JavaScript, so a click, a keystroke or a form submission runs your code right there in the browser. The view then renders again with whatever changed. Everything in the cart below happens without the server.

A cart, in the browser live, in this page View source ↓
  • The cart is empty
Subtotal
$0
Delivery
free
Total
$0

The component

add() and remove() change $items. subtotal() and delivery() are marked #[Computed]. updatedPostcode() runs after the postcode field changes. Open Compiled to see the JavaScript that each one becomes.

The browser previews, the server decides

The totals here are only a preview for the visitor, because anything the browser sends can be changed. Work out any prices and totals that money depends on again on the server, from the database, in the #[Server] method that takes the order.

Browser + server
<?php

namespace App\Nitro\Components;

use Nitro\Attributes\Computed;
use Nitro\Component;

class Cart extends Component
{
    public array $products = [
        ['name' => 'Notebook', 'price' => 4],
        ['name' => 'Pen', 'price' => 2],
        ['name' => 'Backpack', 'price' => 35],
    ];

    public array $items = [];

    public string $postcode = '';

    public function add(int $index): void
    {
        $this->items[] = $this->products[$index];
    }

    public function remove(int $index): void
    {
        array_splice($this->items, $index, 1);
    }

    public function updatedPostcode(string $value): void
    {
        $this->postcode = strtoupper(preg_replace('/\s+/', ' ', trim($value)));
    }

    #[Computed]
    public function subtotal(): int
    {
        return array_sum(array_column($this->items, 'price'));
    }

    #[Computed]
    public function delivery(): int
    {
        return $this->subtotal === 0 || $this->subtotal >= 30 ? 0 : 5;
    }
}

Calling methods from the view

An event attribute names a method, or calls it with arguments. The arguments are expressions from the view, such as the loop's $i. Actions like $set and $toggle change a property without a method of your own.

Blade
<button nitro:click="add">Add</button>
<button nitro:click="remove($i)">Remove</button>
<button nitro:click="$set('postcode', '')">Clear the postcode</button>
<button nitro:click="$toggle('open')">Details</button>

Any DOM event works, with modifiers such as .prevent and .enter. See Directives for the full list.

Computing values

You read a #[Computed] method as if it were a property, as $this->subtotal, both in the class and in the view. Nitro works it out once and keeps the result until the state changes. A computed method takes no parameters. It isn't part of the state, so it's never sent anywhere.

Compute values instead of storing them

A total, a filtered list or a count is better computed than kept in a property. It always matches the state, and the state stays small.

Reacting to changes

updatedPostcode($value) runs in the browser after nitro:model or $set changes $postcode. updated($property, $value) runs after any such change. The cart uses it to tidy what was typed. Type sw1a 1aa in the postcode field and leave it to see the result.

Helper methods

Every component has these methods:

Call What it does
$this->reset('prop', ...) Puts properties back to their defaults
$this->js('...') Runs JavaScript after the next render, with $nitro , $refs and $el
$this->dispatch('event', ...) Dispatches an event to other components (see Events)

PHP in the browser

The compiled code behaves the way PHP does. Arrays are values, integers stay integers, and functions such as array_splice(), preg_replace() and strtoupper() give PHP's results. You can use operators, casts, and PHP's string, array, math, ctype, URL and preg_* functions, as well as 54 of Laravel's Str:: helpers. All of them are tested against PHP and Laravel.

Code that can't run in a browser, such as a facade, a model query, new or a function the browser doesn't have, fails the build. The error names the file and line and tells you what to do, so you find out before your visitors do. Move that code to a server method.

Paginating and sorting

The Nitro\Concerns\WithPagination and WithSorting traits page and sort an array in the browser:

app/Nitro/Components/Posts.php Browser
use Nitro\Concerns\WithPagination;
use Nitro\Concerns\WithSorting;

class Posts extends Component
{
    use WithPagination, WithSorting;

    public array $posts = [];

    public string $search = '';

    #[Computed]
    public function rows(): array
    {
        $found = array_filter($this->posts, fn ($post) => str_contains(strtolower($post['title']), strtolower($this->search)));

        return $this->paginate($this->sorted($found), 12);
    }

    public function updatedSearch(): void   // A new search starts on the first page.
    {
        $this->resetPage();
    }
}
Blade
<th nitro:click="sortBy('title')">Title {{ $this->sortIcon('title') }}</th>
...
@foreach ($this->rows['items'] as $post)
    ...
@endforeach

<p>{{ $this->rows['from'] }}–{{ $this->rows['to'] }} of {{ $this->rows['total'] }}</p>
<button nitro:click="previousPage">Previous</button>
<button nitro:click="nextPage">Next</button>
  • paginate() returns items, page, pages, total, from and to. You move between pages with gotoPage(), previousPage(), nextPage() and resetPage(), and the page number is kept in the query string.
  • sorted() works with sortBy('name'), which reverses the order when you call it again, and with sortIcon('name').
  • Call resetPage() when a filter changes, so that a new search starts from the first page.

Next steps