{% extends "brickwork/shell/app.html" %} {% comment %} A create/edit page: one form on a page. COPY THIS FILE into your project and edit it. It is not on the template loader path, so you cannot extend it (ADR-056). Beat Phase D journey: Form validate (icvoss/django-brickwork#544). This file IS the shared partial plus the 422 path: `{% partialdef form_region inline %}` keeps the full-page render and the HTMX invalid re-render on one block. Wire the view branches in docs/INTEGRATION.md section 4 (no-JS 200 full page, HTMX 422 + `#form_region`, success HX-Redirect). Do not invent a second form template. What your view must supply: form your own Django form (bound on POST) nav_items / nav_active as in list.html THE ONE RULE HERE: you own the
element, brickwork never emits it. That is not a limitation, it is the only sound arrangement: only your project knows its own action URL, and a template that wrapped your fields in its own would put your submit button outside it. So the , the csrf_token, and the submit all live together in this file, which you own. States: valid/invalid per field (bw_form renders the bound form's own errors inline); the 422 HTMX re-render path swaps this same region with inline errors, never a full page reload, when wired. Accessibility: inherits shell/app.html's skip link, sidebar/drawer nav and page-header region; every field renders through the standard forms/_field.html chrome (label/aria-describedby/error wiring); the cancel link is a real anchor, never a button pretending to navigate. Covered by the archetype harness's full gate sweep (render, axe WCAG 2.2 AA, no horizontal overflow, light/dark distinctness, skip-link first-tab-stop with JS disabled) at every W0.1 breakpoint, both themes; the underlying bw_form grid layout and its error states are additionally covered by axe.spec.mjs against form-*.html/form-errors-*.html (axe on the invalid state is the journey floor; keep that fixture green). Responsive: no breakpoint switch of its own; inherits shell/app.html's sidebar-to-drawer collapse at --bw-breakpoint-md (48rem). bw_form's own grid layout (when grid_columns is set) collapses to one column below --bw-breakpoint-sm (40rem), per that tag's own documentation. {% endcomment %} {% load brickwork_components brickwork_forms brickwork_nav %} {% block page_title %}New invoice - Northwind{% endblock %} {% block sidebar %}{% bw_nav nav_items nav_active %}{% endblock %} {% block sidebar_mobile %}{% bw_nav nav_items nav_active %}{% endblock %} {% block brand_wordmark %}Northwind{% endblock %} {% block page_header %} {% include "brickwork/components/_page_header.html" with title="New invoice" description="Raise an invoice against one of your accounts." %} {% endblock %} {% block content %}
{% comment %} Point the action at your own URL. {{ request.path }} posts back to this same page, which is the usual shape for a create/edit view: on success the view redirects, on failure it re-renders this page with the bound, invalid form and the errors appear inline automatically. bw_form renders form.visible_fields() generically, so it works with any form: ModelForm, plain Form, allauth's, your own. It also includes the non-field error region itself, so never include _form_errors.html a second time beside it. The hx-* attributes are progressive enhancement: without htmx the form is a plain POST and the no-JS floor still works (BR-BW-HTMX-001). With htmx, an invalid response must be 422 targeting this same region (see INTEGRATION.md). {% endcomment %} {% partialdef form_region inline %} {% csrf_token %} {% bw_form form %} {% comment %} The submit sits INSIDE the form, beside the fields. A cancel link beside it is an ordinary anchor, not a button: it navigates, it does not submit. {% endcomment %}
{% bw_button "Save invoice" type="submit" variant="primary" %} {% bw_button "Cancel" variant="ghost" href="/invoices/" %}
{% endpartialdef %}
{% endblock %}