Toggle Password Visibility inside Laravel Blade with Vue.js — inline-template

David Abiola
4 min readJun 27, 2021
Photo by Jason Dent on Unsplash

As a full-stack engineer, I’ve worked on several apps built on Laravel backend and Vue.js frontend, and sometimes it can be a bit of a hassle trying to get some simple things in place at the intersection of both stack ends. Luckily for us, Vue.js provides a sleek way to have the best of both worlds.

The Challenge

I have some logic like validation error/feedback handling being handled in Laravel’s templating engine — blade, but I also want to be able to easily add a reactive password visibility toggler with Vue.js, without needing to rewrite my blade error rendering codes, especially since I cannot use blade-specific syntaxes within a Vue.js component’s template. The Vue.js inline-template component attribute is built-in to help with these types of cases.

Take a look at an example component utilizing inline-template attribute:

// login.blade.php

...<div class="form-group">
<label for="password" class="form-label">{{ __('Password') }}</label>
<password-visibility inline-template>
<div class="input-group">
<input aria-label="Password" aria-describedby="password-addon" ref="password" id="password" type="password"
class="form-control @error('password') is-invalid @enderror" name="password"
required autocomplete="new-password" placeholder="********">
<span :title="!visible ? 'show password?' : 'hide password?'" @click="toggleVisibility"
class="input-group-text" id="password-addon"
style="border-left: none; border-top-left-radius: 0; border-bottom-left-radius: 0;">
<i class="fe" :class="[!visible ? 'fe-eye' : 'fe-eye-off']"></i>
</span>
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</password-visibility>
</div>
...

In the above snippet, by adding inline-template attribute to the <password-visibility>…</password-visibility> element, we’re able to combine the characteristic of both a traditional blade template and a reactive Vue.js component template without any issues. Blade handles its designated error-related logic and lets Vue.js conditionally manipulate the necessary attributes accessible from the component JS module; updating elements like the eye icon, ‘show password’ text, title attribute, and the password input element’s type attribute, reactively.

See a screenshot below for clearer formatting:

// PasswordVisibility.vue

Since our template was written in-line, we ended up with a slimmer than usual component:

<script>
export default {
data() {
return {
visible: false
}
},
methods: {
toggleVisibility() {
const input = this.$refs.password;
if (input.type === 'password') {
input.type = 'text';
this.visible = true;
} else if (input.type === 'text') {
input.type = 'password';
this.visible = false;
}
}
}
}
</script>

Nothing too complicated here — A data property that defaults to false and can be conditionally updated, and a method that conditionally sets the value of our input element’s type attribute.

Wiring up both ends

This bit may depend on how your project is set up. For me, I have a passwordVisibility.js file in my resources > js directory that looks like this:

import Vue from "vue";

import PasswordVisibility from '../components/PasswordVisibility';

new Vue({
el: 'password-visibility',
components: {
PasswordVisibility
}
});

Using Webpack, all the necessary modules are bundled up and published to the specified public directories, alongside other specified assets.

// webpack.mix.js

const mix = require('laravel-mix');

/*
|--------------------------------------------------------------------------
| Mix Asset Management
|--------------------------------------------------------------------------
|
| Mix provides a clean, fluent API for defining some Webpack build steps
| for your Laravel application. By default, we are compiling the Sass
| file for the application as well as bundling up all the JS files.
|
*/

mix.js('resources/js/app.js', 'public/js')
.vue()
.js('resources/js/scripts/passwordVisibility.js', 'public/js/scripts')
.sass('resources/sass/app.scss', 'public/css');

As highlighted above, a compiled version of passwordVisibility.js will be published to the ‘public/js/scripts’, where we can easily access and include it in our project, like so:

// below page @ login.blade.php
@section(
'scripts')
<script src="/js/scripts/passwordVisibility.js"></script>
@endsection

And assuming everything is wired up correctly, we should see things working as expected in the browser.

type=”password”
type=”text”
The Blade still cuts just fine as well!

Thanks for coming along, guys!

--

--

David Abiola

Human & software engineer. Interested in ()=> {[Arts, Education, Music, Science, Tech, AI, co-Humans]};