How to create a Django form in 2mins using Alpine.js πŸ”οΈ

Published: July 27, 2023

There will be 4 steps. Each takes under 30 seconds.

We'll assume that you've already setup your Django project and created an app (I'll be using one I named sim ). You don't need to know anything about Alpine.js. I'll walk you through.

My video follows the guide below. Let's get to it!

1. Create template

  • create a folder called templates in your sim app
  • add an html file, we'll call it example.html
  • add your form html to the template
<div>
    <form>

        <div>
            <input name="email" type="email" />
            <input name="codename" type="text" />
            <input name="dress_color" type="color" />
            <button>
                Submit
            </button>
        </div>

        <div>
            <p>
                Successfully submitted form βœ…
            </p>
        </div>

        <div>
            <p>
                Error submitting your form ❌
            </p>
        </div>

    </form>
</div>

2. Add your Django view

  • Add your view, update your urls, and check that a template is rendered at the right url.
# views.py
from django.shortcuts import render
def example(request):
  return render(request, 'templates/example.html', context={})

def sample_post(request):
    data = request.POST
    print(f'{data = }')

    return JsonResponse({'status': 'success'})

# urls.py
from . import views
from django.urls import path

urlpatterns = [
    path('example', views.example, name='example'),
    path('sample-post/', views.sample_post, name='sample_post')
]

3. Add alpine js to template

  • Add Alpine js submit function
  • include the Django CSRF token
  • add your specific view url path
  • Add Alpine js syntax to control the form and manage the form's state
  • Add Alpine js loader script using a CDN (very fast and light)
<div>
    <form @submit.prevent="submit" x-data="{ status: 'normal', errors: {} }">
        <div x-show="status === 'normal'">
            <input name="email" type="email" />
            <input name="codename" type="text" />
            <input name="dress_color" type="color" />
            <button>
                Submit
            </button>
        </div>

        <div x-show="status === 'success'">
            <p>
                Successfully submitted form βœ…
            </p>
        </div>

        <div x-show="status === 'error'">
            <p>
                Error submitting your form ❌
            </p>
        </div>
    </form>
</div>

<script>
    function submit(event) {
        event.preventDefault();
        const formData = new FormData(event.target);

        // Update the `endpointUrl` to your specific url below.
        const endpointUrl = "/sample-post/"
        fetch(endpointUrl, {
                method: "post",
                body: formData,
                headers: {
                    'X-CSRFToken': '{{ csrf_token }}',
                },
            })
            .then(response => {
                this.status = response.ok ? 'success' : 'error';
                return response.json();
            })
            .then(data => {
                this.errors = data.errors || {};
            });
    }
</script>
<script defer="" src="https://cdn.jsdelivr.net/npm/alpinejs@3.12.3/dist/cdn.min.js">
</script>

4. Check that the view works as expected

  • Submit something.
  • Check in the Django run console that you see something like: data = {"email": ..., "codename": ..., "dress_color":...}

Bonus: Prevent form flickering due to alpine loading

  • Add x-cloak to the form. This will hide the form until it's finished loading (avoiding flicker).
  • Add x-cloak into the style tag (or add a similar line to any stylesheet that you are using)
<div>
    <form x-cloak @submit.prevent="submit" x-data="{ status: 'normal', errors: {} }">
        <div x-show="status === 'normal'">
            <input name="email" type="email" />
            <input name="codename" type="text" />
            <input name="dress_color" type="color" />
            <button>
                Submit
            </button>
        </div>

        <div x-show="status === 'success'">
            <p>
                Successfully submitted form βœ…
            </p>
        </div>

        <div x-show="status === 'error'">
            <p>
                Error submitting your form ❌
            </p>
        </div>
    </form>
</div>

<script>
    function submit(event) {
        event.preventDefault();
        const formData = new FormData(event.target);

        // Update the `endpointUrl` to your specific url below.
        const endpointUrl = "/sample-post/"
        fetch(endpointUrl, {
                method: "post",
                body: formData,
                headers: {
                    'X-CSRFToken': '{{ csrf_token }}',
                },
            })
            .then(response => {
                this.status = response.ok ? 'success' : 'error';
                return response.json();
            })
            .then(data => {
                this.errors = data.errors || {};
            });
    }
</script>
<script defer="" src="https://cdn.jsdelivr.net/npm/alpinejs@3.12.3/dist/cdn.min.js">
</script>

<style>
    [x-cloak] {
        display: none !important;
    }
</style>

Build this even faster with Photon Designer

Congratulations! Using Alpine.js is a neat, clean way to add simple JavaScript, including managing state, to your Django templates.

This is the style, using Alpine.js, that Photon Designer exports automatically.

I built Photon Designer to release new Django products much faster - so that you can start making money, and giving value to users, dramatically faster than before.
In this way, Photon Designer is like a beaver - helping you to build Django frontends faster, so your revenue stream flows earlier and faster.

A helpful beaver

Subscribe to my free newsletter

Get updates on AI, software, and business.