# Setup

> A complete screen built from Button, IconButton, PageHeader, StatTile and 4 more components.

Pattern · Pro kit · [Live page](https://ui.twentyfirst.media/pro/patterns/SetupScreen/)

## Code

```tsx
import * as React from "react";
import { Button, PageHeader, StatTile, TintIcon, Wizard } from "@twentyfirstmedia/pro";
import { Shell } from "./_workspace";

function App() {
  const c = React.useState(2);
  return (
    <Shell
      area="Workspace"
      current="overview"
      action={{
        label: "New project",
        icon: "plus",
      }}
      pages={[
        {
          id: "overview",
          label: "Overview",
          icon: "home",
        },
        {
          id: "board",
          label: "Projects",
          icon: "grid",
          count: 7,
        },
        {
          id: "calendar",
          label: "Calendar",
          icon: "calendar",
        },
        {
          id: "people",
          label: "People",
          icon: "users",
        },
        {
          id: "reports",
          label: "Reports",
          icon: "chart",
        },
      ]}
      overlay={
        <div
          style={{
            position: "absolute",
            inset: 0,
            borderRadius: "var(--radius-xl)",
            overflow: "hidden",
          }}
        >
          <div
            className="tf-modal-wrap"
            style={{
              position: "absolute",
              inset: 0,
            }}
          >
            <div className="tf-backdrop" />
            <Wizard
              brand="Halo"
              current={c[0]}
              onPick={c[1]}
              done={{
                0: true,
                1: true,
              }}
              steps={[
                {
                  label: "Name your workspace",
                  icon: "grid",
                },
                {
                  label: "Invite your team",
                  icon: "users",
                },
                {
                  label: "Connect your mailbox",
                  icon: "mail",
                },
                {
                  label: "Connect a domain",
                  icon: "globe",
                },
                {
                  label: "Connect your bank",
                  icon: "card",
                },
                {
                  label: "Create your first agent",
                  icon: "bot",
                },
              ]}
              footer={[
                <Button
                  key="b"
                  variant="ghost"
                  icon="chevronLeft"
                  onClick={() => {
                    c[1](Math.max(0, c[0] - 1));
                  }}
                >
                  Back
                </Button>,
                <Button
                  key="n"
                  iconRight="chevronRight"
                  onClick={() => {
                    c[1](Math.min(5, c[0] + 1));
                  }}
                >
                  Continue
                </Button>,
              ]}
            >
              <div
                className="tf-grid"
                style={
                  {
                    "--cols": "1fr 1fr",
                  } as React.CSSProperties
                }
              >
                {["Google Workspace", "Microsoft 365", "IMAP / SMTP", "Halo Mail"].map((m, i) => (
                  <div
                    key={m}
                    className="tf-file"
                    style={
                      i === 0
                        ? {
                            boxShadow: "inset 0 0 0 2px var(--ink)",
                            background: "var(--surface)",
                          }
                        : undefined
                    }
                  >
                    <TintIcon icon="mail" tint={i === 0 ? "mint" : "plain"} />
                    <b>{m}</b>
                  </div>
                ))}
              </div>
            </Wizard>
          </div>
        </div>
      }
    >
      <PageHeader title="Good morning, Mara" subtitle="Everything that needs a decision today" />
      <div
        className="tf-grid"
        style={
          {
            "--cols": "repeat(4, minmax(0, 1fr))",
            "--cols-sm": "repeat(2, minmax(0, 1fr))",
            "--cols-md": "repeat(2, minmax(0, 1fr))",
          } as React.CSSProperties
        }
      >
        <StatTile tint="sky" value="15" label="All projects" />
        <StatTile tint="mint" value="8" label="Live" />
        <StatTile tint="placeholder" value="3" label="Needs review" />
        <StatTile tint="butter" value="€32,669" label="Revenue (MTD)" />
      </div>
    </Shell>
  );
}
export default function Preview() {
  return <App />;
}
```

## Props

### Button

| Prop | Type | Notes |
| --- | --- | --- |
| `variant?` | `"primary" \| "secondary" \| "soft" \| "ghost" \| "danger" \| "danger-solid"` |  |
| `size?` | `"md" \| "sm"` |  |
| `icon?` | `IconName` |  |
| `iconRight?` | `IconName` |  |
| `disabled?` | `boolean` |  |
| `type?` | `"button" \| "submit" \| "reset"` |  |
| `onClick?` | `(e: MouseEvent<HTMLButtonElement>) => void` |  |
| `children?` | `ReactNode` |  |
| `asChild?` | `boolean` | Render the single child element (a link, a router Link) with the button's look instead of a <button>. |
| `id?` | `string` |  |
| `name?` | `string` | Form field name and value, sent with the form when this button submits it. |
| `value?` | `string` |  |
| `form?` | `string` | The id of the form this button belongs to, when it sits outside it. |
| `title?` | `string` |  |
| `tabIndex?` | `number` |  |
| `autoFocus?` | `boolean` |  |
| `aria-label?` | `string` |  |
| `aria-labelledby?` | `string` |  |
| `aria-describedby?` | `string` |  |
| `aria-expanded?` | `boolean \| "true" \| "false"` | For disclosure and menu triggers: whether what the button controls is open. |
| `aria-controls?` | `string` |  |
| `aria-haspopup?` | `boolean \| "true" \| "false" \| "menu" \| "listbox" \| "tree" \| "grid" \| "dialog"` |  |
| `aria-pressed?` | `boolean \| "true" \| "false" \| "mixed"` | For toggle buttons. |
| `aria-current?` | `boolean \| "true" \| "false" \| "page" \| "step" \| "location" \| "date" \| "time"` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### Icon

| Prop | Type | Notes |
| --- | --- | --- |
| `name` | `IconName` | Required |
| `size?` | `number` |  |
| `label?` | `string` |  |
| `className?` | `string` |  |
| `style?` | `CSSProperties` | Inline style on the root element. |

### IconButton

| Prop | Type | Notes |
| --- | --- | --- |
| `icon` | `IconName` | Required |
| `label` | `string` | Accessible name and tooltip (`aria-label` and `title`); `aria-label` or `title` override them. |
| `variant?` | `"soft" \| "solid" \| "outline" \| "ghost"` |  |
| `size?` | `"sm" \| "md" \| "lg"` |  |
| `type?` | `"button" \| "submit" \| "reset"` |  |
| `onClick?` | `(e: MouseEvent<HTMLButtonElement>) => void` |  |
| `disabled?` | `boolean` |  |
| `asChild?` | `boolean` | Render the single child element (a link) with the button's look; the icon is placed inside it. |
| `children?` | `ReactNode` |  |
| `id?` | `string` |  |
| `name?` | `string` | Form field name and value, sent with the form when this button submits it. |
| `value?` | `string` |  |
| `form?` | `string` | The id of the form this button belongs to, when it sits outside it. |
| `title?` | `string` |  |
| `tabIndex?` | `number` |  |
| `autoFocus?` | `boolean` |  |
| `aria-label?` | `string` |  |
| `aria-labelledby?` | `string` |  |
| `aria-describedby?` | `string` |  |
| `aria-expanded?` | `boolean \| "true" \| "false"` | For disclosure and menu triggers: whether what the button controls is open. |
| `aria-controls?` | `string` |  |
| `aria-haspopup?` | `boolean \| "true" \| "false" \| "menu" \| "listbox" \| "tree" \| "grid" \| "dialog"` |  |
| `aria-pressed?` | `boolean \| "true" \| "false" \| "mixed"` | For toggle buttons. |
| `aria-current?` | `boolean \| "true" \| "false" \| "page" \| "step" \| "location" \| "date" \| "time"` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### PageHeader

| Prop | Type | Notes |
| --- | --- | --- |
| `crumbs?` | `(string \| Crumb)[]` | A breadcrumb above the title (see `Breadcrumb`): labels, or items with `href`/`onClick`. |
| `crumbLinkAs?` | `ElementType` | The element crumb links render as, e.g. Next.js `Link`. |
| `title` | `string` | Required |
| `subtitle?` | `string` |  |
| `actions?` | `ReactNode[]` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### StatTile

| Prop | Type | Notes |
| --- | --- | --- |
| `value` | `ReactNode` | Required |
| `label` | `string` | Required |
| `tint?` | `Tint \| "surface" \| "placeholder"` |  |
| `delta?` | `string` |  |
| `delay?` | `number` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### SubNav

| Prop | Type | Notes |
| --- | --- | --- |
| `eyebrow?` | `string` |  |
| `action?` | `{ label: string; icon?: IconName; onClick?: () => void }` |  |
| `items` | `SubNavItem[]` | Required |
| `current?` | `string` |  |
| `onPick?` | `(id: string) => void` |  |
| `children?` | `ReactNode` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### TintIcon

| Prop | Type | Notes |
| --- | --- | --- |
| `icon` | `IconName` | Required |
| `tint?` | `Tint \| "plain"` |  |
| `label?` | `string` |  |
| `size?` | `number` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### TopBar

| Prop | Type | Notes |
| --- | --- | --- |
| `brand?` | `ReactNode` | The product name, or a node (a logo mark with the name). |
| `tag?` | `string` |  |
| `items` | `NavItem[]` | Required |
| `active?` | `string` |  |
| `user?` | `{ name: string; email?: string }` |  |
| `onNavigate?` | `(label: string) => void` |  |
| `extra?` | `ReactNode` |  |
| `userOpen?` | `boolean` |  |
| `onUser?` | `() => void` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### Wizard

| Prop | Type | Notes |
| --- | --- | --- |
| `steps` | `{ id?: string; label: string; icon?: IconName }[]` | Required |
| `current?` | `number` |  |
| `done?` | `Record<string, boolean>` |  |
| `onPick?` | `(i: number) => void` |  |
| `footer?` | `ReactNode` |  |
| `brand?` | `string` |  |
| `label?` | `string` |  |
| `children?` | `ReactNode` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |
