Skip to content

Start building your next app or website — with AI, right in your browser.

Visit devdojo.com
Docs
Layouts

Sites 05 / 13

Layouts

Write your page shell once — head, nav, footer — and let every page drop its content into {{ $slot }}.

Layouts

A layout is the shared shell around your pages — the <html> skeleton, the <head>, your nav and footer. Write it once in resources/views/components/layouts/, and every page slots its content inside. Change the nav in one file, and it changes everywhere. 🧩

A layout is just an ordinary component (see Components) — one that happens to hold the whole document. That's why it lives under components/ and is used with an <x-layouts.…> tag.

The {{ $slot }} variable

A layout is a normal HTML file with one special variable: {{ $slot }}. That's where each page's content lands.

<!-- resources/views/components/layouts/main.blade.php -->
@props(['title' => 'Home', 'description' => ''])
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{{ $title }}</title>
    <meta name="description" content="{{ $description }}">
    @vite('resources/css/site.css')
</head>
<body>
    <x-nav/>

    <main>{{ $slot }}</main>

    <x-footer/>
</body>
</html>

Two lines make this a layout: {{ $slot }} (where page content goes) and @vite('resources/css/site.css') (which loads Tailwind and your styles — more below).

Using a layout from a page

Wrap your page content in an <x-layouts.main> tag — the name after x-layouts. is the layout file (without .blade.php):

<!-- resources/views/pages/index.blade.php -->
<x-layouts.main title="Home">
    <h1>Welcome!</h1>
</x-layouts.main>

Keep the page inside the tags. Everything the page renders goes between the <x-layouts.main> tags — that's the content that lands in {{ $slot }} and gets the document shell around it.

Layout attributes with @props

The @props([...]) line at the top of the layout declares the attributes it accepts, each with a default. Whatever you pass on the <x-layouts.main> tag becomes a variable inside the layout:

<x-layouts.main title="Pricing" description="Simple plans for every team.">
<!-- inside layouts/main.blade.php -->
<title>{{ $title }}</title>
<meta name="description" content="{{ $description }}">
  • @props(['title' => 'Home', 'description' => '']) — the props the layout accepts. Anything you don't pass falls back to the default written right there.
  • Attribute values go in double quotes: title="Pricing".
  • Inside the layout, read a prop with {{ $title }}. Because the default is declared in @props, a page that omits title still renders — it just shows "Home".

Declare before you use. Every variable a layout echoes must be in its @props list (or be the global $site). A stray {{ $subtitle }} that isn't declared is a build error — a fast, visible nudge to add it to @props. When a value is optional, default it: @props(['subtitle' => '']).

Named slots

Sometimes a layout needs more than one content region — say a hero area above the main content. Declare the extra slot in @props and read it like any variable; pages fill it with an <x-slot:name> tag:

<!-- layouts/marketing.blade.php -->
@props(['title' => 'Home', 'hero' => ''])
<!doctype html>
<html lang="en">
<head>
    <title>{{ $title }}</title>
    @vite('resources/css/site.css')
</head>
<body>
    <header class="bg-zinc-900 text-white">{{ $hero }}</header>
    <main>{{ $slot }}</main>
</body>
</html>
<!-- a page using it -->
<x-layouts.marketing title="Launch day">
    <x-slot:hero>
        <h1 class="text-5xl font-bold">We're live!</h1>
    </x-slot>

    <p>Everything you need, shipping today.</p>
</x-layouts.marketing>

The tag's plain body (everything outside the <x-slot:…> tags) is the default {{ $slot }}; each named slot fills its matching variable.

@vite — Tailwind and your CSS

Put @vite('resources/css/site.css') in your layout's <head>. It loads Tailwind CSS and inlines your resources/css/site.css, so your custom styles apply on every page — in the preview, on your published site, and in exports. No build step, no waiting.

Because your Tailwind classes are compiled right in the browser, everything in Tailwind works — including arbitrary values like w-[37px] — the moment you type it. Start your resources/css/site.css with @import "tailwindcss"; and add your own rules below it.

Multiple layouts

You can have as many layouts as you like — say, main.blade.php for regular pages and minimal.blade.php for a landing page with no nav. Each page picks its own by name. A page uses one layout at a time.

Switching a page to a different layout works in either mode:

Open the Layout tab in the sidebar and pick a new layout from the Page layout select. The same tab lists the layout's header and footer sections — and on the canvas, + Add to header and + Add to footer pills at the layout's boundaries let you grow the shared shell without leaving the page.

Change the page's wrapper tag to point at a different layout file in components/layouts/:

<!-- resources/views/pages/launch.blade.php -->
<x-layouts.minimal title="Launch day">
    <h1>We're live!</h1>
</x-layouts.minimal>

Do I need a layout?

For anything beyond a quick experiment, yes — a layout saves you from repeating your <head>, nav, and footer on every page, and it's where @vite loads your styles. A page can render without one, but then it's on its own for the document shell. Future you says thanks.

Next up

The <x-nav/> and <x-footer/> tags above are Components — the other half of never repeating yourself.

© 2026 DevDojo Edit this page