Nitro

Essentials

Views

A component's view is a Blade view. The server renders it with Blade for the first page, and the browser renders it again from its compiled form whenever the state changes, updating only what changed.

On this page

You write a component's view like any other Blade view, with echoes, @if, @foreach, @class, Laravel's helpers and PHP's functions. Because the view also runs in the browser, it can only use what works in both places. When something can't run in the browser, the build tells you, with the file and line.

A view rendering in the browser live, in this page View source ↓
  • Ada Lovelace · Mathematician •••••••• 0018
  • Grace Hopper · Rear Admiral •••••••• 0342
  • Alan Turing · Computer Scientist •••••••• 0571
  • Katherine Johnson · Space Scientist •••••••• 0923

4 of 4 contacts

The component

When you type, the list is filtered in the browser. @forelse, $loop->first, @class and the Str:: helpers all run there, and they give the same results as on the server.

Browser + server
<?php

namespace App\Nitro\Components;

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

class Contacts extends Component
{
    public string $search = '';

    public array $contacts = [
        ['name' => 'ada lovelace', 'role' => 'mathematician', 'phone' => '020 7946 0018'],
        ['name' => 'grace hopper', 'role' => 'rear admiral', 'phone' => '020 7946 0342'],
        ['name' => 'alan turing', 'role' => 'computer scientist', 'phone' => '020 7946 0571'],
        ['name' => 'katherine johnson', 'role' => 'space scientist', 'phone' => '020 7946 0923'],
    ];

    #[Computed]
    public function found(): array
    {
        $search = strtolower(trim($this->search));

        return array_values(array_filter($this->contacts, fn ($contact) => $search === '' || str_contains($contact['name'], $search)));
    }
}

One root element

A view must have a single root element, which is the component's own element. Everything the view renders goes inside it.

What you can use in a view

In a view
Echoes {{ }} , {!! !!}
Control flow @if @elseif @else @unless @isset @empty @foreach (with $loop ) @forelse @for @while @break @continue @switch
Attributes @class @style @checked @selected @disabled @readonly @required
Forms @error and $errors , @csrf , @method
Data @json
Children Components by their tag, with :key in a loop
Dynamic children nitro:dynamic-component with :is
Slots nitro:slot , printed as $slot and $slots['name']
Teleport @teleport('modals') ... @endteleport , rendered at @portal('modals') in the layout
Deferred @deferred('stats') ... @placeholder ... @enddeferred in a page (see Page data)
Script @nitroScript ... @endNitroScript : JavaScript run once for each instance as it goes live, never on the server (see Third-party libraries)
Laravel helpers route() , url() , asset() , __() / trans() , and config() for the keys in nitro.public_config
PHP Operators, casts and PHP's functions: strings, mbstring, arrays, math, ctype, URLs, HTML entities, preg_* , sprintf , json_encode and more, tested against PHP
Str:: 54 of Laravel's string helpers ( slug , limit , title , headline , camel , snake , mask , squish , ...), tested against Laravel

Nitro inlines @include and anonymous Blade components (<x-panel>) when it compiles the view. Anything else, such as @php, class-based Blade components or custom directives, can't run in the browser, and the build fails with the file and line.

Displaying data

{{ $name }} escapes its value, in the browser as on the server. {!! $html !!} doesn't escape it, so use it only for HTML you trust. To read a computed value, use $this->total.

Rendering child components

A view can place other components by their tag and pass data to their mount() method (see Components). Inside a loop, give each one a :key. To render a component whose name comes from a value, use nitro:dynamic-component:

Blade
<nitro:dynamic-component :is="$tab" />   {{-- 'settings.profile', 'settings.billing', or '' to render nothing --}}

Using slots

A component can wrap content that its parent passes in. It can receive a default slot and any number of named slots.

<nitro:card>
    <p>{{ $post['title'] }} has {{ $post['comments'] }} comments.</p>

    <nitro:slot name="footer">
        <button nitro:click="publish($post['id'])">Publish</button>
    </nitro:slot>
</nitro:card>
<div class="card">
    {{ $slot }}

    @if ($slots->has('footer'))
        <footer>{{ $slots['footer'] }}</footer>
    @endif
</div>

To check whether a slot was given, use $slots->has('footer') or $slot->isEmpty(). Slot content belongs to the parent, so its handlers and nitro:model act on the parent component. In the example above, publish() is the parent's method.

Rendering content elsewhere with teleport

A modal or a dropdown often needs to render outside the component, at the end of the page. @teleport renders its content where the layout has the matching @portal, while the content stays part of the component:

Blade
{{-- In the component: --}}
@teleport('modals')
    <div class="modal">...</div>
@endteleport

{{-- In the layout, where the content appears: --}}
@portal('modals')

Reading config in the browser

In a view, config() can only read the keys listed in nitro.public_config, which is app.name by default. Their values are sent to the browser, so only list keys that can be public:

PHP
// config/nitro.php
'public_config' => ['app.name', 'shop.currency'],

Next steps