Veto
Layouts

Shell

The app frame: an app bar, a drawer, a content region and a footer. This page is inside one.

Putting it together

The pieces go inside VetoLayout in any order - the frame positions them, so the markup reads top to bottom instead of being nested to match the picture. They coordinate through shared state, which is how the content region knows to move when a drawer opens without either component knowing about the other.

razor
@inherits LayoutComponentBase

<VetoThemeProvider />

<VetoLayout>
    <VetoAppBar>
        <VetoIconButton Icon="@VetoIcons.Menu"
                        Label="Toggle navigation"
                        OnClick="() => _open = !_open" />
        Veto
        <VetoSpacer />
        <VetoThemeToggle />
    </VetoAppBar>

    <VetoDrawer @bind-Open="_open">
        <VetoNavMenu Items="Nav" />
    </VetoDrawer>

    <VetoMainContent>
        @Body
    </VetoMainContent>
</VetoLayout>

Drawer behaviour

Every behaviour ships; pick one with Variant. Nothing is forced on you, and the default responds to the viewport.

Variants

Parameter Type Default Description
Persistent — — Always visible, pushing content aside.
Temporary — — Hidden until opened, then overlaid with a scrim. Escape closes it and the page behind stops scrolling.
Mini — — Collapsed to an icon rail, expanding on hover or toggle.
Responsive — default Persistent above the breakpoint, temporary below. With MiniBreakpoint set it steps full, rail, overlay.

The responsive behaviour is pure CSS. Only the open state is tracked in code, which means no viewport listener, no layout shift while WebAssembly boots, and a drawer that is already correct in prerendered HTML.

razor
<!-- Full width, then a rail, then an overlay -->
<VetoDrawer @bind-Open="_open"
            Variant="VetoDrawerVariant.Responsive"
            Breakpoint="VetoBreakpoint.Medium"
            MiniBreakpoint="VetoBreakpoint.Small" />

<!-- Always an overlay, wherever it is opened -->
<VetoDrawer @bind-Open="_open" Variant="VetoDrawerVariant.Temporary" Anchor="VetoAnchor.Right" />

Navigation

VetoNavMenu takes its entries as data, so the same navigation can feed a drawer, a dock and a footer without being written out three times. Active entries are matched against the URL and marked with aria-current, and a group containing the current page starts expanded.

csharp
public static readonly IReadOnlyList<VetoNavEntry> Items =
[
    new VetoNavEntry { Label = "Overview", Href = "/", Icon = VetoIcons.Home, MatchExact = true },
    new VetoNavEntry
    {
        Label = "Components",
        Icon = VetoIcons.Grid,
        Children =
        [
            new VetoNavEntry { Label = "Text box", Href = "/docs/components/text-box" },
            new VetoNavEntry { Label = "Card", Href = "/docs/components/card" }
        ]
    }
];

VetoDrawer

Parameter Type Default Description
Open bool true Whether the drawer is open. Supports @bind-Open.
Variant VetoDrawerVariant Responsive Persistent, Temporary, Mini or Responsive.
Anchor VetoAnchor Left Left, Right, Top or Bottom.
Width string "16rem" Width when fully open.
MiniWidth string "4rem" Width when collapsed to a rail.
Breakpoint VetoBreakpoint Medium Where a responsive drawer switches between docked and overlay.
MiniBreakpoint VetoBreakpoint? null Adds the rail step between the two.
ClipMode VetoClipMode Clipped Whether the drawer starts below the app bar or runs full height.
ExpandOnHover bool true Expands a mini drawer while the pointer is over it. Pointer devices only.

VetoAppBar

Parameter Type Default Description
Height string "3.5rem" The bar's height. The content region offsets itself by it.
Dense bool false Reduces height and padding.
Bordered bool true Draws a bottom border.
Elevated bool false Casts a shadow instead of drawing a border.
Translucent bool false Lets content scroll under a blurred bar, with a solid fallback.
Something went wrong. Reload 🗙