DEV Community

HTTP
HTTP

Posted on

2

Django: Toggle Password Visibility With a Button Using Crispy Forms

In this tutorial you will learn how to create a button attached to a password input form that toggles the visibility of your password.

django version==4.2.2

example-GIF

Start by installing the following packages:

pip install django-crispy-forms
Enter fullscreen mode Exit fullscreen mode
pip install crispy-bootstrap5
Enter fullscreen mode Exit fullscreen mode

Make sure to include them both in installed apps, in settings.py:

INSTALLED_APPS = [
    # ...
    'crispy_forms',
    'crispy_bootstrap5'
]
Enter fullscreen mode Exit fullscreen mode

And define the CRISPY TEMPLATES PACK in settings.py:

CRISPY_ALLOWED_TEMPLATE_PACKS = 'bootstrap5'
CRISPY_TEMPLATE_PACK = 'bootstrap5'
Enter fullscreen mode Exit fullscreen mode

Add the following CDN links to your template:

<!-- Bootstrap CDN -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<!-- Bootstrap icons CDN -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">

Enter fullscreen mode Exit fullscreen mode

In forms.py (in the same directory as views.py), add the following form class:

from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm

from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Div
from crispy_forms.bootstrap import FieldWithButtons, StrictButton

class CreateUserForm(UserCreationForm):
    helper = FormHelper()
    helper.form_tag = False
    helper.layout = Layout(
        Div(
            Div('username', css_class='col-12'),
            Div(FieldWithButtons('password1', StrictButton('<i class="bi bi-eye"></i>', type='button', css_class='btn btn-outline-secondary', id='password1Button')), css_class='col-6'
                ),
            Div(FieldWithButtons('password2', StrictButton('<i class="bi bi-eye"></i>', type='button', css_class='btn btn-outline-secondary', id='password2Button')), css_class='col-6'
                ),
            css_class='row'
        )
    )

    class Meta:
        model = get_user_model()
        fields = ['username', 'password1', 'password2']
Enter fullscreen mode Exit fullscreen mode

In views.py, create the SignupView, if you use Class Based Views:

from django.urls import reverse_lazy
from django.views.generic import CreateView
from .forms import CreateUserForm

class SignUpView(CreateView):
    template_name = 'signup.html'
    form_class = CreateUserForm
    success_url = reverse_lazy('')
Enter fullscreen mode Exit fullscreen mode

If you use Function Based Views, add the following code to views.py:

from .forms import CreateUserForm
from django.shortcuts import render

def sign_up(request):
    if request.method == 'POST':
        form = CreateUserForm(request.POST)
        if form.is_valid():
            form.save()
    else:
        form = CreateUserForm()
    return render(request, 'signup.html', {'form': form})
Enter fullscreen mode Exit fullscreen mode

Add the following html code to signup.html:

{% load crispy_forms_tags %}

<script>
  document.addEventListener('DOMContentLoaded', function () {
    for (i of [1, 2]) {
      const togglePassword = document.querySelector(`#password${i}Button`);
      const password = document.querySelector(`#id_password${i}`);

      togglePassword.addEventListener('click', function (e) {

        const type = password.getAttribute('type') === 'password' ? 'text' : 'password';
        password.setAttribute('type', type);

        if (this.firstChild.classList.contains('bi-eye-slash')) {
          this.firstChild.classList.remove('bi-eye-slash')
          this.firstChild.classList.add('bi-eye');
        }
        else {
          this.firstChild.classList.remove('bi-eye');
          this.firstChild.classList.add('bi-eye-slash');
        }
      });
    }
  });
</script>

<form method="post">
    {% csrf_token %}
    {% crispy form %}

</form>
Enter fullscreen mode Exit fullscreen mode

Make sure you do include

{% crispy form %}

instead of the usual

{{ form|crispy }}

This ensures that the modifications to the form made in forms.py actually see the daylight.

Finally, add the URL of the view to urls.py:

from django.urls import path
from . import views

urlpatterns = [
    # Class Based Views
    path('signup/', views.SignUpView.as_view(), name='signup'),
    # Function Based Views (Choose one of the two)
    path('signup/', views.sign_up, name='signup')
]
Enter fullscreen mode Exit fullscreen mode

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay