JGuang

Layout

Layout · Astryx

Preview
npm install @astryxdesign/core@0.7.1 @astryxdesign/theme-neutral@0.7.1 @stylexjs/stylex@0.19.0

Layout

Layout is a general five-slot primitive for arranging header, start, content, end, and footer regions within a page or bounded container. AppShell owns the page shell and app-wide navigation behavior; use HStack or VStack for simple directional stacking.

Installation

npm install @astryxdesign/core@0.7.1 @astryxdesign/theme-neutral@0.7.1 @stylexjs/stylex@0.19.0

Requires React 19+, base CSS and a Theme provider. See Setup.

Layout

Layout is a general five-slot primitive for arranging header, start, content, end, and footer regions within a page or bounded container. AppShell owns the page shell and app-wide navigation behavior; use HStack or VStack for simple directional stacking.

PropTypeDefaultDescription
contentReactNodeContent slot (center). Accepts any ReactNode; use LayoutContent when a content region is needed. Children passed to <Layout> render here too: <Layout>{main}</Layout> is shorthand for <Layout content={main} />.
headerReactNodeHeader slot. Accepts any ReactNode; use LayoutHeader when a header region is needed.
footerReactNodeFooter slot. Accepts any ReactNode; use LayoutFooter when a footer region is needed.
startReactNodeLogical-start slot (left in LTR). Accepts any ReactNode; use LayoutPanel when a panel region is needed.
endReactNodeLogical-end slot (right in LTR). Accepts any ReactNode; use LayoutPanel when a panel region is needed.
height'fill' | 'auto''fill'Height behavior: fill the container or grow with content.
contentWidthSizeValueMaximum width of the aligned content within each slot (header, content, footer, panels), centered when narrower than the available space. Without panels, LayoutContent spans the available width so its scrollbar stays at the outer edge while its children align internally to contentWidth. With exactly one panel, the panel stays aligned to the contentWidth frame while LayoutContent extends to the opposite open edge. With both panels, contentWidth includes the complete middle composition. Percentage widths—including percentage-bearing calc(), min(), max(), and clamp() values—and intrinsic widths, plus bare var(...) values, retain the constrained composition; use calc(var(...)) for a variable guaranteed to resolve to a length. Dividers stay full-bleed. Numbers are treated as pixels, strings are used as-is (e.g. 60ch). Common page widths: 640 for forms, settings, and text-focused pages; 960 for content pages and wider layouts.
padding0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10Padding at the layout's outer edges using the spacing scale. Applies to this Layout's own header, footer, panels, and content. A nested Layout does not inherit it: without padding, its regions use the enclosing Card, Section, or Dialog padding, or the default inset (spacing 4). That keeps a page Layout inside AppShell inset even though AppShell's own regions are full bleed.
defaultHasDividersbooleanDefault divider visibility for LayoutHeader and LayoutFooter children. Headers and footers that don't pass hasDivider use this value; when unset, nested layouts inherit from their parent context.

Usage guidance

  • Use Layout when content needs named header, start, content, end, or footer regions.
  • Use HStack and VStack for simple directional stacking within a content area.
  • Avoid: Use Layout for simple stacking layouts; use HStack or VStack instead.
  • Avoid: Use Layout as the page shell or for app-wide navigation; use AppShell for that responsibility.

Page with a details panel inside AppShell

function OrdersPage() {
  return (
    <AppShell
      sideNav={
        <SideNav>
          <SideNavItem label="Orders" isSelected />
          <SideNavItem label="Customers" />
          <SideNavItem label="Settings" />
        </SideNav>
      }>
      {/* No padding props needed: the page Layout's regions keep their
          default inset inside AppShell's full-bleed content area. */}
      <Layout
        header={
          <LayoutHeader hasDivider>
            <Heading level={1}>Orders</Heading>
          </LayoutHeader>
        }
        end={
          <LayoutPanel
            hasDivider
            width={320}
            role="complementary"
            label="Order details">
            <VStack gap={2}>
              <Heading level={2}>Order #1042</Heading>
              <Text type="body" color="secondary">
                Shipped · 3 items · $184.00
              </Text>
            </VStack>
          </LayoutPanel>
        }
        content={
          <LayoutContent>
            <Text type="body">
              Select an order to see its shipping and payment details.
            </Text>
          </LayoutContent>
        }
      />
    </AppShell>
  );
}

Theming API

{
  "targets": [
    {
      "className": "astryx-layout",
      "visualProps": [
        "height"
      ]
    },
    {
      "className": "astryx-layout-content"
    },
    {
      "className": "astryx-layout-footer"
    },
    {
      "className": "astryx-layout-header"
    },
    {
      "className": "astryx-layout-panel"
    }
  ]
}

LayoutHeader

LayoutContent

LayoutFooter

LayoutPanel

Card

Section

Anatomy

  • Layout container: General layout primitive that places the header, start, content, end, and footer slots.
  • Header: Optional LayoutHeader region supplied by the caller, typically in the header slot.
  • Panel: Optional LayoutPanel region supplied by the caller in the start or end slot.
  • Content area: Optional LayoutContent region supplied by the caller in the content slot.
  • Footer: Optional LayoutFooter region supplied by the caller, typically in the footer slot.

Layout Content

Scrollable main content area.

PropTypeDefaultDescription
childrenReactNodeContent.
padding0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10Internal padding using the spacing scale. Overrides the default padding from the layout container.
isScrollablebooleantrueEnable scrollable overflow. With arithmetic contentWidth values, the scrollport spans through every open side while context-aware insets keep children aligned.
labelstringAccessible label for the landmark element.
roleAriaRoleARIA landmark role.

Bottom bar for action bars, pagination, and status bars.

PropTypeDefaultDescription
childrenReactNodeFooter content.
hasDividerbooleanfalseBorder at top edge.
heightSizeValueFooter height. Numbers are treated as pixels, strings are used as-is.
labelstringAccessible label for the landmark element.
roleAriaRoleARIA landmark role.

Layout Header

Top bar for page titles, app bars, and toolbars.

PropTypeDefaultDescription
childrenReactNodeHeader content.
hasDividerbooleanfalseBorder at bottom edge.
heightSizeValueHeader height. Numbers are treated as pixels, strings are used as-is.
labelstringAccessible label for the landmark element.
paddingBlockEnd0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10Block-end (bottom) padding, using the spacing scale. Overrides padding on that edge only; paddingBlockEnd={0} docks the last child on the header bottom edge.
roleAriaRoleARIA landmark role.

Layout Panel

Sidebar for navigation, settings, or inspector panels.

PropTypeDefaultDescription
childrenReactNodePanel content.
hasDividerbooleanfalseBorder on the appropriate edge.
padding0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10Internal padding using the spacing scale. Overrides the default padding from the layout container.
isScrollablebooleantrueEnable scrollable overflow.
labelstringAccessible label for the landmark element.
roleAriaRoleARIA landmark role.
widthnumber | stringWidth of the panel. Numbers are treated as pixels, strings are used as-is. Ignored when resizable is provided; the hook controls width.
resizableResizablePropsResize props from useResizable(). When provided, the hook drives the panel width and a ResizeHandle should be placed adjacent to the panel. Carries the region's axis ('horizontal' | 'vertical'), which must match the adjacent ResizeHandle's direction.

Examples

  • Layout Content: LayoutContent is the scrollable main content area within a Layout, providing automatic padding and scroll containment between the header and footer.
  • Layout Footer: LayoutFooter is a fixed footer slot within a Layout, pinned to the bottom for persistent actions like form buttons or navigation.
  • Layout Header: LayoutHeader is a fixed header slot within a Layout, pinned to the top for titles, navigation, and action buttons.
  • Layout Panel: LayoutPanel is a sidebar slot within a Layout, used for navigation, detail views, or secondary content alongside the main content area.
  • Layout:
  • Layout — Basic Card: A card layout with header, scrollable content area, and footer with action buttons.
  • LayoutContent — Basic: A scrollable main content area below a fixed header. Use LayoutContent inside Layout to get automatic padding and scroll containment for the primary content.
  • Layout — Content Only: A minimal layout with just a content area inside a card, without header or footer.
  • Layout — Content Width: A layout using contentWidth to constrain and center content while keeping dividers full-bleed.
  • Layout — Dual Panel: A file browser style layout with start panel for folders, main content for files, and end panel for details.
  • LayoutFooter — Actions: A fixed footer with end-aligned action buttons below scrollable content. Use LayoutFooter inside Layout for persistent actions like Save and Cancel.
  • Layout — Full Bleed Content: A layout where content extends edge-to-edge with zero padding, ideal for tables or images.
  • LayoutHeader — With Actions: A fixed page header with a title and a primary action, above scrollable content. Use LayoutHeader inside Layout for persistent page-level headers.
  • LayoutPanel — Navigation: A fixed-width side panel holding a navigation list next to the main content. Use LayoutPanel in the start or end slot of Layout for sidebars.
  • Layout — Sidebar Navigation: A settings page layout with a navigation sidebar panel, content area, header, and footer.