ListLayout

A page that lists things: header, filters, then the items.

Overview

An index of quotes, builds, members or any other collection; a single record is DetailLayout.

Rows

Do

Quotes

Every quote you have sent.

Status

Naledi Mokoena

Accepted

Q-1042 · R 1 240 / mo

Pieter van Wyk

Sent

Q-1041 · R 860 / mo

import {
  Body,
  Button,
  Card,
  FilterGroup,
  ListLayout,
  Pill,
  ToggleChip,
} from "@hackcove/ui";

<ListLayout
  title="Quotes"
  subtitle="Every quote you have sent."
  actions={<Button>New quote</Button>}
  filters={
    <FilterGroup legend="Status">
      <ToggleChip pressed>All</ToggleChip>
      <ToggleChip pressed={false}>Sent</ToggleChip>
    </FilterGroup>
  }
>
  <Card as="article" title="Naledi Mokoena" status={<Pill tone="emerald">Accepted</Pill>}>
    <Body as="p">Q-1042 · R 1 240 / mo</Body>
  </Card>
  <Card as="article" title="Pieter van Wyk" status={<Pill tone="slate">Sent</Pill>}>
    <Body as="p">Q-1041 · R 860 / mo</Body>
  </Card>
</ListLayout>
filters sit under the header, then the rows: one Card per item.
Don't

Quotes

Every quote you have sent.

Naledi Mokoena

Q-1042 · R 1 240 / mo

import { Body, Card, PageHeader, Stack } from "@hackcove/ui";

<Stack>
  <PageHeader title="Quotes" subtitle="Every quote you have sent." />
  <Card as="article" title="Naledi Mokoena">
    <Body as="p">Q-1042 · R 1 240 / mo</Body>
  </Card>
</Stack>
A one-off header and stack drifts from every other list page; ListLayout is the one header, filters and list.

Nothing yet

Do

Quotes

Every quote you have sent.

No quotes yet

Quotes you send show up here.

import { Body, Button, EmptyState, ListLayout } from "@hackcove/ui";

<ListLayout
  title="Quotes"
  subtitle="Every quote you have sent."
  isEmpty
  empty={
    <EmptyState title="No quotes yet" actions={<Button>New quote</Button>}>
      <Body as="p" color="secondary">
        Quotes you send show up here.
      </Body>
    </EmptyState>
  }
/>
empty takes the list's place when isEmpty: say what is missing and what to do.
Don't

Quotes

Every quote you have sent.

import { ListLayout } from "@hackcove/ui";

<ListLayout title="Quotes" subtitle="Every quote you have sent." isEmpty />
isEmpty without empty leaves a blank page under the header.

Full page

Quotes

Every quote you have sent.

Status

Naledi Mokoena

Q-1042 · R 1 240 / mo

Pieter van Wyk

Q-1041 · R 860 / mo

import {
  AppShell,
  Body,
  BodyStrong,
  Button,
  Card,
  FilterGroup,
  ListLayout,
  NavTabs,
  ToggleChip,
} from "@hackcove/ui";

<AppShell
  brand={<a href="#">Hack Cove</a>}
  nav={
    <NavTabs
      label="Main"
      items={[
        { label: "Quotes", href: "#quotes", active: true },
        { label: "Clients", href: "#clients" },
      ]}
    />
  }
>
  <ListLayout
    title="Quotes"
    subtitle="Every quote you have sent."
    actions={<Button>New quote</Button>}
    filters={
      <FilterGroup legend="Status">
        <ToggleChip pressed>All</ToggleChip>
        <ToggleChip pressed={false}>Sent</ToggleChip>
        <ToggleChip pressed={false}>Accepted</ToggleChip>
      </FilterGroup>
    }
  >
    <Card as="article">
      <BodyStrong as="p">Naledi Mokoena</BodyStrong>
      <Body as="p" color="secondary">
        Q-1042 · R 1 240 / mo
      </Body>
    </Card>
    <Card as="article">
      <BodyStrong as="p">Pieter van Wyk</BodyStrong>
      <Body as="p" color="secondary">
        Q-1041 · R 860 / mo
      </Body>
    </Card>
  </ListLayout>
</AppShell>
A whole list page: the shell with its brand and nav, then the layout with its filters and rows.

Usage

  • Put the page's title, subtitle and primary actions in the header props; breadcrumbs and tabs go there too.
  • filters sit between the header and the list: a FilterGroup of ToggleChips.
  • The items are the children, one Card per item, or a Table; the layout spaces them.
  • Set isEmpty and give empty an EmptyState that says what is missing and what to do next; isEmpty without empty is a blank page.
  • Do not build the header and the list by hand with PageHeader and Stack: the layout is the one right header, filters and list.

Accessibility

  • The title is the page's h1.
  • filters and children render as given, so each filter group keeps its own fieldset and legend.
  • data-* and aria-* go on the list's wrapper.

API

ListLayout

A list page: header, an optional filters slot, then the list, or empty when isEmpty.


actions

Right of the title on sm and up, below it on a phone.

Type
ReactNode

breadcrumbs

A Breadcrumbs above the title.

Type
ReactNode

empty

Shown in place of children when isEmpty.

Type
ReactNode

filters
Type
ReactNode

isEmpty
Type
boolean
Default
false

subtitle
Type
ReactNode

tabs

A NavTabs (or similar) under the title.

Type
ReactNode

title required
Type
ReactNode