Split the template into pieces (layout, navbar, card, button), save each as an anonymous component in resources/views/components, replace content with {{ $slot }} and @props, and put {{ $attributes->merge([...]) }} on the root so callers can add classes.
Start with the layout
Move the shared page shell into resources/views/components/layout.blade.php. Everything that changes between pages goes in the slot.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{ $title ?? 'App' }}</title>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="bg-gray-50 text-gray-900">
{{ $slot }}
</body>
</html>Pages then use <x-layout>...</x-layout>, and you can pass the title as a named slot: <x-slot:title>Pricing</x-slot>.
Turn repeated blocks into components
Any block you see more than once (cards, buttons, form fields) becomes a component. Data goes in @props, inner content goes in $slot, and the root element merges whatever attributes the caller passes.
{{-- resources/views/components/card.blade.php --}}
@props(['title'])
<div {{ $attributes->merge(['class' => 'rounded-xl border border-gray-200 bg-white p-6']) }}>
<h3 class="text-lg font-semibold">{{ $title }}</h3>
<div class="mt-2 text-sm text-gray-600">{{ $slot }}</div>
</div><x-card title="Fast setup" class="shadow-sm">
Ready in two minutes.
</x-card>Because of merge, the shadow-sm class is added to the component's own classes instead of replacing them. Other attributes like id or wire:click pass straight through.
Loops and conditionals
Hard-coded lists in the template become @foreach over data you pass in from the controller or define in @props:
@props(['links' => [
['label' => 'Features', 'href' => '/features'],
['label' => 'Pricing', 'href' => '/pricing'],
]])
<ul class="flex gap-8 text-sm">
@foreach ($links as $link)
<li><a href="{{ $link['href'] }}" class="hover:text-indigo-600">{{ $link['label'] }}</a></li>
@endforeach
</ul>For conditional classes, $attributes->class([...]) and the @class directive accept an array of class names keyed by condition.
Copy elements as Blade components with PickCode
- Open the template in your browser. A local file, your Laravel dev server or a live demo all work.
- Pick a block. Press Alt Shift C and select the card, button or section you want as a component.
- Switch to Blade. Press Space, then 3. The output is an anonymous component with Tailwind classes and $attributes->merge on the root.
- Save it as a component file. Paste into resources/views/components/name.blade.php. Repeated items (3 or more) come out as @foreach over data in @props.
- Use it. Render it with <x-name /> and add classes where you use it.
Template CSS: keep it or move to Tailwind
Most HTML templates ship a big stylesheet. You can keep it in resources/css and load it with Vite, which is the quickest path. If your Laravel app uses Tailwind (the default in new Laravel starter kits), converting each component's styles to utilities as you go keeps the styling inside the component file. See HTML to Tailwind.
Questions
Anonymous or class-based components?
Anonymous components (a single Blade file) are enough for markup with props and slots. Add a class only when the component needs logic or injected services.
Where do anonymous component files go?
In resources/views/components. A file at components/forms/input.blade.php renders as <x-forms.input />.
Why use $attributes->merge instead of a class prop?
It lets callers add classes and any other HTML attribute without you declaring each one, and keeps the default classes.
Does this work with Livewire?
Yes. Livewire views are Blade, so the same components can be used inside them, and wire: attributes pass through $attributes.