How to create a Django form in 2mins using Alpine.js 🏔️

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 \<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 working with Photon Designer

Let's get visual.

Do you want to create beautiful django frontends effortlessly?
Click below to book your spot on our early access mailing list (as well as early adopter prices).