Configuration

First prepare your Django templates to use a supported HTML structure, and then initialise the formsets using the configuration options to customise how your formset works.

HTML Structure

By default, django-fancy-formset would like you to construct your formset in a specific way:

<div data-formset="{{ formset.prefix }}">   {# Formset container to target #}
  {{ formset.management_form }}             {# Add the management form #}
  <fieldset style="display: none">          {# Add and hide the empty form #}
    {{ formset.empty_form.as_p }}
  </fieldset>
  {% for form in formset %}
    <fieldset>                              {# Each formset form has a container #}
    {{ form.as_p }}                         {# Actual form layout doesn't matter #}
    </fieldset>
  {% endfor %}
</div>
  • set a data-formset="prefix" attribute on the formset container so it can be found by init()

  • put each form in its own fieldset container, as direct children of the formset container

  • add a formset.empty_form in a container as one of the forms, to act as a template

  • remember to add the formset.management_form somewhere

It doesn’t matter what your formset forms look like, just as long as they’re in a container.

If you want to construct your formset differently, you can extend the classes to override the defaults.

Note

All inline style="..." attributes are removed from the empty form container when it is copied, so you can set style="display: none" on the empty form to hide it.

If you want to add styles to the form container, you should use CSS classes. If you want to hide it in a different way, see options, Events and Extending functionality.

Styling your formset

There is a default stylesheet available which:

  • Adds some basic fieldset styling to make your form clearer to use

  • Styles the delete button to hide the form being deleted

  • Styles the add button

This is available as formset.min.css if you want to use it directly, or formset.css (or src/formset.scss in github) if you want to use it as a starting point.

Initialise the formsets

If your formsets follow the expected HTML structure above, you can initialise all of the formsets on a page at once by calling init() with no arguments.

For example, you can do this in the HTML from the bottom of your body tag:

  <script>
    formset.init();
  </script>
</body>

or once the DOM is ready from your JavaScript bundle:

import { init } from 'django-fancy-formset';

document.addEventListener('DOMContentLoaded', e => {
  init();
});

You can also customise which formsets are initialised and how they work by specifying options and targets:

formset.init(options, targets);

Specifying options

You can configure the formsets using an options object - for example:

formset.init(
  {
    formSelector: 'div.form',
    templateSelector: 'div.form.form-template',
    allowDeleteAtMin: true
  }
);
options

type: object

options.formsetSelector

Selector used to target the root formset element. If no target is passed to init(), the target defaults to querySelectorAll(options.formsetSelector).

Default: "[data-formset]" - select all DOM elements with a data-formset attribute

options.formsetClass

type: Formset

JavaScript class to use for the formset object. Only needed if subclassing the standard Formset class.

Default: Formset

options.prefix

Explicit prefix for the formset

By default the prefix will be picked up from an attribute on the root formset element (the attribute options.prefixAttr, which defaults to "data-formset"). You only need to set prefix if you don’t want to add the attribute to the root formset element.

If set, any value in prefixAttr will be ignored.

Default: null - prefix will be collected using prefixAttr

options.prefixAttr

If prefix is not set, look for the formset prefix on this attribute of the root formset element.

Default: "data-formset" - the value of the "data-formset" attribute

options.formSelector

Selector to find all form containers, relative to the formset root element.

Default: ":scope > fieldset" - all direct fieldset children of the formset root

options.formClass

type: Form

JavaScript class to use when creating a form object. Only needed if subclassing the standard Form class.

Default: Form

options.pkFieldName

Name of the primary key field for the form

Default: "id"

options.formsetActiveCss

CSS class name to add to an active formset root element

Useful for restyling interactive formsets with progressive enhancement

Default: "formset-active"

options.formAddedCss

CSS class name to add to a form added by the “Add” button

Defaukt: "added"

options.formDeletedCss

CSS class name to add to a form marked for deletion

Default: "deleted"

options.addButtonLabel

Label for the formset’s add <button>, appended to the formset root

Default: "Add"

options.addButtonCss

CSS class name for the formset’s add <button>

Default: "formset-add"

options.deleteConClosest

Selector used to find the field container ancestor of the delete form field

The delete element for a form will be <input name="...-DELETE">. We find this element within the form root as deleteEl, then find its container with deleteEl.closest(options.deleteConClosest)

In default form layouts, this will be:

  • as_p: <p> ... <input name="...-DELETE"> ... </p>

  • as_div: <div> ... <input name="...-DELETE"> ... </div>

  • as_list: <li> ... <input name="...-DELETE"> ... </li>

  • as_table: <tr> ... <input name="...-DELETE"> ... </tr>

Default: "p, div, tr, li"

options.deleteConCss

CSS class to add to the form field’s delete container

This is a convenience to simplify restyling the delete button.

Default: "formset-delete"

options.formsetAtMinCss

CSS class name for the formset root when it has the minimum number of active forms

Default: "formset-at-min"

options.allowDeleteAtMin

type: bool

Control if forms can be deleted when the formset has the minimum number of forms

Only applies to the delete checkbox; does not affect empty form removal at startup

Default: false

options.formsetAtMaxCss

CSS class name for the formset root when it has the maximum number of active forms

Default: "formset-at-max"

options.allowAddAtMax

type: bool

Control if forms can be added when the formset has the maximum number of forms

Default: false

Specifying targets

If not all of your formsets on the page need to be initialised, or if they need different options, you can specify a target as the second argument.

The target can be a selector, or the results of querySelectorAll:

formset.init({}, 'fieldset.formset')
formset.init({}, document.querySelectorAll('fieldset.formset'))