Skip to content

5. Vistas con Blade en Laravel

Blade es el motor de plantillas incluido con Laravel. A diferencia de otros motores de plantillas PHP, Blade no te restringe de usar código PHP plano en tus vistas. De hecho, todas las vistas Blade se compilan en código PHP plano y se almacenan en caché hasta que sean modificadas, lo que significa que Blade añade esencialmente cero sobrecarga a tu aplicación.

Las vistas Blade utilizan la extensión de archivo

.blade.php
y se almacenan en el directorio
resources/views
.

Laravel proporciona varios comandos Artisan para crear vistas y componentes Blade rápidamente:

Aunque puedes crear archivos de vista manualmente, Laravel ofrece un comando para generarlas:

Terminal window
php artisan make:view nombre-vista

Esto creará un archivo

nombre-vista.blade.php
en el directorio
resources/views
.

Para crear una vista en un subdirectorio:

Terminal window
php artisan make:view carpeta.nombre-vista

Esto generará

resources/views/carpeta/nombre-vista.blade.php
.

Para crear un componente Blade de clase:

Terminal window
php artisan make:component NombreComponente

Este comando genera:

  • Una clase PHP en
    app/View/Components/NombreComponente.php
  • Una plantilla Blade en
    resources/views/components/nombre-componente.blade.php

Para crear un componente en un subdirectorio:

Terminal window
php artisan make:component Admin/AlertaAdmin

Esto generará el componente en

app/View/Components/Admin/AlertaAdmin.php
y la vista en
resources/views/components/admin/alerta-admin.blade.php
.

Si solo necesitas la plantilla sin la clase PHP:

Terminal window
php artisan make:component forms.input --view

Esto creará únicamente

resources/views/components/forms/input.blade.php
sin generar una clase PHP.

Para crear un componente que renderiza su contenido directamente desde el método render() sin una vista separada:

Terminal window
php artisan make:component Alert --inline

Esto generará solo la clase PHP con un método render() que devuelve una cadena HTML.

Blade proporciona una sintaxis limpia y elegante para trabajar con datos y estructuras de control en tus vistas. Vamos a explorar las directivas básicas de Blade.

Puedes mostrar datos pasados a tu vista Blade utilizando llaves dobles:

<!-- Mostrar una variable -->
{{ $variable }}
<!-- Mostrar el resultado de una función -->
{{ time() }}
<!-- Mostrar una variable con escape HTML desactivado (cuidado con XSS) -->
{!! $contenidoHtml !!}

Puedes añadir comentarios en tus plantillas Blade que no serán visibles en el HTML resultante:

{{-- Este comentario no aparecerá en el HTML --}}

Blade proporciona directivas convenientes para las estructuras de control comunes de PHP:

<!-- Directiva @if -->
@if($usuario->tipo === 'admin')
<p>Este usuario es administrador</p>
@elseif($usuario->tipo === 'editor')
<p>Este usuario es editor</p>
@else
<p>Este usuario es miembro regular</p>
@endif
<!-- Directiva @unless (inverso de @if) -->
@unless($usuarios->isEmpty())
<p>Hay usuarios disponibles</p>
@endunless
<!-- Directiva @isset -->
@isset($usuario)
<p>La variable usuario está definida</p>
@endisset
<!-- Directiva @empty -->
@empty($usuarios)
<p>No hay usuarios disponibles</p>
@endempty
<!-- Sintaxis estándar -->
{{ $esActivo ? 'Activo' : 'Inactivo' }}
<!-- Sintaxis abreviada -->
{{ $nombre ?? 'Invitado' }}
<!-- Bucle @foreach -->
@foreach($usuarios as $usuario)
<p>{{ $usuario->nombre }}</p>
@endforeach
<!-- Bucle @forelse (con caso vacío) -->
@forelse($usuarios as $usuario)
<p>{{ $usuario->nombre }}</p>
@empty
<p>No hay usuarios registrados</p>
@endforelse
<!-- Bucle @for -->
@for($i = 0; $i < 10; $i++)
<p>Valor: {{ $i }}</p>
@endfor
<!-- Bucle @while -->
@while($condicion)
<p>Bucle while en ejecución</p>
@endwhile

Dentro de un bucle

@foreach
o
@forelse
, puedes acceder a variables especiales:

@foreach($usuarios as $usuario)
@if($loop->first)
<p>Este es el primer usuario</p>
@endif
<p>{{ $loop->iteration }} / {{ $loop->count }}</p>
@if($loop->last)
<p>Este es el último usuario</p>
@endif
@endforeach

Las propiedades disponibles en la variable

$loop
son:

  • $loop->index
    : Índice del bucle actual (comienza en 0)
  • $loop->iteration
    : Iteración actual (comienza en 1)
  • $loop->remaining
    : Iteraciones restantes
  • $loop->count
    : Total de elementos
  • $loop->first
    : Si es la primera iteración
  • $loop->last
    : Si es la última iteración
  • $loop->even
    : Si es una iteración par
  • $loop->odd
    : Si es una iteración impar
  • $loop->depth
    : Nivel de anidamiento del bucle
  • $loop->parent
    : En bucles anidados, accede a la variable loop del padre

Blade proporciona directivas convenientes para verificar el estado de autenticación del usuario:

@auth
<!-- El usuario está autenticado -->
<p>Bienvenido, {{ Auth::user()->name }}</p>
@endauth
@guest
<!-- El usuario NO está autenticado -->
<p>Por favor inicia sesión</p>
@endguest
<!-- Verificar un guard específico -->
@auth('admin')
<!-- El usuario está autenticado en el guard 'admin' -->
@endauth

Puedes crear directivas personalizadas para verificar roles o permisos:

@can('editar', $post)
<a href="/posts/{{ $post->id }}/edit">Editar post</a>
@elsecan('ver', $post)
<a href="/posts/{{ $post->id }}">Ver post</a>
@endcan
@cannot('eliminar', $post)
<p>No tienes permiso para eliminar este post</p>
@endcannot

Blade proporciona un poderoso sistema de herencia de plantillas que te permite crear un diseño base que contiene todas las secciones comunes de tu sitio y definir “bloques” que las plantillas hijas pueden sobrescribir.

La directiva

@extends
se utiliza para especificar qué plantilla debe “extender” la vista actual:

resources/views/child.blade.php
@extends('layouts.app')

Esto indica que la vista actual extiende la plantilla ubicada en

resources/views/layouts/app.blade.php
.

Las directivas

@section
y
@yield
trabajan juntas para implementar la herencia de plantillas:

resources/views/layouts/app.blade.php
<!DOCTYPE html>
<html>
<head>
<title>@yield('title', 'Mi Sitio')</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/css/app.css">
@yield('styles')
</head>
<body>
<header>
@include('partials.nav')
</header>
<main>
@yield('content')
</main>
<footer>
@include('partials.footer')
</footer>
<script src="/js/app.js"></script>
@yield('scripts')
</body>
</html>

En este ejemplo:

  • @yield('title', 'Mi Sitio')
    define un espacio llamado “title” con un valor predeterminado “Mi Sitio”.
  • @section('title', 'Página de inicio')
    en la vista hija proporciona contenido para ese espacio.
  • Para secciones más grandes, usamos
    @section('content') ... @endsection
    .

La directiva

@show
es similar a
@endsection
, pero además de finalizar la sección, también la renderiza inmediatamente:

<!-- Layout -->
@section('sidebar')
<p>Contenido del sidebar principal</p>
@show
<!-- Vista hija -->
@section('sidebar')
@parent
<p>Contenido adicional del sidebar</p>
@endsection

La directiva

@parent
permite incluir el contenido de la sección padre dentro de una sección sobrescrita.

La directiva

@include
te permite incluir una vista Blade dentro de otra vista:

<!-- Incluir una vista simple -->
@include('partials.header')
<!-- Incluir una vista y pasar datos -->
@include('partials.error', ['mensaje' => 'Error en el formulario'])
<!-- Incluir una vista si existe -->
@includeIf('partials.sidebar', ['algunaVariable' => 'valor'])
<!-- Incluir una vista si una condición es verdadera -->
@includeWhen($usuario->esAdmin, 'partials.admin-panel')
<!-- Incluir una vista si una condición es falsa -->
@includeUnless($usuario->esAdmin, 'partials.user-panel')
<!-- Incluir la primera vista que exista de un array -->
@includeFirst(['custom.admin', 'admin'], ['algunaVariable' => 'valor'])

La directiva

@each
combina las funcionalidades de bucle e inclusión en una sola directiva:

<!-- Sintaxis: @each('vista.a.renderizar', $datos, 'variable', 'vista.si.vacio') -->
@each('partials.usuario', $usuarios, 'usuario', 'partials.no-usuarios')

Esto renderizará la vista

partials.usuario
para cada elemento en
$usuarios
, pasando cada elemento como la variable
$usuario
. Si
$usuarios
está vacío, se renderizará
partials.no-usuarios
.

Los componentes Blade proporcionan un enfoque modular para construir interfaces de usuario. Laravel ofrece dos tipos de componentes: componentes de clase y componentes anónimos.

Los componentes de clase son componentes Blade respaldados por una clase PHP. Para crear un componente de clase, puedes usar el comando Artisan:

Terminal window
php artisan make:component Alert

Este comando creará dos archivos:

  1. Una clase de componente en
    app/View/Components/Alert.php
  2. Una plantilla Blade en
    resources/views/components/alert.blade.php
<?php
namespace App\View\Components;
use Illuminate\View\Component;
class Alert extends Component
{
public $type;
public $message;
/**
* Crear una nueva instancia del componente.
*
* @param string $type
* @param string $message
* @return void
*/
public function __construct($type = 'info', $message = null)
{
$this->type = $type;
$this->message = $message;
}
/**
* Métodos adicionales disponibles en la plantilla.
*/
public function classes()
{
return ["alert", "alert-{$this->type}"];
}
/**
* Obtener la vista / contenido que representa el componente.
*
* @return \Illuminate\Contracts\View\View|\Closure|string
*/
public function render()
{
return view('components.alert');
}
}

Los componentes anónimos son componentes Blade que no tienen una clase asociada. Son útiles para componentes simples que no requieren lógica adicional:

resources/views/components/input.blade.php
<div class="form-group">
<label for="{{ $id }}" class="form-label">{{ $label }}</label>
<input
type="{{ $type ?? 'text' }}"
id="{{ $id }}"
name="{{ $name ?? $id }}"
value="{{ $value ?? old($name ?? $id) }}"
{{ $attributes->merge(['class' => 'form-control']) }}
>
@error($name ?? $id)
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>

Para usar este componente:

<x-input
id="email"
label="Correo electrónico"
type="email"
required
placeholder="ejemplo@correo.com"
/>

Los componentes Blade pueden recibir atributos y contenido a través de slots:

Puedes acceder a los atributos pasados al componente mediante la variable

$attributes
:

<!-- En el componente -->
<div {{ $attributes }}>
<!-- Contenido -->
</div>
<!-- Fusionar clases -->
<div {{ $attributes->merge(['class' => 'default-class']) }}>
<!-- Contenido -->
</div>
<!-- Filtrar atributos -->
<div {{ $attributes->filter(fn ($value, $key) => $key === 'class') }}>
<!-- Contenido -->
</div>

Los componentes pueden tener un slot principal y slots con nombre:

<!-- En el componente -->
<div class="card">
<div class="card-header">
{{ $header ?? 'Encabezado predeterminado' }}
</div>
<div class="card-body">
{{ $slot }}
</div>
<div class="card-footer">
{{ $footer ?? '' }}
</div>
</div>
<!-- Uso del componente -->
<x-card>
<x-slot:header>
Mi encabezado personalizado
</x-slot:header>
Contenido principal de la tarjeta
<x-slot:footer>
<button>Guardar</button>
</x-slot:footer>
</x-card>

Puedes crear layouts utilizando componentes, lo que proporciona una alternativa moderna a

@extends
:

resources/views/components/layouts/app.blade.php
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title ?? 'Mi aplicación' }}</title>
<link rel="stylesheet" href="/css/app.css">
{{ $styles ?? '' }}
</head>
<body>
<header>
<x-navigation />
</header>
<main>
{{ $slot }}
</main>
<footer>
<x-footer />
</footer>
<script src="/js/app.js"></script>
{{ $scripts ?? '' }}
</body>
</html>

Puedes renderizar componentes dinámicamente utilizando una variable para el nombre del componente:

@php
$componentName = $tipo === 'admin' ? 'admin-panel' : 'user-panel';
@endphp
<x-dynamic-component :component="$componentName" :data="$data" />

Las stacks en Blade te permiten insertar contenido en secciones específicas de tus plantillas desde cualquier vista hija. Esto es especialmente útil para recursos como scripts o estilos CSS que necesitas incluir desde diferentes vistas pero quieres renderizarlos en un lugar específico de tu layout.

La directiva

@stack
define un lugar donde se renderizará el contenido “empujado” con
@push
:

resources/views/layouts/app.blade.php
<!DOCTYPE html>
<html>
<head>
<title>@yield('title')</title>
<link rel="stylesheet" href="/css/app.css">
@stack('styles')
</head>
<body>
<main>
@yield('content')
</main>
<script src="/js/app.js"></script>
@stack('scripts')
</body>
</html>

En este ejemplo, cada vista hija “empuja” sus propios estilos y scripts a las stacks definidas en el layout principal. Cuando se renderiza la vista, todo el contenido empujado a cada stack se incluirá en el orden en que fue empujado.

Si necesitas añadir contenido al principio de una stack en lugar de al final, puedes usar

@prepend
:

@prepend('scripts')
<script src="/js/first-script.js"></script>
@endprepend

Para asegurarte de que un bloque de código solo se incluya una vez, incluso si la vista que lo contiene se incluye múltiples veces, puedes usar

@once
:

@once
@push('scripts')
<script>
// Este script solo se incluirá una vez
console.log('Cargado una sola vez');
</script>
@endpush
@endonce

Inyección de servicios en vistas (@inject)

Section titled “Inyección de servicios en vistas (@inject)”

La directiva

@inject
te permite recuperar un servicio del contenedor de servicios de Laravel directamente en tu vista Blade. Esto puede ser útil cuando necesitas acceder a un servicio sin tener que pasarlo explícitamente desde tu controlador.

La sintaxis de

@inject
es la siguiente:

@inject('nombreVariable', 'NombreClaseServicio')

Donde:

  • nombreVariable
    es el nombre de la variable que contendrá la instancia del servicio en tu vista.
  • NombreClaseServicio
    es el nombre de la clase o el alias del servicio que quieres inyectar.

Supongamos que tienes un servicio

MenuService
que proporciona elementos de menú para tu aplicación:

<?php
namespace App\Services;
class MenuService
{
public function getMainMenu()
{
return [
['title' => 'Inicio', 'url' => '/'],
['title' => 'Productos', 'url' => '/productos'],
['title' => 'Servicios', 'url' => '/servicios'],
['title' => 'Contacto', 'url' => '/contacto'],
];
}
public function getUserMenu($user)
{
$menu = [
['title' => 'Mi perfil', 'url' => '/perfil'],
];
if ($user->isAdmin()) {
$menu[] = ['title' => 'Panel de administración', 'url' => '/admin'];
}
$menu[] = ['title' => 'Cerrar sesión', 'url' => '/logout'];
return $menu;
}
}

En general, es mejor pasar datos a las vistas desde los controladores cuando sea posible. Sin embargo,

@inject
puede ser útil para servicios que:

  • Son utilizados en múltiples vistas (como navegación, configuración, etc.)
  • No dependen del contexto específico de la solicitud actual
  • Son ligeros y no realizan operaciones pesadas

Una alternativa a

@inject
es crear un View Composer, que te permite adjuntar datos a una vista cada vez que se renderiza:

<?php
namespace AppProviders;
use AppServicesMenuService;
use IlluminateSupportFacadesView;
use IlluminateSupportServiceProvider;
class ViewServiceProvider extends ServiceProvider
{
public function boot()
{
// Compartir con todas las vistas
View::share('siteName', 'Mi Sitio Web');
// Compartir solo con vistas específicas
View::composer(
['layouts.app', 'partials.navigation'],
function ($view) {
$view->with('menu', app(MenuService::class));
}
);
}
}

Blade es un motor de plantillas potente y flexible que ofrece numerosas características para crear vistas dinámicas y reutilizables en Laravel. Desde la sintaxis básica hasta componentes avanzados, herencia de plantillas, stacks e inyección de servicios, Blade proporciona todas las herramientas necesarias para construir interfaces de usuario modernas y mantenibles.

Recuerda que las mejores prácticas incluyen:

  • Mantener las vistas simples y enfocadas en la presentación
  • Utilizar componentes para elementos de UI reutilizables
  • Aprovechar la herencia de plantillas para mantener un diseño consistente
  • Usar stacks para organizar recursos como scripts y estilos
  • Limitar el uso de
    @inject
    a casos específicos donde realmente sea necesario
🐝