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>

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

Subscribe to my free newsletter

Get updates on AI, software, and business.