Skip to main content

Alpine.js variables in Django Admin forms

Project description

django-form-alpine

django-form-alpine integrates Alpine.js into Django forms declaratively — you write Alpine directives directly in your widget attrs, and the library resolves which surrounding DOM element each directive should land on.

A Django Admin preset is included out of the box, so you get zero-config support for all standard admin containers. You can also define your own resolvers to use the library in any Django form, outside of the admin.

Installation

pip install django-form-alpine

Add django_form_alpine to INSTALLED_APPS:

INSTALLED_APPS = [
    # ...
    "django_form_alpine",
    # ...
]

How it works

The library has two layers:

  • core.js — the engine. On DOMContentLoaded it reads window.DjangoFormAlpine.resolvers, iterates over all form inputs, and for each resolver it applies any matching prefixed attributes to the resolved container.
  • admin.js — the Django Admin preset. Registers built-in resolvers for all standard admin containers (.form-row, fieldset, .field-box, .inline-related, etc.) into window.DjangoFormAlpine unless you supply your own.

Two mixins are provided:

Mixin Loads Use when
FormAlpineMixin core.js + alpine.js Any Django form with custom resolvers
AdminAlpineMixin admin.js + core.js + alpine.js Django Admin (built-in resolvers included)

Quick start

Django Admin

Inherit from AdminAlpineMixin in your ModelAdmin or admin Form:

from django.contrib import admin
from django_form_alpine import AdminAlpineMixin
from .models import MyModel

@admin.register(MyModel)
class MyModelAdmin(AdminAlpineMixin, admin.ModelAdmin):
    pass

That's it — the admin preset resolvers are loaded automatically.

Any Django form

Use FormAlpineMixin and define your own resolvers (see Custom resolvers):

from django import forms
from django_form_alpine import FormAlpineMixin

class MyForm(FormAlpineMixin, forms.ModelForm):
    class Meta:
        model = MyModel
        fields = "__all__"

Features

Synchronize state with x-add-model-data

Add x-add-model-data to a widget to automatically register the field in the form's x-data and bind it with x-model:

class MyForm(forms.ModelForm):
    my_field = forms.CharField(
        widget=forms.TextInput(attrs={
            "x-add-model-data": "myFieldState"
        })
    )

This initializes myFieldState in the closest form[x-data] and sets x-model="myFieldState" on the input.

Prefixed directives

Apply Alpine.js directives to surrounding containers directly from widget attrs using the x-<resolver>-<directive> (or @<resolver>-<directive>) pattern.

Django Admin preset resolvers

Prefix Target container
form-row Closest .form-row
form-multiline Closest .form-multiline
form Closest form
fieldset Closest fieldset
field-box Closest .field-box (falls back to label.parentElement, then el.parentElement)
field-container Parent of the field box
label Field's label (inside .flex-container or .form-row)
errorlist .errorlist inside the field container
help .help inside the field container
inline-container tr.form-row or .inline-related
nonfield-errorlist .errorlist.nonfield in tabular or stacked inlines
option-label Closest label (for checkboxes and radios)

Example: show/hide a form row

class MyForm(forms.ModelForm):
    toggle = forms.BooleanField(
        widget=forms.CheckboxInput(attrs={
            "x-add-model-data": "showExtra"
        })
    )
    extra_field = forms.CharField(
        widget=forms.TextInput(attrs={
            "x-form-row-show": "showExtra"
        })
    )

Inline forms with __row_prefix__

Use __row_prefix__ to namespace Alpine state keys per inline row, so each row has its own independent state:

class MyInlineForm(AdminAlpineMixin, forms.ModelForm):  # or FormAlpineMixin with custom resolvers
    my_field = forms.CharField(
        widget=forms.TextInput(attrs={
            "x-add-model-data": "__row_prefix__myField",
            "x-field-box-show": "__row_prefix__otherField",
        })
    )

__row_prefix__ is resolved at runtime in this order:

  1. Container ID — ID of the closest tr.form-row or .inline-related, with dashes replaced by underscores (e.g. items_0). So __row_prefix__myFielditems_0_myField.
  2. Element name — parsed with a prefix-number pattern (e.g. items-0). The prefix is used as-is, preserving the dash.
  3. Empty string__row_prefix__ is simply removed if neither applies.

Custom resolvers

Use FormAlpineMixin and define your resolvers in a <script> tag before the form's scripts load:

<script>
  window.DjangoFormAlpine = {
    resolvers: {
      "my-section": (el) => el.closest(".my-section"),
      "my-label": (el) => el.closest(".my-label"),
    },
  };
</script>

Each resolver is a function (el) => HTMLElement | null where el is the form input element.

When you provide your own resolvers, the admin preset is not loaded. If you want both, set useAdminResolvers: true:

<script>
  window.DjangoFormAlpine = {
    useAdminResolvers: true,
    resolvers: {
      // Your custom resolver — merged on top of the admin ones
      "my-section": (el) => el.closest(".my-section"),
    },
  };
</script>

Configuration

To use a custom Alpine.js bundle instead of the one included with the package:

# settings.py
django_form_alpine_JS_PATH = "path/to/your/custom-alpine.js"

Changelog

See CHANGELOG.md for full release notes.

Contributing

See CONTRIBUTING.md

License

This project is licensed under the MIT License - see the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_form_alpine-0.0.2.tar.gz (32.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_form_alpine-0.0.2-py3-none-any.whl (29.2 kB view details)

Uploaded Python 3

File details

Details for the file django_form_alpine-0.0.2.tar.gz.

File metadata

  • Download URL: django_form_alpine-0.0.2.tar.gz
  • Upload date:
  • Size: 32.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for django_form_alpine-0.0.2.tar.gz
Algorithm Hash digest
SHA256 c6d0ec242a783b779628766156baa802a7a171fc9607ab8cc94f974f4381fbd2
MD5 ad790892b4701543a264b1f225d28d1b
BLAKE2b-256 d452df4df1496e595838330cc1ba7f8107a478c527fcf11adedc4860981b2972

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_form_alpine-0.0.2.tar.gz:

Publisher: release.yml on rodolvbg/django-form-alpine

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file django_form_alpine-0.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for django_form_alpine-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 9ba36c60d68d40c0c867749349458aa7ebdcbfb706d7320c9d639eccb5a70a09
MD5 6c60e3f58d7079e6f5dab04ab678d057
BLAKE2b-256 cbb713c3c1a37f62af27a74d70308acbe481748a6585865e151d96c4b258f889

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_form_alpine-0.0.2-py3-none-any.whl:

Publisher: release.yml on rodolvbg/django-form-alpine

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page