Mejorar la experiencia de usuario en formularios es una práctica esencial en cualquier aplicación moderna. En Laravel 12, una de las funcionalidades más solicitadas en formularios de login, registro o cambio de contraseña es el botón para mostrar u ocultar la contraseña.
En este tutorial aprenderás paso a paso cómo implementar un botón profesional para mostrar/ocultar contraseña usando:
- Blade
- Alpine.js
- Buenas prácticas de seguridad
- Componente reutilizable
Todo optimizado para proyectos modernos en Laravel 12.

¿Por qué usar Alpine.js en Laravel 12?
Laravel 12 se integra perfectamente con Alpine.js, especialmente si utilizas:
- Laravel Breeze
- Laravel Jetstream
- Livewire
- Componentes Blade personalizados
Alpine.js permite manipular el DOM de forma reactiva sin necesidad de escribir JavaScript complejo. Es ligero, moderno y fácil de mantener.
Ventajas:
- Código limpio
- Sin dependencias pesadas
- Fácil integración en Blade
- Ideal para componentes reutilizables
Implementación básica con Blade y Alpine.js
Comencemos con la versión más sencilla y funcional.
Estructura del input password
<div x-data="{ show: false }" class="mb-3">
<label for="password" class="form-label">Contraseña</label>
<div style="position: relative;">
<input
:type="show ? 'text' : 'password'"
name="password"
id="password"
class="form-control"
autocomplete="current-password"
>
<button type="button" @click="show = !show"
style="position:absolute; right:10px; top:50%; transform:translateY(-50%); border:none; background:none;">
<span x-text="show ? 'Ocultar' : 'Mostrar'"></span>
</button>
</div>
</div>¿Cómo funciona?
x-data="{ show: false }"crea una variable reactiva.:type="show ? 'text' : 'password'"cambia dinámicamente el tipo del input.@click="show = !show"alterna el estado.x-textcambia el texto del botón.
Resultado: botón funcional sin JavaScript adicional.
Mejorando la interfaz con íconos
Una interfaz profesional suele usar íconos en lugar de texto.
Ejemplo con íconos dinámicos
<div x-data="{ show: false }" class="mb-3">
<label>Contraseña</label>
<div style="position: relative;">
<input
:type="show ? 'text' : 'password'"
name="password"
class="form-control">
<button
type="button"
@click="show = !show"
style="position:absolute; right:10px; top:50%; transform:translateY(-50%); border:none; background:none;">
<span x-show="!show">👁</span>
<span x-show="show">🙈</span>
</button>
</div>
</div>Ahora el usuario verá:
- 👁 cuando la contraseña esté oculta
- 🙈 cuando esté visible
Esto mejora significativamente la experiencia en dispositivos móviles.
Crear un componente Blade reutilizable (Solución profesional)
Si trabajas en sistemas grandes, repetir código no es buena práctica. Lo ideal es crear un componente Blade.
Paso 1: Crear el componente
php artisan make:component PasswordInputLaravel generará:
app/View/Components/PasswordInput.php
resources/views/components/password-input.blade.phpPaso 2: Código del componente
Archivo:
resources/views/components/password-input.blade.php
<div x-data="{ show: false }" class="mb-3">
<label>{{ $label ?? 'Contraseña' }}</label>
<div style="position: relative;">
<input
:type="show ? 'text' : 'password'"
name="{{ $name }}"
{{ $attributes->merge(['class' => 'form-control']) }}>
<button
type="button"
@click="show = !show"
style="position:absolute; right:10px; top:50%; transform:translateY(-50%); border:none; background:none;">
<span x-show="!show">👁</span>
<span x-show="show">🙈</span>
</button>
</div>
</div>Paso 3: Usarlo en cualquier formulario
<x-password-input name="password" label="Contraseña" required />Ventajas:
- Código reutilizable
- Más limpio
- Escalable
- Ideal para sistemas empresariales
Validación segura en Laravel 12
Mostrar la contraseña en el frontend no afecta la seguridad del backend.
Siempre debes validar correctamente:
$request->validate([
'password' => ['required', 'min:8']
]);Y almacenar con:
use Illuminate\Support\Facades\Hash;
$user->password = Hash::make($request->password);Recuerda:
- Nunca guardes contraseñas en texto plano.
- Usa siempre
Hash::make(). - Configura correctamente autocomplete.
Problemas comunes y soluciones
Problema 1: Alpine.js no funciona
Solución: asegúrate de tener Alpine cargado en tu layout principal:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>Si usas Vite:
import Alpine from 'alpinejs'
window.Alpine = Alpine
Alpine.start()Problema 2: El botón envía el formulario
Solución: asegúrate de que el botón tenga:
type="button"No uses type=»submit».
Problema 3: El ícono se desalineado
Solución CSS recomendada:
.password-wrapper {
position: relative;
}
.password-wrapper button {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
}Buenas prácticas UX para formularios en Laravel
- Mantener altura uniforme en todos los inputs.
- Usar iconos claros.
- No saturar el diseño.
- Compatible con móviles.
- Agregar aria-label para accesibilidad.
Ejemplo accesible:
<button type="button" @click="show = !show" aria-label="Mostrar u ocultar contraseña">¿Es seguro mostrar la contraseña?
Sí. La funcionalidad solo cambia el tipo del input en el navegador.
No altera el hash, ni la validación, ni la seguridad del servidor.
La verdadera seguridad depende de:
- Hash correcto
- Validación backend
- HTTPS activo
- Protección CSRF
Conclusión
Implementar un botón para mostrar/ocultar contraseña en Laravel 12 con Blade y Alpine.js es:
- Fácil
- Profesional
- Seguro
- Escalable
Si desarrollas sistemas administrativos, eCommerce o plataformas SaaS, este pequeño detalle mejora notablemente la experiencia de usuario.
La mejor práctica en proyectos reales es crear un componente Blade reutilizable y mantener el código limpio.
