Skip to content

Form Submissionยค

Handle the entire form submission flow in a single file. From UI definition to server-side handler, without Django's Form class and without modifying urlpatterns.

  1. Define the form to submit in the HTML as a <form>.

  2. Add a View.post() method on the same component that defines the <form>, to define how to process the form data and return a partial HTML response.

  3. Obtain the URL to submit the form to and set it as the action attribute of the <form>. You don't need to go to your urlpatterns. The submission URL is dynamically generated using get_component_url().

The ContactFormComponent renders a simple form. After submission, it receives a partial HTML response and appends a "thank you" message below the form.

Form Submission example

Definitionยค

from typing import NamedTuple

from django.http import HttpRequest, HttpResponse

from django_components import Component, get_component_url, register, types

DESCRIPTION = "Handle the entire form submission flow in a single file and without Django's Form class."


@register("thank_you_message")
class ThankYouMessage(Component):
    class Kwargs(NamedTuple):
        name: str

    def get_template_data(self, args, kwargs: Kwargs, slots, context):
        return {"name": kwargs.name}

    template: types.django_html = """
        <div class="p-4 bg-green-100 border border-green-400 text-green-700 rounded-lg mt-4">
            <p>Thank you for your submission, {{ name }}!</p>
        </div>
    """


@register("contact_form")
class ContactFormComponent(Component):
    def get_template_data(self, args, kwargs: NamedTuple, slots, context):
        # Send the form data to the HTTP handlers of this component
        submit_url = get_component_url(ContactFormComponent)
        return {
            "submit_url": submit_url,
        }

    template: types.django_html = """
        <form hx-post="{{ submit_url }}" hx-target="#thank-you-container" hx-swap="innerHTML" class="space-y-4">
            {% csrf_token %}
            <div>
                <label for="name" class="block text-sm font-medium text-gray-700">
                    Name
                </label>
                <input
                    type="text"
                    name="name"
                    id="name"
                    class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500"
                >
            </div>
            <div>
                <button type="submit" class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
                    Submit
                </button>
            </div>
        </form>
        <div id="thank-you-container"></div>
    """  # noqa: E501

    class View:
        # Submit handler
        def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
            # Access the submitted data
            name = request.POST.get("name", "stranger")

            # Respond with the "thank you" message
            return ThankYouMessage.render_to_response(kwargs={"name": name})

Exampleยค

To see the component in action, you can set up a view and a URL pattern as shown below.

views.pyยค

from django.http import HttpRequest, HttpResponse

from django_components import Component, types


class FormSubmissionPage(Component):
    class Media:
        js = (
            "https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio,container-queries",
            "https://unpkg.com/htmx.org@2.0.7",
        )

    template: types.django_html = """
        {% load component_tags %}
        <html>
            <head>
                <title>Form Submission Example</title>
            </head>
            <body class="bg-gray-100 p-8" hx-boost="true">
                <div class="max-w-md mx-auto bg-white p-6 rounded-lg shadow-md">
                    <h1 class="text-2xl font-bold mb-4">
                        Self-Contained Form Component
                    </h1>
                    <p class="text-gray-600 mb-6">
                        This form's HTML and submission logic are all
                        handled within a single component file.
                    </p>
                    {% component "contact_form" / %}
                </div>
            </body>
        </html>
    """

    class View:
        def get(self, request: HttpRequest) -> HttpResponse:
            return FormSubmissionPage.render_to_response(request=request)

urls.pyยค

from django.urls import path

from examples.pages.form_submission import FormSubmissionPage

urlpatterns = [
    path("examples/form_submission", FormSubmissionPage.as_view(), name="form_submission"),
]