Components / Foundations
Navigation
One declarative NavItem tree rendered as a sidebar, header, or capability rail with route-aware active state.
Live demonstration
Use it
Read the pinned package source
- Build immutable NavItem values in a site module, use lazy translations for labels, then filter them per request.
- Resolve active state from request.resolver_match. Do not use path-prefix matching.
- Put the same filtered tree in the desktop and mobile shell seams so every destination remains reachable.
{% load brickwork_nav %}
<nav aria-label="Component library">{% bw_nav items=nav_items active=nav_active %}</nav>
<nav aria-label="Header navigation">{% bw_nav_header items=nav_items active=nav_active %}</nav>
<nav aria-label="Capabilities">{% bw_nav_rail items=nav_items active=nav_active density=rail_density %}</nav>
Python context
from brickwork.models import NavContext, NavItem
from brickwork.services.navigation import resolve_active_item, visible_items
items = (
NavItem(key="components", label="Components", url_name="components:index", active_url_names=("components:detail",)),
NavItem(key="guides", label="Guides", href="/docs/"),
NavItem(key="docs", label="Documentation", section_header=True, children=(
NavItem(key="forms", label="Forms", url_name="components:foundation_detail", url_kwargs={"slug": "forms"}),
)),
)
visible = visible_items(items, NavContext(request=request))
active = resolve_active_item(visible, request.resolver_match)
Public API
| Name | Signature or values | Contract |
|---|---|---|
NavItem | frozen dataclass | Exactly one of url_name, external_url, href, section_header, or menu_trigger defines its link shape. |
bw_nav | items, active=None, resolver_match=None | Recursive sidebar and mobile-drawer tree. |
bw_nav_header | items, active=None, resolver_match=None | Flat horizontal header renderer. |
bw_nav_rail | items, active=None, resolver_match=None, density='labelled' | Capability rail. Density is labelled or icons. |
visible_items | items, NavContext | Applies declared permissions, features and visibility policies. It is display only, never authorisation. |
resolve_active_item | items, resolver_match | Matches route name and declared route kwargs, including active_url_names. |
Accessibility and no-JavaScript behaviour
The renderers output ordinary links and native disclosure behaviour. A rail menu trigger declares aria-haspopup, while the consumer owns its progressive panel.
Sidebar and mobile drawer links remain ordinary anchors. Visibility is resolved server-side.
Troubleshooting
- A navigation entry causes a render error.
- Use a registered icon name and only one URL source. Validate the tree at import or application startup.
- The wrong item stays active.
- Declare active_url_names for detail routes and supply fixed url_kwargs for parameterised routes.