0x55aa
← Back to Blog

Laravel Blade Components: Stop Copy-Pasting HTML Like a Caveman šŸŽØ

•6 min read

Laravel Blade Components: Stop Copy-Pasting HTML Like a Caveman šŸŽØ

Ever copied the same button HTML across 15 different views and then realized you need to change the styling? Yeah, me too. Let's fix that!

Blade Components are like Legos for your UI - build once, use everywhere, and look like a genius doing it.

What's the Big Deal? šŸ¤”

Remember when you had to copy this everywhere?

<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
    {{ $text }}
</button>

And then your designer said "actually, make all buttons green"? Time to update 47 files! 😭

With Blade Components: Change it once, boom - it's updated everywhere. That's not magic, that's just smart coding!

The Basics: Your First Component šŸš€

Create a component with one artisan command:

php artisan make:component Button

This creates two things:

  1. app/View/Components/Button.php (the brains)
  2. resources/views/components/button.blade.php (the looks)

The component class:

class Button extends Component
{
    public function __construct(
        public string $type = 'primary',
        public string $size = 'md'
    ) {}

    public function render()
    {
        return view('components.button');
    }
}

The component view:

<button
    {{ $attributes->merge([
        'class' => 'font-bold py-2 px-4 rounded ' . $this->getButtonClasses()
    ]) }}
>
    {{ $slot }}
</button>

Use it anywhere:

<x-button type="primary">Click Me!</x-button>
<x-button type="danger" size="lg">Delete Everything</x-button>

One button to rule them all! šŸ’

The Magic $attributes Object ✨

$attributes is like a Swiss Army knife for components. It passes everything you didn't explicitly define:

<x-button
    id="submit-btn"
    data-user="{{ $user->id }}"
    @click="handleClick"
>
    Submit
</x-button>

All those attributes automatically get added to your component! No prop drilling, no hassle.

Pro tip: Use $attributes->merge() to add default classes while allowing overrides:

<div {{ $attributes->merge(['class' => 'card shadow-lg']) }}>
    {{ $slot }}
</div>

Now you can do: <x-card class="bg-red-500"> and it becomes class="card shadow-lg bg-red-500". Beautiful! šŸ˜

Slots: Not Just for Gambling šŸŽ°

Slots let you pass complex HTML into components. Think of them as "fill in the blank" for your UI.

The component:

<!-- resources/views/components/alert.blade.php -->
<div class="alert alert-{{ $type }}">
    <div class="alert-icon">
        {{ $icon }}
    </div>
    <div class="alert-content">
        {{ $slot }}
    </div>
</div>

Using it:

<x-alert type="success">
    <x-slot:icon>
        āœ…
    </x-slot:icon>

    Your profile was updated successfully!
</x-alert>

Multiple slots = Maximum flexibility! It's like building with Legos, but for HTML!

Anonymous Components: For When You're Lazy (In a Good Way) šŸ’¤

Don't need a class? Use anonymous components! Just create the view file:

# Create: resources/views/components/card.blade.php
<div {{ $attributes->merge(['class' => 'rounded-lg shadow-lg p-6 bg-white']) }}>
    @if(isset($title))
        <h3 class="text-xl font-bold mb-4">{{ $title }}</h3>
    @endif

    {{ $slot }}
</div>

Use it:

<x-card>
    <x-slot:title>Hello World</x-slot:title>
    This is so much cleaner than div soup!
</x-card>

No class needed. Pure simplicity. 🧘

Real-World Example: The Dropdown šŸ“‹

Let's build something useful - a reusable dropdown component!

Component class:

class Dropdown extends Component
{
    public function __construct(
        public string $trigger = 'Options',
        public string $align = 'right'
    ) {}
}

Component view:

<div x-data="{ open: false }" class="relative">
    <button @click="open = !open" {{ $attributes }}>
        {{ $trigger }}
    </button>

    <div
        x-show="open"
        @click.away="open = false"
        class="absolute {{ $align }}-0 mt-2 w-48 bg-white rounded-lg shadow-xl"
    >
        {{ $slot }}
    </div>
</div>

Usage:

<x-dropdown>
    <x-slot:trigger>
        <span>āš™ļø Settings</span>
    </x-slot:trigger>

    <a href="/profile">Profile</a>
    <a href="/settings">Settings</a>
    <form method="POST" action="/logout">
        <button type="submit">Logout</button>
    </form>
</x-dropdown>

Build once, use everywhere. Change once, update everywhere. That's the dream! 🌟

Component Props with Type Hinting šŸŽÆ

Make your components bulletproof with type hints:

class UserCard extends Component
{
    public function __construct(
        public User $user,
        public bool $showEmail = false,
        public ?string $badge = null
    ) {}
}

Use it:

<x-user-card :user="$user" :show-email="true" badge="Admin" />

Notice: :user="$user" passes the variable, badge="Admin" passes the string. Laravel is smart enough to know the difference!

Bonus Tips šŸŽ

1. Component methods are accessible in views:

class Alert extends Component
{
    public function getIconForType(): string
    {
        return match($this->type) {
            'success' => 'āœ…',
            'error' => 'āŒ',
            'warning' => 'āš ļø',
            default => 'ā„¹ļø'
        };
    }
}

// In your view:
<span>{{ $this->getIconForType() }}</span>

2. Use @props in anonymous components:

@props(['type' => 'info', 'dismissible' => false])

<div class="alert-{{ $type }}">
    {{ $slot }}
    @if($dismissible)
        <button @click="$el.parentElement.remove()">Ɨ</button>
    @endif
</div>

3. Nest components like a boss:

<x-card>
    <x-slot:header>
        <x-heading>Dashboard</x-heading>
    </x-slot:header>

    <x-stats-grid :stats="$stats" />

    <x-slot:footer>
        <x-button>Refresh</x-button>
    </x-slot:footer>
</x-card>

4. Dynamic components:

<x-dynamic-component :component="$componentName" :user="$user" />

Perfect for building admin panels or dashboards!

When to Use Components 🤷

DO use components for:

  • Buttons, badges, alerts (anything you use 3+ times)
  • Navigation bars, footers, sidebars
  • Form inputs with labels and validation
  • Cards, modals, tooltips
  • Anything you're copy-pasting

DON'T use components for:

  • One-off UI elements
  • Simple divs with one class
  • Things that are actually unique

Rule of thumb: If you're copying it more than twice, componentize it!

Real Talk šŸ’¬

Q: "Aren't components slower than plain HTML?"

A: Not really! Laravel compiles them to PHP. The overhead is negligible. Your unoptimized database queries are way slower (we've all been there).

Q: "Should I component-ize everything?"

A: No! Don't create <x-div> or <x-span>. Use components for meaningful, reusable pieces. If it saves you time, do it. If it's over-engineering, don't.

Q: "Can I use Alpine.js/Vue/React with components?"

A: Absolutely! Components are just HTML wrappers. Mix and match as you please!

The Component Mindset Shift 🧠

Think of your UI as a library of building blocks:

Before Components:

  • Copy/paste HTML everywhere
  • Fix bugs in 20 files
  • Inconsistent styling
  • Maintenance nightmare

After Components:

  • Build once, reuse everywhere
  • Fix bugs in one place
  • Consistent UI automatically
  • Maintenance dream

Your future self will thank you! šŸ™

The Checklist āœ…

Start building your component library:

  • Create a Button component (most used!)
  • Build an Alert component with slots
  • Make a reusable Card component
  • Extract your form inputs into components
  • Build a Modal component
  • Componentize your navigation

One component at a time, you'll build a UI library that makes development feel like magic!

The Bottom Line

Blade Components are Laravel's answer to "DRY" (Don't Repeat Yourself). They're:

  • āœ… Easy to create
  • āœ… Powerful and flexible
  • āœ… Maintainable
  • āœ… Testable
  • āœ… Make you look like a senior dev

Stop treating HTML like it's 1999. Use components, stay DRY, and ship features faster!


Want to level up your Laravel game? Connect with me on LinkedIn - I share tips like this all the time!

Enjoying these posts? Star the repo on GitHub and watch for more Laravel goodies!

Now go build beautiful, reusable components! šŸŽØāœØ