5.5 Creación de Vistas en Laravel y Uso de Blade

5.5.1 Introducción a Blade

Blade es el motor de plantillas que Laravel utiliza para construir las vistas de forma sencilla, ordenada y dinámica.

Ventajas principales de Blade

  • Permite reutilizar código con layouts y partials.
  • Tiene una sintaxis muy clara y elegante.
  • Es más rápido y organizado que escribir HTML puro.
  • Permite incluir recursos estáticos (árbol de carpetas, CSS, imágenes) fácilmente.

5.5.2 Creación de páginas HTML completas

Vamos a crear 4 páginas básicas en resources/views/landing/:

  • index.blade.php
  • about.blade.php
  • services.blade.php
  • contact.blade.php

Vamos a crear las páginas de ejemplo.

Página de inicio. index.blade.php

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Inicio</title>    
</head>
<body>
    <header>
        <h1>Bienvenido a nuestra web</h1>
    </header>

    <main>
        <p>Esta es la página de inicio.</p>
    </main>

    <footer>
        <p>Pie de página &copy; 2025</p>
    </footer>
</body>
</html>

Página de sobre nosotros. about.blade.php

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Sobre nosotros</title>
</head>
<body>
    <header>
        <h1>Sobre nosotros</h1>
    </header>

    <main>
        <p>Información sobre nuestra empresa.</p>
    </main>

    <footer>
        <p>Pie de página &copy; 2025</p>
    </footer>
</body>
</html>

Página de servicios. services.blade.php

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Servicios</title>
</head>
<body>
    <header>
        <h1>Servicios</h1>
    </header>

    <main>
        <p>Descripción de nuestros servicios.</p>
    </main>

    <footer>
        <p>Pie de página &copy; 2025</p>
    </footer>
</body>
</html>

Página de contacto. contact.blade.php

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Contacto</title>
</head>
<body>
    <header>
        <h1>Contacto</h1>
    </header>

    <main>
        <p>Formulario de contacto.</p>
    </main>

    <footer>
        <p>Pie de página &copy; 2025</p>
    </footer>
</body>
</html>

Ubicación de las vistas

Las vistas se encuentran en resources/views/landing/ y tienen la extensión .blade.php.

Estructura de carpetas

resources
└── views
    └── landing
        ├── index.blade.php
        ├── about.blade.php
        ├── services.blade.php
        └── contact.blade.php

Definir las rutas

En routes/web.php:

Route::view('/', 'landing.index')->name('home');
Route::view('/about', 'landing.about')->name('about');
Route::view('/services', 'landing.services')->name('services');
Route::view('/contact', 'landing.contact')->name('contact');

Importante: cada ruta tiene un nombre (home, about, etc.) que podemos usar para generar enlaces en lugar de escribir la URL directamente.

Probamos las rutas en el navegador, debemos ver las páginas HTML que hemos creado.

5.5.3 Creación de un Layout base

Podemos darnos cuenta que todas las páginas comparten más del 90% de su estructura HTML, y eso es poco eficiente. Cualquier cambio en la cabecera o pie de página, tendríamos que hacerlo en cada archivo. Para ello blade nos permite crear un layout base que contenga la estructura común de las páginas, y que pueda ser reutilizado en todas las vistas.

Los layouts son plantillas que contienen la estructura común de las páginas. En Laravel, los layouts se crean en la carpeta resources/views/landing/layouts/.

Ejemplo de layout base. landing.blade.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>
        @yield('title')
    </title>
</head>
<body>
    <header>
        @yield('header')"
    </header>

    <main>
        @yield('content')
    </main>

    <footer>
        <p>Pie de página &copy; 2025</p>
    </footer>
</body>
</html>
  • @yield('title') es un marcador de posición que se reemplazará por el contenido de la sección title en las vistas que extiendan este layout.
  • @yield('header') y @yield('content') son marcadores de posición para el contenido específico de cada vista.

Modificar las vistas para que extiendan el layout:

Ejemplo de vista que extiende el layout. index.blade.php

1
2
3
4
5
6
7
8
@extends('landing.layouts.landing')
@section('title', 'Inicio')
@section('header')
    <h1>Bienvenido a nuestra web</h1>
@endsection
@section('content')
    <p>Esta es la página de inicio.</p>
@endsection
Ahora hacemos lo mismo con las otras vistas:

Ejemplo de vista que extiende el layout. about.blade.php

1
2
3
4
5
6
7
8
@extends('landing.layouts.landing')
@section('title', 'Sobre nosotros')
@section('header')
    <h1>Sobre nosotros</h1>
@endsection
@section('content')
    <p>Información sobre nuestra empresa.</p>
@endsection

Ejemplo de vista que extiende el layout. services.blade.php

1
2
3
4
5
6
7
8
9
@extends('landing.layouts.landing')
@section('title', 'Servicios')
@section('header')
    <h1>Servicios</h1>
@endsection
@section('content')
    <p>Descripción de nuestros servicios.</p>
@endsection
@endsection

Ejemplo de vista que extiende el layout. contact.blade.php

1
2
3
4
5
6
7
8
9
@extends('landing.layouts.landing')
@section('title', 'Contacto')
@section('header')
    <h1>Contacto</h1>
@endsection
@section('content')
    <p>Formulario de contacto.</p>
@endsection
@endsection

Ventajas

Con los layouts, si quieres cambiar la estructura común (cabecera, pie de página), solo tienes que hacerlo en un único archivo.

5.5.4 Añadir un menú de navegación

En el layout, dentro del header, incluimos el menú de navegación:

Para ello, vamos amodificar la plantilla y vamos a añadir un menú de navegación:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<header>
    <nav>
        <ul>
            <li><a href="/">Inicio</a></li>
            <li><a href="/about">Sobre nosotros</a></li>
            <li><a href="/services">Servicios</a></li>
            <li><a href="/contact">Contacto</a></li>
        </ul>
    </nav>
    @yield('header')
</header>   

Este menú debe aparecer en todas las páginas. Si lo añadimos directamente al layout, no tenemos que repetirlo en cada vista. Podemos probarlo y puede funionar. Pero no es la mejor forma de hacerlo. Puede dar problemas, por ejemplo, si cambiamos la URL de una de las páginas, tendríamos que cambiarlo en todas las vistas. Para evitar esto, Laravel nos permite nombrar las rutas y usar esos nombres para generar los enlaces. En resumen, en lugar de escribir las URLs directamente, usamos el nombre de la ruta.

Recordatorio

Recuerda como nombramos las rutas, por ejemplo la ruta de inicio:

Route::view('/', 'landing.index')->name('home');

<nav>
    <ul>
        <li><a href="{{ route('home') }}">Inicio</a></li>
        <li><a href="{{ route('about') }}">Sobre nosotros</a></li>
        <li><a href="{{ route('services') }}">Servicios</a></li>
        <li><a href="{{ route('contact') }}">Contacto</a></li>
    </ul>
</nav>

Buenas prácticas

Es mejor usar {{ route('nombre') }} en lugar de URLs escritas a mano, así si la ruta cambia solo lo actualizas en un lugar.

5.5.5 Uso de Partials

Pero aún podemos mejorar más el código. El menú de navegación es un bloque de código que se repite en todas las páginas. Para evitar repetirlo, podemos usar partials.

En resources/views/_partials/, creamos un archivo nav.blade.php para el menú:

1
2
3
4
5
6
7
8
<nav>
    <ul>
        <li><a href="{{ route('home') }}">Inicio</a></li>
        <li><a href="{{ route('about') }}">Sobre nosotros</a></li>
        <li><a href="{{ route('services') }}">Servicios</a></li>
        <li><a href="{{ route('contact') }}">Contacto</a></li>
    </ul>
</nav>

Incluimos el partial en el layout:

@include('_partials.nav')

Ahora el layout queda así:

layout.blade.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>
        @yield('title')
    </title>
</head>
<body>
    <header>
        @include('_partials.nav')
        @yield('header')
    </header>

    <main>
        @yield('content')
    </main>

    <footer>
        <p>Pie de página &copy; 2025</p>
    </footer>
</body>
</html>

5.5.6 Uso de Componentes

Ahora vamos a mejorar el diseño de la página de servicios. En lugar de mostrar una lista de servicios Queremos mostrar tarjetas en la página de servicios.

Primero creamos tarjetas manualmente en services.blade.php, dentro de la sección content:

<div class="card">
    <h2>Servicio 1</h2>
    <p>Descripción breve del servicio 1.</p>
</div>

<div class="card">
    <h2>Servicio 2</h2>
    <p>Descripción breve del servicio 2.</p>
</div>

<div class="card">
    <h2>Servicio 3</h2>
    <p>Descripción breve del servicio 3.</p>
</div>

Esta sería una forma de hacerlo, pero no es la mejor. Si queremos añadir más servicios, tendríamos que repetir el mismo código HTML muchas veces. Para evitar esto blade nos permite crear componentes. Los componentes son bloques de código reutilizables que podemos usar en diferentes partes de la aplicación. En Laravel, los componentes se crean en la carpeta resources/views/_components/.

Luego, creamos un componente en resources/views/_components/card.blade.php:

<div class="card">
    <h2>{{ $title }}</h2>
    <p>{{ $content }}</p>
</div>

Y lo usamos así en services.blade.php:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@extends('landing.layouts.landing')
@section('title', 'Servicios')
@section('header')
    <h1>Servicios</h1>
@endsection
@section('content')
    @component('_components.card')
        @slot('title', 'Servicio 1');
        @slot('content')
            <p>Descripción breve del servicio 1.</p>
        @endslot
    @endcomponent
    @component('_components.card')
        @slot('title', 'Servicio 2');
        @slot('content')
            <p>Descripción breve del servicio 2.</p>
        @endslot
    @endcomponent
    @component('_components.card')
        @slot('title', 'Servicio 3');
        @slot('content')
            <p>Descripción breve del servicio 3.</p>
        @endslot
    @endcomponent
@endsection

Ventaja

Con componentes evitamos repetir el mismo código HTML muchas veces. Los componentes estan parametrizados y son reutilizables. Si queremos cambiar el diseño de la tarjeta, solo tenemos que hacerlo en un único archivo.

Componentes con atributos (x-component)

Veamos un ejemplo de un componente alert, que queremos usar para mostrar mensajes de alerta en la aplicación.

Ventajas:

  • Reutilizables: extraes UI repetida (alertas, botones, tarjetas).
  • API declarativa: props y slots claros; menos @include con arrays sueltos.
  • Encapsulan estilos/estructura y permiten fusionar atributos del padre.
  • Cero boilerplate: no creas clase; solo el .blade.php.
  • Composición: pueden anidar otros componentes <x-…>.

Convenciones y rutas

  • Archivo: resources/views/components/alert.blade.php → uso: <x-alert …/>
  • Subcarpetas: resources/views/components/forms/input.blade.php<x-forms.input …/>
  • Nombres con guion: toast-notice.blade.php<x-toast-notice …/>

Ejemplo — alert

Archivo: resources/views/components/alert.blade.php

alert.blade.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@props([
  'type' => 'info',     // info | success | warning | error
  'title' => null,
])

@php
  $base = 'rounded-md p-4 border';
  $map = [
    'info'    => 'bg-blue-50 text-blue-800 border-blue-200',
    'success' => 'bg-green-50 text-green-800 border-green-200',
    'warning' => 'bg-yellow-50 text-yellow-800 border-yellow-200',
    'error'   => 'bg-red-50 text-red-800 border-red-200',
  ];
@endphp

<div {{ $attributes->merge(['class' => "$base ".($map[$type] ?? $map['info'])]) }}>
  @isset($title)
    <div class="font-semibold mb-1">{{ $title }}</div>
  @endisset

  <div>{{ $slot }}</div>

  @isset($actions)
    <div class="mt-3">{{ $actions }}</div>
  @endisset
</div>

Uso:

<x-alert type="success" title="¡Listo!" class="mb-4">
  Los cambios se guardaron correctamente.
  <x-slot:actions>
    <a href="{{ route('items.index') }}" class="underline">Volver</a>
  </x-slot:actions>
</x-alert>

En este ejemplo, el componente alert tiene:

  • Props: type (tipo de alerta) y title (título opcional).
  • Slot principal: contenido de la alerta.
  • Slot con nombre actions: para botones o enlaces adicionales.

Patrones recomendados

  • Props con default en @props([...]); pasa valores dinámicos con dos puntos (:prop="…") para arrays/booleanos.
  • Clases condicionales con $attributes->class([...]); deduplica y fusiona con lo que envíe el padre.
  • Slots con nombre para zonas opcionales (header, footer, actions).
  • Evita lógica pesada (consultas, cálculos complejos). Mantén el componente “presentacional”.
  • Organiza por dominios: components/cards/…, components/forms/…, etc.
  • Comparado con @include: los componentes ofrecen API (props/slots) y fusión de atributos; @include solo pega HTML.

Continuamos con nuestro componente card

Modificamos el componente para que reciba las propiedades title y content:

Carpeta de componentes

En el caso de utilizar este tipo de componentes con la sintaxis <x-...>, Laravel busca los componentes en la carpeta resources/views/components/ por defecto. Si queremos usar otra carpeta, como _components, tenemos que registrarla en el AppServiceProvider.

Así que movemos el componente card.blade.php a resources/views/components/. Para evitar confusiones, es mejor usar la carpeta por defecto components.

Componente tarjeta con props. card.blade.php

1
2
3
4
5
6
7
8
9
@props(['title'])
<div class="card">
    @isset($title)
        <h2>{{ $title }}</h2>
    @endisset
    <div>
        <p>{{ $slot }}</p>
    </div>
</div>

Uso del componente tarjeta con <x-...> en services.blade.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@extends('landing.layouts.landing')
@section('title', 'Servicios')

@section('header')
    <h1>Servicios</h1>
@endsection

@section('content')
    <x-card title="Servicio 1">
        <p>Descripción breve del servicio 1.</p>
    </x-card>

    <x-card title="Servicio 2">
        <p>Descripción breve del servicio 2.</p>
    </x-card>

    <x-card title="Servicio 3">
        <p>Descripción breve del servicio 3.</p>
    </x-card>
@endsection

Cualquiera de las dos formas de usar el componente es válida. La segunda puede ser más limpia y clara, la primera es más sencilla para los que empiezan.

5.5.7 Incluir recursos estáticos (assets)

Incluir imágenes

Dentro de las tarjetas podemos añadir imágenes. Vamos a incluir una carpeta llamada assets dentro de public/ y dentro de esta carpeta creamos otra llamada images/. En esta carpeta vamos a incluir las imágenes que queramos usar en la aplicación. Copiamos una imagen de ejemplo en public/assets/images/ y la llamamos servicio.jpg.

Para añadir esta imagen de manera estática, usamos la función modificamos la tarjeta para incluir la imagen:

card.blade.php
1
2
3
4
5
<div class="card">
    <h2>{{ $title }}</h2>
    <img src="assets/images/servicios.ong" alt="Servicio">
    <p>{{ $content }}</p>
</div>

Pero con esto no es la mejor forma de hacerlo. Laravel tiene una función llamada asset() que nos permite generar la URL correcta para acceder a los recursos estáticos. Así que lo mejor es usarla:

<div class="card">
    <h2>{{ $title }}</h2>
    <img src="{{ asset('assets/images/servicios.png') }}" alt="Servicio" width="128px">
    <p>{{ $content }}</p>
</div>

Ubicación de las imágenes

Las imágenes deben estar en public/assets/images/ y la función asset() generará la URL correcta para acceder a ellas.

Incluir archivos CSS

Igual que hemos incluido las imágenes, podemos incluir archivos CSS. En la carpeta assets/css/ creamos un archivo style.css y lo enlazamos en el layout. Este archivo contendrá los estilos CSS que queramos aplicar a la aplicación.

layout.blade.php
<link rel="stylesheet" href="{{ asset('assets/css/style.css') }}">

El fichero puede tener el siguiente contenido de prueba:

style.css
h1 {
    color: darkblue;
}

Mejorar el diseño

Vamos a mejorar el diseño de las tarjetas y del menú de navegación. En el archivo style.css añadimos los siguientes estilos:

body {
    font-family: Arial, sans-serif;
    background-color: #f4f4f4;
}
h1 {
    color: darkblue;
}
h2 {
    color: #333;
}
p {
    color: #666;
}
.card {
    border: 1px solid #ccc;
    padding: 15px;
    margin: 10px;
    display: inline-block;
    width: 200px;
}

nav ul {
    display: flex;
    gap: 20px;
    list-style: none;
}

nav a {
    text-decoration: none;
    font-weight: bold;
}

5.5.8 Mejorar el diseño final

  • El menú será una barra horizontal.
  • Las tarjetas estarán alineadas lado a lado.
  • Cada tarjeta tendrá una imagen, título y descripción.

5.5.9 Conclusión

En este tema hemos aprendido:

  • Crear vistas en Blade.
  • Reutilizar layouts y partials.
  • Crear componentes para código repetitivo.
  • Incluir imágenes y CSS en el proyecto.

Con estas bases, estamos preparados para empezar a trabajar en proyectos más complejos usando Laravel y Blade de forma profesional.