Skip to content

OverlayLayout

The standard overlay that is not a form: a title and description with the close button, a body that scrolls, and a footer that stays in view. A record in a sheet, settings that apply at once, or an alert-sized card that is not a question.

Language
Appearance

A record in a sheet

Opened from a trigger; the main action is last in the footer, and focus returns to the button.

import { Button, OverlayLayout, OverlayTrigger } from '@arbol-ai/ui';

<OverlayTrigger>
  <Button variant="outline">Ana Torres</Button>
  <OverlayLayout
    description="Writer in this conversation"
    dirty={false}
    footer={
      <>
        <Button slot="close" variant="outline">
          Done
        </Button>
        <Button>Open profile</Button>
      </>
    }
    kind="sheet"
    title="Ana Torres"
  >
    <dl className="rounded-card divide-y border text-sm">
      <div className="flex justify-between gap-4 px-3 py-2.5">
        <dt className="text-muted-foreground">Phone</dt>
        <dd>+57 300 555 0101</dd>
      </div>
      <div className="flex justify-between gap-4 px-3 py-2.5">
        <dt className="text-muted-foreground">Last visit</dt>
        <dd>October 28</dd>
      </div>
    </dl>
  </OverlayLayout>
</OverlayTrigger>

Settings that apply at once

Nothing is lost on closing, so it never asks; Reset sits at the start of the footer.

import { useState } from 'react';
import { Button, OverlayLayout, OverlayTrigger, SettingToggle } from '@arbol-ai/ui';

const BoardSettingsExample = () => {
  const [showWeekends, setShowWeekends] = useState(false);
  const [startNow, setStartNow] = useState(true);
  return (
    <OverlayTrigger>
      <Button variant="outline">Board settings</Button>
      <OverlayLayout
        dirty={false}
        footer={<Button slot="close">Done</Button>}
        footerStart={
          <Button
            onPress={() => {
              setShowWeekends(false);
              setStartNow(true);
            }}
            variant="ghost"
          >
            Reset everything
          </Button>
        }
        kind="sheet"
        title="Board settings"
      >
        <SettingToggle
          description="Saturdays and Sundays get a column."
          isSelected={showWeekends}
          label="Show weekends"
          onChange={setShowWeekends}
        />
        <SettingToggle
          description="The board scrolls to the current hour when it opens."
          isSelected={startNow}
          label="Start at the current time"
          onChange={setStartNow}
        />
      </OverlayLayout>
    </OverlayTrigger>
  );
};

<BoardSettingsExample />

An alert-sized card

kind=“alert” with role=“dialog”: a small card on every screen that a click outside dismisses, since it asks nothing.

import { Button, OverlayLayout, OverlayTrigger } from '@arbol-ai/ui';

<OverlayTrigger>
  <Button variant="outline">Lunch break</Button>
  <OverlayLayout
    description="Dr. Ruiz, Thursday 12:00–13:00."
    footer={<Button slot="close">Release the time</Button>}
    kind="alert"
    // oxlint-disable-next-line jsx-a11y/prefer-tag-over-role -- the overlay's role prop, not an element's
    role="dialog"
    title="Lunch break"
  >
    <p className="text-muted-foreground text-sm">Nobody can book in this time.</p>
  </OverlayLayout>
</OverlayTrigger>

Source

The examples above are src/blocks/overlay-layout/overlay-layout.examples.tsx, which the library’s tests render too.

Type to search…

↑↓ navigate↵ selectEsc close