Tabs

There are two Layout classes for adding Tabs component to a form: TabPanel, which contains the list of fields and other LayoutObjects which form the contents of each panel and a parent Tabs which contains the list of panels.

from django import forms

from crispy_forms_gds.helper import FormHelper
from crispy_forms_gds.layout import HTML, Layout, Tabs, TabPanel


class TabsForm(forms.Form):
    def __init__(self, *args, **kwargs):
        super(TabsForm, self).__init__(*args, **kwargs)

        headings = ["Case manager", "Cases opened", "Cases closed"]
        past_day = [
            ["David Francis", "3", "0"],
            ["Paul Farmer", "1", "0"],
            ["Rita Patel", "2", "0"],
        ]
        past_week = [
            ["David Francis", "24", "18"],
            ["Paul Farmer", "16", "20"],
            ["Rita Patel", "24", "27"],
        ]
        past_month = [
            ["David Francis", "98", "95"],
            ["Paul Farmer", "122", "131"],
            ["Rita Patel", "126", "142"],
        ]
        past_year = [
            ["David Francis", "1380", "1472"],
            ["Paul Farmer", "1129", "1083"],
            ["Rita Patel", "1539", "1265"],
        ]

        self.helper = FormHelper()
        self.helper.layout = Layout(
            Tabs(
                TabPanel(
                    "Past day",
                    HTML.h1("Past day"),
                    HTML.table(headings, past_day)
                ),
                TabPanel(
                    "Past week",
                    HTML.h1("Past week"),
                    HTML.table(headings, past_week)
                ),
                TabPanel(
                    "Past month",
                    HTML.h1("Past month"),
                    HTML.table(headings, past_month),
                ),
                TabPanel(
                    "Past year",
                    HTML.h1("Past year"),
                    HTML.table(headings, past_year)
                ),
            )
        )

You can see this form live in the Demo site. Here we just copied the example from the GOV.UK Design System site so all the layout objects are chunks of HTML.

The first argument passed to each TabPanel is the title, followed by the list of fields or other layout objects that make up the contents. The Tabs object just contains the list of TabPanels.

When each tab is displayed the panel shrinks to fit the content. That’s not a a problem if the data is regular, as in the above example, or if the tabs are displayed on a separate page in a multi-page form. It might not make for a good visual experience if used on a large form however.

There is one complication. The name passed to the TabPanel is used to generate the id attribute on the <div> that is used to create the panel. That means if you have more than one set of tabs on a page with the same set of titles, clicking on one panel brings to the front all the panels with the same name. That is easily fixed however. Just set the css_id so you make the identifier for each panel unique:

HTML.h1("Past Week"),
Tabs(
    TabPanel(
        "Opened", HTML.h1("Opened"), HTML.table(headings, past_week_opened)
    ),
    TabPanel(
        "Closed", HTML.h1("Closed"), HTML.table(headings, past_week_closed)
    )
),
HTML.h1("Past Month"),
Tabs(
    TabPanel(
        "Opened", HTML.h1("Opened"), HTML.table(headings, past_month_opened),
        css_id="past-month-opened"
    ),
    TabPanel(
        "Closed", HTML.h1("Closed"), HTML.table(headings, past_month_closed),
        css_id="past-month-closed"
    ),
)