Meowland docs
Workbench

Component reference

Page

A content page inside an existing host region: it arranges the identity block, an optional toolbar and notice, and the page content column.

Preview

Documentation page with sections

One content page inside a host region: identity, page tools, a status row and the section rhythm. The outer Container stands in for the host shell's page area; Page itself owns no viewport and no scrolling.

packages/meowtail/stories/page.stories.tsxline 36tsx
render: () => (
  <Container width="page">
    <Page
      eyebrow="Guide · Composition"
      title="Build a page from regions"
      description="Page arranges the page identity, optional tools and the content rhythm; Section names one part of that content and keeps its heading level."
      actions={[
        <Button variant="outline">Copy page link</Button>,
        <Button variant="quiet">Edit this page</Button>,
      ]}
      toolbar={
        <Toolbar label="Page tools">
          <Button variant="quiet" size="small">
            <Icon name="list-checks" />
            Filters
          </Button>
          <Button variant="quiet" size="small">
            <Icon name="list" />
            Outline
          </Button>
        </Toolbar>
      }
      notice={
        <Alert
          layout="bar"
          tone="info"
          actions={
            <Button variant="quiet" size="small">
              View source
            </Button>
          }
        >
          This guide is generated from the authoring templates; only the local controls run here.
        </Alert>
      }
    >
      <Section title="Overview" description="What the two compositions own.">
        <p>
          The page owns the identity block and the spacing between its sections; each section owns
          one titled region. Both arrangements compose primitives that already exist, so the page
          keeps one visual language instead of starting another one.
        </p>
      </Section>

      <Section
        title="Compose the identity"
        description="Eyebrow, title, description and actions form one block."
        actions={
          <Button variant="quiet" size="small">
            Open example
          </Button>
        }
      >
        <p>
          PageHeader renders the h1 and its supporting copy. The eyebrow names the area the page
          belongs to, and the actions act on the page rather than on one section.
        </p>
        <ListGroup>
          <ListRow
            title="Eyebrow"
            description="A small label for the area the page belongs to."
            status="Optional"
          />
          <ListRow
            title="Actions"
            description="Controls that act on the whole page, aligned with the title."
          />
          <ListRow
            title="Notice"
            description="A status row between the identity and the content."
            status={[<Badge tone="accent">Current</Badge>]}
          />
        </ListGroup>
      </Section>

      <Section
        title="Keep one section rhythm"
        description="Sections stack at the page's spacing step."
        actions={
          <Button variant="quiet" size="small">
            Reset
          </Button>
        }
        footer="A nested section steps down one heading level."
        variant="card"
      >
        <p>
          The card variant wraps the same section in the existing Card surface, so a card section
          and a plain section stay one visual language.
        </p>
        <Section title="Nested section">
          <p>
            A section inside a page renders h2; a section nested in another section renders h3.
            The heading level comes from the surrounding region rather than from the caller.
          </p>
        </Section>
      </Section>

      <Section title="Escapes stay available" description="Custom chrome replaces identity only.">
        <p>
          A host that already renders its own header passes the header slot: the toolbar, notice
          and content stay, and the identity block is replaced rather than duplicated. Genuinely
          custom regions can still drop to PageFrame, Card or a layout primitive.
        </p>
      </Section>
    </Page>
  </Container>
)

Installation

bun add meowtail

Usage

usage.tsts
import { Page } from "meowtail";

Examples

The other stories that show this component.

Long identity, tools and notice

The same public page composition under content pressure: long eyebrow, title, description, actions and notice, then long section copy. No business request is simulated.

packages/meowtail/stories/page.stories.tsxline 175tsx
render: () => (
  <Container width="page">
    <Page
      eyebrow={longPageCopy.eyebrow}
      title={longPageCopy.title}
      description={longPageCopy.description}
      actions={[
        <Button variant="outline">{longPageCopy.actionA}</Button>,
        <Button variant="quiet">{longPageCopy.actionB}</Button>,
      ]}
      toolbar={
        <Toolbar label="Page view tools">
          <Button variant="quiet" size="small">
            <Icon name="list" />
            Reading width: content
          </Button>
          <Button variant="quiet" size="small">
            <Icon name="settings" />
            Appearance: follow system
          </Button>
        </Toolbar>
      }
      notice={
        <Alert
          layout="bar"
          tone="warning"
          actions={
            <Button variant="quiet" size="small">
              Review the change
            </Button>
          }
        >
          {longPageCopy.notice}
        </Alert>
      }
    >
      <Section title={longPageCopy.overviewTitle} description={longPageCopy.overviewDescription}>
        <p>{longPageCopy.paragraph}</p>
      </Section>
      <Section
        title={longPageCopy.sectionTitle}
        description={longPageCopy.sectionDescription}
        actions={[
          <Button variant="quiet" size="small">
            Previous
          </Button>,
          <Button variant="quiet" size="small">
            Next
          </Button>,
        ]}
        footer="The footer keeps a supporting note in a smaller line after the content."
      >
        <p>{longPageCopy.paragraph}</p>
        <p>
          Long words such as
          {` ${"authoring-composition-with-regions".repeat(2)} `}
          wrap instead of forcing the content column wider than the host allows.
        </p>
      </Section>
    </Page>
  </Container>
)

API reference

It creates no viewport and owns no scrolling; PageFrame stays the frame primitive for shells and dialogs. The identity block needs a title or a header; without either the page is only its toolbar, notice and content. Slots are fixed for the mount: presence decides whether a region renders, while a Signal passed as slot content still updates its text.

Props

PropTypeDefault
titleThe page name; PageHeader renders it as the h1. Required unless header is given: with neither, the page renders no identity block and keeps only its toolbar, notice and content.
Child–
descriptionOne line of purpose under the title. Ignored without a title or header.
Child–
eyebrowOptional small label above the title. Ignored without a title or header.
Child–
actionsPage-level actions, placed in the header. Ignored without a title or header.
Child–
leadingA mark before the title, forwarded to PageHeader. Ignored without a title or when header replaces the identity block. Presence is fixed for the mount.
Child–
headerEscape hatch: replaces the eyebrow and the PageHeader identity block with host chrome, and needs no title. title, description, eyebrow, leading and actions are then unused.
Child–
toolbarOptional bar below the header for filters or view controls.
Child–
noticeA status row between the header and the content.
Child–
widthContent width, forwarded to the existing Container; default content. Fixed for the mount: the width is chosen when the page mounts, so pass a new key or remount to switch widths.
PageWidth"content"

Also takes className, children and the attributes and events of its root element.

DOM parts

rootheadereyebrowtoolbarnoticecontent

Registry

The component is registered as page in the meowtail component registry.