Documentation
¶
Index ¶
- func AppShellBreakpointIsValid(b AppShellBreakpoint) bool
- func AsidePositionIsValid(p AsidePosition) bool
- func ContainerWidthIsValid(w ContainerWidth) bool
- func SidebarWidthIsValid(w SidebarWidth) bool
- func SplitRatioIsValid(r SplitRatio) bool
- func StackGapIsValid(g StackGap) bool
- type AppShellBreakpoint
- type AppShellProps
- type AsidePosition
- type ContainerProps
- type ContainerWidth
- type SidebarWidth
- type SplitProps
- type SplitRatio
- type StackGap
- type StackProps
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AppShellBreakpointIsValid ¶
func AppShellBreakpointIsValid(b AppShellBreakpoint) bool
AppShellBreakpointIsValid reports whether b is a defined breakpoint (the zero value counts as defined: it means "use the default lg").
func AsidePositionIsValid ¶
func AsidePositionIsValid(p AsidePosition) bool
AsidePositionIsValid reports whether p is a recognized AsidePosition.
func ContainerWidthIsValid ¶
func ContainerWidthIsValid(w ContainerWidth) bool
ContainerWidthIsValid reports whether w is a recognized ContainerWidth.
func SidebarWidthIsValid ¶
func SidebarWidthIsValid(w SidebarWidth) bool
SidebarWidthIsValid reports whether w is a recognized SidebarWidth.
func SplitRatioIsValid ¶
func SplitRatioIsValid(r SplitRatio) bool
SplitRatioIsValid reports whether r is a recognized SplitRatio.
func StackGapIsValid ¶
StackGapIsValid reports whether g is a recognized StackGap.
Types ¶
type AppShellBreakpoint ¶
type AppShellBreakpoint string
AppShellBreakpoint is the viewport breakpoint at which AppShell switches from the mobile (single-column + MobileNav) to the desktop (sidebar grid) layout. The zero value resolves to AppShellBreakpointLG, the historical default.
const ( // AppShellBreakpointUnspecified is the zero value; it renders as lg. AppShellBreakpointUnspecified AppShellBreakpoint = "" // AppShellBreakpointMD shows the sidebar from 768px up. AppShellBreakpointMD AppShellBreakpoint = "md" // AppShellBreakpointLG shows the sidebar from 1024px up (the default). AppShellBreakpointLG AppShellBreakpoint = "lg" // AppShellBreakpointXL shows the sidebar from 1280px up. AppShellBreakpointXL AppShellBreakpoint = "xl" )
type AppShellProps ¶
type AppShellProps struct {
utils.BaseProps
// Sidebar renders in the left grid column on desktop (lg+). Hidden on
// mobile. Typically navigation.SidebarNav, but any templ.Component works.
Sidebar templ.Component
// display.Drawer or other mobile navigation pattern. Nil = no mobile nav.
MobileNav templ.Component
// Header renders inside the content column, sticky to the top when
// StickyHeader is true. Typically navigation.Nav. Optional.
Header templ.Component
// bottom of the viewport (mt-auto) at every breakpoint — the shell is a
// full-height flex column below the grid breakpoint and a stretching grid
// above it. Optional.
Footer templ.Component
// Content is the main body of the shell. Required.
Content templ.Component
// SidebarWidth controls the desktop sidebar column width via a CSS custom
// property (--tc-sidebar-w). Default SidebarWidthMD (16rem). The main
// column is always minmax(0, 1fr) — never bare 1fr (grid-blowout guard).
SidebarWidth SidebarWidth
// Breakpoint selects the viewport width at which the desktop sidebar
// appears and the MobileNav hides — the hamburger breakpoint. Default
// (zero value) keeps the historical lg: (1024px); md:/xl: cover
// tablet-first and wide-dashboard shells (M22/F102).
Breakpoint AppShellBreakpoint
// StickyHeader pins the Header to the top of the content column on scroll.
// Default true. Set to false for static headers.
StickyHeader bool
// Container, when true (default), wraps Content in a layout.Container at
// ContainerWidth. Set to false when Content manages its own width
// (e.g. an edge-to-edge table or map).
Container bool
// ContainerWidth is the max-width applied to the Content wrapper when
// Container is true. Default ContainerWidthLG.
ContainerWidth ContainerWidth
}
AppShellProps configures a sidebar + content application shell. This is the 2D layout primitive every admin dashboard rebuilds by hand: a fixed-width sidebar on desktop, a sticky optional header, and a flexible main column.
AppShell renders INSIDE the `<main>` landmark provided by `layout.Base` — it does NOT emit its own `<main>` or skip-link (Base owns those). Use it as the body content of Base:
@layout.Base(props) {
@layout.AppShell(layout.AppShellProps{
Sidebar: navigation.SidebarNav(...),
Header: navigation.Nav(...),
Content: dashboardContent(),
})
}
Mobile ¶
The desktop sidebar is `hidden lg:block` — invisible below the lg breakpoint. For mobile navigation, render a separate `display.Drawer` (or any other mobile pattern) and pass it as the MobileNav slot. AppShell will render that slot only below lg. This keeps layout free of the display import and gives the consumer full control over mobile UX.
Empty-slot contract ¶
Every slot is optional; nil renders predictably:
Sidebar nil → no sidebar wrapper, NO --tc-sidebar-w style, single-column
shell (the two-track grid is only emitted when a sidebar
exists — emitting it anyway collapses the shell; fixed
2026-09-08 after the dashboard recipe rendered ~16rem wide)
Header nil → no <header> element
MobileNav nil → nothing rendered below lg
Footer nil → no <footer> element
Content nil → empty content column (the shell frame still renders)
Embedded contexts and min-h-dvh ¶
The shell stretches to the full viewport height (`min-h-dvh`) because it is designed as the direct child of `layout.Base`'s <main>. When embedding an AppShell inside a card or other non-page container (like the demo does), override the height via Class: `utils.Class` merges consumer classes last, so `Class: "min-h-0"` (or an explicit height) wins over the shell default.
func DefaultAppShellProps ¶
func DefaultAppShellProps() AppShellProps
DefaultAppShellProps returns sensible defaults: MD sidebar, sticky header, Content wrapped in a Container at LG width.
type AsidePosition ¶
type AsidePosition string
AsidePosition controls whether the Aside renders before (start) or after (end) the Main content. Both are logical positions — they auto-mirror in RTL contexts because the grid uses source order, not physical left/right.
const ( // AsidePositionEnd renders Aside AFTER Main (default — sidebar on the // right in LTR, left in RTL). AsidePositionEnd AsidePosition = "end" // AsidePositionStart renders Aside BEFORE Main (sidebar on the left in // LTR, right in RTL). AsidePositionStart AsidePosition = "start" // AsidePositionDefault is the canonical default (End). AsidePositionDefault AsidePosition = AsidePositionEnd )
type ContainerProps ¶
type ContainerProps struct {
utils.BaseProps
// Width controls the max-width. Default is ContainerWidthLG.
// Use ContainerWidthProse for long-form articles.
Width ContainerWidth
// NoPad suppresses the responsive horizontal gutter
// (px-4 sm:px-6 lg:px-8). The gutter is ON by default — the zero
// value is the padded common case, so struct literals keep it
// without setting anything. Set NoPad to true only when the
// consumer manages padding (e.g. edge-to-edge maps inside a
// ContainerWidthFull wrapper, or nesting inside a Card/Grid).
NoPad bool
}
ContainerProps configures a content Container — a centered max-width wrapper with responsive horizontal padding. This is the single source of truth for page content width; use it to replace the repeated `max-w-6xl mx-auto px-4 sm:px-6 lg:px-8` snippet.
All new page content should be wrapped in a Container. AppShell already wraps its main content slot in a Container by default — set AppShellProps .Container=false to opt out (e.g. when the page itself manages width).
func DefaultContainerProps ¶
func DefaultContainerProps() ContainerProps
DefaultContainerProps returns sensible defaults: LG width. The responsive gutter needs no explicit opt-in — it is the zero-value default.
type ContainerWidth ¶
type ContainerWidth string
ContainerWidth is a typed enum for the maximum width of a Container. Unknown values fall back to ContainerWidthLG (graceful degradation — never panic).
const ( // ContainerWidthSM narrows the container to max-w-3xl (48rem) — for // sign-in forms, focused single-purpose pages, and short articles. ContainerWidthSM ContainerWidth = "sm" // ContainerWidthMD is max-w-5xl (64rem) — for two-column layouts and // medium-density pages. ContainerWidthMD ContainerWidth = "md" // ContainerWidthLG is max-w-7xl (80rem) — the application default for // dashboards, list pages, and admin panels. ContainerWidthLG ContainerWidth = "lg" // ContainerWidthXL is max-w-[90rem] — for wide dashboards and data-heavy // layouts that need more horizontal real estate than LG. ContainerWidthXL ContainerWidth = "xl" // ContainerWidthFull is max-w-full — full-bleed edge-to-edge content. // Pair with explicit px-* padding on the consumer side. ContainerWidthFull ContainerWidth = "full" // ContainerWidthProse is max-w-prose (65ch) — for long-form articles and // documentation where line length must stay readable. ContainerWidthProse ContainerWidth = "prose" // ContainerWidthDefault is the canonical default (LG). ContainerWidthDefault ContainerWidth = ContainerWidthLG )
type SidebarWidth ¶
type SidebarWidth string
SidebarWidth is a typed enum for the desktop sidebar column width of an AppShell. Unknown values fall back to SidebarWidthMD.
const ( // SidebarWidthSM is 12rem (w-48) — compact icon-heavy sidebars. SidebarWidthSM SidebarWidth = "sm" // SidebarWidthMD is 16rem (w-64) — the default, matches SidebarNav. SidebarWidthMD SidebarWidth = "md" // SidebarWidthLG is 20rem (w-80) — wide sidebars with labels + descriptions. SidebarWidthLG SidebarWidth = "lg" // SidebarWidthAuto sizes the sidebar to its content via `auto` in the grid // template. Use when the sidebar (e.g. SidebarNav) sets its own width and // the grid should not constrain it. CAUTION with SidebarNav specifically: // SidebarNav hardcodes `w-64` (16rem). Under SidebarWidthAuto the grid // track sizes to that element, which is fine — but under SidebarWidthSM // (12rem) the fixed `w-64` sidebar OVERFLOWS its 12rem track (the demo hit // this: it now uses the MD default). Either widen SidebarWidth, override // SidebarNav's width via its Class, or use Auto and let `w-64` win. SidebarWidthAuto SidebarWidth = "auto" // SidebarWidthDefault is the canonical default (MD). SidebarWidthDefault SidebarWidth = SidebarWidthMD )
type SplitProps ¶
type SplitProps struct {
utils.BaseProps
// Main is the primary content column. Required.
Main templ.Component
// Aside is the secondary content column (sidebar, metadata, related
// links). Required.
Aside templ.Component
// AsidePosition controls whether Aside renders before or after Main.
// Default AsidePositionEnd (aside after main in source order + visual).
AsidePosition AsidePosition
// AsideLabel, when set, names the aside landmark (aria-label). Setting it
// renders the column as a semantic <aside> complementary landmark — a
// labeled non-landmark element is invalid HTML-ARIA (aria-label on a
// roleless generic), so the label implies the landmark. Without it, an
// unnamed <aside> would show up unlabeled in screen-reader landmark
// rotors. Empty keeps the plain element (see AsideLandmark).
AsideLabel string
// AsideLandmark, when true, renders the aside column as a semantic
// <aside> complementary landmark instead of the default plain <div>.
// Use it when the column genuinely holds complementary content (related
// links, metadata, TOC); leave it false for plain two-column layouts so
// screen-reader landmark rotors stay clean. Zero value = <div>.
AsideLandmark bool
// Ratio controls the relative column widths. Default SplitRatio1To3
// (main 2/3, aside 1/3).
Ratio SplitRatio
// Gap controls spacing between the two columns. Default GridGapLG (1.5rem).
Gap string
// ContainerAware, when true, wraps the Split in a @container div and swaps
// md: breakpoint classes for @md: so the 2-column collapse responds to the
// parent container's width, not the viewport. Useful when Split is placed
// inside a sidebar, card body, drawer, or other constrained layout. Default
// false (viewport breakpoints). See ADR-0018.
ContainerAware bool
}
SplitProps configures a 2-column content + aside layout — the second most common 2D pattern after AppShell. Use it for article+sidebar widgets, detail+metadata, or any main-content-with-secondary-content layout.
Both columns use minmax(0,1fr) per grid track to prevent grid blowout from wide content (see ADR-0016). The layout collapses to a single stacked column below the md breakpoint (mobile-friendly by default).
func DefaultSplitProps ¶
func DefaultSplitProps() SplitProps
DefaultSplitProps returns sensible defaults: plain layout column, aside at end, 1To3 ratio, gap-6.
type SplitRatio ¶
type SplitRatio string
SplitRatio is a typed enum for the relative widths of the Main and Aside columns in a Split. Unknown values fall back to SplitRatio1To3.
const ( // SplitRatio1To3 — Main takes 2/3, Aside takes 1/3 (default, classic // article+sidebar pattern). SplitRatio1To3 SplitRatio = "1-3" // SplitRatio1To4 — Main takes 3/4, Aside takes 1/4 (wide main, narrow aside). SplitRatio1To4 SplitRatio = "1-4" // SplitRatio1To2 — Main and Aside are equal width. SplitRatio1To2 SplitRatio = "1-2" // SplitRatioDefault is the canonical default (1To3). SplitRatioDefault SplitRatio = SplitRatio1To3 )
type StackGap ¶
type StackGap string
StackGap is a typed enum for vertical spacing between stacked children. Unknown values fall back to StackGapMD. Mirrors the GridGap shape so the two composition primitives share a vocabulary.
const ( StackGapNone StackGap = "none" StackGapSM StackGap = "sm" // space-y-2 (0.5rem) StackGapMD StackGap = "md" // space-y-4 (1rem) — default StackGapLG StackGap = "lg" // space-y-6 (1.5rem) StackGapXL StackGap = "xl" // space-y-8 (2rem) // StackGapDefault is the canonical default (MD). StackGapDefault StackGap = StackGapMD )
type StackProps ¶
type StackProps struct {
utils.BaseProps
// Gap controls the vertical space between children. Default StackGapMD
// when zero or unknown.
Gap StackGap
}
StackProps configures a vertical stack of children with consistent spacing. Use Stack to replace repeated `space-y-N` strings — it is the 1D vertical counterpart to the 2D Grid primitive. Stack is flex-col (NOT grid): both axes do not matter, only the vertical rhythm. See ADR-0016.
func DefaultStackProps ¶
func DefaultStackProps() StackProps
DefaultStackProps returns sensible defaults: MD gap.