Skip to contentAsheeUIAsheeUI

SidebarLayout

The application shell, a header and a footer around a navigation column and the content it belongs to.

SidebarLayout is the shell a product's screens sit in: a header above both columns, a persistent navigation column beside the content, and a footer under them. It owns the arrangement and nothing else, the navigation, the destinations and everything on the page are supplied as nodes, so the shell holds no application state and knows nothing about what a campaign is.

Its one opinion is worth stating plainly: on a narrow screen the navigation column stacks above the content rather than disappearing into an off-canvas drawer, so the whole page stays reachable with the keyboard and there is no focus trap to get wrong.

Usage

import {
  Navbar,
  PageContent,
  Sidebar,
  SidebarLayout,
  Typography,
} from "@asheeui/web";

<SidebarLayout
  header={<Navbar brand="Ashee SMS" links={links} />}
  sidebar={<Sidebar items={items} activeKey="campaigns" />}
>
  <PageContent spacing="lg">
    <Typography role="heading-lg">Campaigns</Typography>
  </PageContent>
</SidebarLayout>;

Four slots, and the shell wraps two of them and not the other two. It renders the navigation column as an aside and the page inside a content column; header and footer are placed bare, without a wrapper of their own, so their landmark is whatever you pass. Navbar brings a header and Footer brings a footer; a plain div brings neither.

The navigation column

side states which edge the column sits on and sidebarWidth how wide it is: sm is 14rem, md 16rem and lg 20rem. Both take effect where the shell becomes two columns, from the lg breakpoint (1024 pixels); below it the column is a full-width band above the content whichever side is stated, because there is no second column to sit at the end of.

sidebarLabel names the column, and it is worth stating whenever the page has another navigation region: a named complementary landmark is one a reader can jump to by name. The column is a slot rather than a Sidebar prop, an invoice, a set of filters or a Sidebar are all just nodes in it.

Keeping the column in view

stickySidebar, registered true, is what keeps the column in view while the content scrolls: from lg it becomes position: sticky at the top of the viewport, as tall as the viewport, with its own scroll bar for a navigation longer than the screen. Turning it off lets the column leave with the content, which suits a page read from top to bottom, a help article whose column is a short list of guides, say, rather than a dashboard moved between all day.

Props

The three arrangement options are registered by the component, so each resolves from the instance, then from components.sidebarlayout, then from the registration: side start, sidebarWidth md, stickySidebar true. sidebarLabel is not among them, a landmark's name belongs to the page that places the column, so it is instance-only, as are the four slots and as. Nothing here states a width for the content column or a rhythm for what it holds: the content takes the room the column leaves, and its spacing belongs to PageContent or Section.

Accessibility

  • The navigation column is an aside named by sidebarLabel (Sidebar by default), so it is a complementary landmark. A Sidebar placed in the column adds no second one: the layout tells it, around the slot, that the landmark already exists, so the sidebar renders a plain div and contributes only its navigation landmark, named by its navLabel, Sidebar navigation by default. The two names therefore differ on their own, and nothing has to be renamed to keep the landmark list readable.
  • Below lg the column is still the first thing in the document, and the side is a statement about order rather than about the DOM: the column is written before the content and painted after it only when side="end" and there are two columns. Nothing is moved, hidden or duplicated by the breakpoint. With the column at the end, that does mean the painted order and the tab order part company from lg, the column is reached before the content it sits beside.
  • The shell renders no main of its own: the content column is a plain div. The landmark comes from what you put in it, PageContent is a main by default, so a content column of plain elements leaves the page without one.
  • header and footer are slots, not landmarks: Navbar renders a header and Footer a footer, and the shell adds no name to either.

The spacing inside the columns is the Layout and spacing vocabulary; which shell a product should start from is the argument in Page compositions.

Native

@asheeui/native ships SidebarLayout with the same props and the same cascade. The platform's differences are the platform's: it has no media query, so the direction is decided once from the window and stated on the row rather than in a stylesheet, and there is no scroll-linked positioning, so stickySidebar resolves through the contract and changes nothing. See React Native.