Skip to content

Overlays & utilities

Layers that sit above the page. Modal overlays trap focus, close with Escape and return focus to the control that opened them; non-modal ones dismiss on outside click.

13 components on this page. Every demo is live — change the theme in the header or flip a demo to right-to-left with its RTL button. 10 of them are React-only for now; Vue, Svelte and Angular versions are coming.

Dialog Link to Dialog

A modal window for focused tasks and decisions.

Live demo

Result: —

Props

PropTypeDescription
open boolean Visibility (controlled).
title ReactNode Heading; names the dialog.
onClose () => void Escape, close button or backdrop.
footer ReactNode Action buttons.
size 'sm' | 'md' | 'lg' Width.
closeOnBackdrop boolean Close when the backdrop is clicked.

Accessibility

Dialog keyboard support
KeyAction
Tab / Shift + Tab Cycle focus inside the dialog
Escape Close and return focus to the trigger

role="dialog" with aria-modal and aria-labelledby; the page behind cannot scroll.

Code

Dialog · React
<Button onClick={() => setOpen(true)}>Open</Button>
<Dialog open={open} title="Delete project?" onClose={() => setOpen(false)}
  footer={<Button variant="danger">Delete</Button>}>
  This cannot be undone.
</Dialog>

Drawer Link to Drawer

A panel that slides in from the start or end edge.

Live demo

Props

PropTypeDescription
open / onClose boolean / () => void Visibility.
title ReactNode Heading.
side 'left' | 'right' Edge to slide from.
footer ReactNode Actions.

Accessibility

Drawer keyboard support
KeyAction
Tab / Shift + Tab Cycle focus inside the drawer
Escape Close

Code

Drawer · React
<Drawer open={open} title="Filters" onClose={() => setOpen(false)}>
  <Checkbox label="Only active members" />
</Drawer>

Tooltip Link to Tooltip

A short hint shown on hover and keyboard focus.

Live demo
Copy link to clipboardOpens in a new tab

Props

PropTypeDescription
text string Tooltip content.
placement 'top' | 'bottom' Position.
children ReactElement The trigger; receives aria-describedby.

Accessibility

Tooltip keyboard support
KeyAction
Tab Focus the trigger to show the tooltip
Escape Hide it without moving focus

role="tooltip" linked with aria-describedby. Never put interactive content in a tooltip — use Popover.

Code

Tooltip · React
<Tooltip text="Copy link to clipboard"><Button>Copy link</Button></Tooltip>

Popover Link to Popover

A non-modal floating panel anchored to a trigger, for interactive content.

Live demo

Props

PropTypeDescription
trigger ReactElement Gets onClick, aria-expanded, aria-controls and aria-haspopup.
open / onOpenChange boolean Controlled visibility.
role 'dialog' | 'group' dialog for interactive content.
showCloseIcon / dismissable boolean Close button / close on outside click.
side / align 'top' | 'bottom' / 'start' | 'center' | 'end' Placement; flips when there is no room.

Accessibility

Popover keyboard support
KeyAction
Enter / Space Open from the trigger
Escape Close and return focus to the trigger

Code

ReactComing to Vue, Svelte and Angular.

Popover · React
<Popover aria-label="Share" showCloseIcon trigger={<Button>Share</Button>}>
  <Input label="Link" readOnly value="https://…" />
</Popover>

ConfirmDialog Link to ConfirmDialog

An alert dialog that asks the user to confirm, via a component or the useConfirm() hook.

Live demo

Result: —

Component: —

Props

PropTypeDescription
ConfirmProvider component Wrap your app once.
useConfirm().confirm(options) Promise<boolean> Resolves true on accept.
message / header ReactNode Content.
severity 'danger' | 'warning' | 'info' | 'success' Icon and accept-button style.
acceptLabel / rejectLabel / defaultFocus string Buttons; focus starts on reject by default.

Accessibility

ConfirmDialog keyboard support
KeyAction
Tab Move between the buttons
Escape Reject and close

role="alertdialog"; focus starts on the safe (reject) action so Enter never deletes by accident.

Code

ReactComing to Vue, Svelte and Angular.

ConfirmDialog · React
function DeleteButton() {
  const { confirm } = useConfirm();
  return <Button variant="danger" onClick={async () => {
    if (await confirm({ header: 'Delete project?', message: 'This cannot be undone.', severity: 'danger', acceptLabel: 'Delete' })) remove();
  }}>Delete</Button>;
}

<ConfirmProvider><DeleteButton /></ConfirmProvider>

ConfirmPopup Link to ConfirmPopup

A lightweight confirmation anchored to the button that triggered it.

Live demo

Result: —

Component: —

Props

PropTypeDescription
target HTMLElement | null Anchor element.
open boolean Visibility.
message / onAccept / onReject … Same options as ConfirmDialog.
confirm({ target }) useConfirm Pass a target to get a popup instead of a dialog.

Accessibility

ConfirmPopup keyboard support
KeyAction
Escape Reject and close

Code

ReactComing to Vue, Svelte and Angular.

ConfirmPopup · React
const { confirm } = useConfirm();
<Button onClick={(e) => confirm({ target: e.currentTarget, message: 'Archive this item?' })}>Archive</Button>

DialogProvider / useDialog Link to DialogProvider / useDialog

Open any component in a dialog from code and await its result.

Live demo

Accent: Violet

Props

PropTypeDescription
DialogProvider component Wrap your app once.
useDialog().open(Component, options) DynamicDialogRef Opens a dialog; ref.result resolves on close.
options { header, data?, footer?, size?, closable? } Dialog settings.
Component props { data, dialogRef } Call dialogRef.close(value) to return a value.

Accessibility

DialogProvider / useDialog keyboard support
KeyAction
Escape Close (when closable)

Code

ReactComing to Vue, Svelte and Angular.

DialogProvider / useDialog · React
function PickColor({ dialogRef }: DynamicDialogContentProps<void, string>) {
  return <Button onClick={() => dialogRef.close('teal')}>Teal</Button>;
}
const { open } = useDialog();
const color = await open(PickColor, { header: 'Pick a colour' }).result;

BlockUI Link to BlockUI

Blocks interaction with a region (or the whole page) while work is in progress.

Live demo
Profile

Props

PropTypeDescription
blocked boolean Block state.
fullScreen boolean Block the whole document.
label / spinner string / boolean Status text and spinner.
template ReactNode Custom mask content.

Accessibility

Blocked content is made inert and aria-busy, so it cannot be focused or clicked; the label is announced.

Code

ReactComing to Vue, Svelte and Angular.

BlockUI · React
<BlockUI blocked={saving} label="Saving…">
  <Card title="Profile">…</Card>
</BlockUI>

ScrollTop Link to ScrollTop

A button that appears after scrolling and returns to the top.

Live demo

v0.30.0 — improvements and fixes. Scroll down to reveal the button.

v0.29.0 — improvements and fixes. Scroll down to reveal the button.

v0.28.0 — improvements and fixes. Scroll down to reveal the button.

v0.27.0 — improvements and fixes. Scroll down to reveal the button.

v0.26.0 — improvements and fixes. Scroll down to reveal the button.

v0.25.0 — improvements and fixes. Scroll down to reveal the button.

v0.24.0 — improvements and fixes. Scroll down to reveal the button.

v0.23.0 — improvements and fixes. Scroll down to reveal the button.

v0.22.0 — improvements and fixes. Scroll down to reveal the button.

v0.21.0 — improvements and fixes. Scroll down to reveal the button.

v0.20.0 — improvements and fixes. Scroll down to reveal the button.

v0.19.0 — improvements and fixes. Scroll down to reveal the button.

v0.18.0 — improvements and fixes. Scroll down to reveal the button.

v0.17.0 — improvements and fixes. Scroll down to reveal the button.

v0.16.0 — improvements and fixes. Scroll down to reveal the button.

v0.15.0 — improvements and fixes. Scroll down to reveal the button.

v0.14.0 — improvements and fixes. Scroll down to reveal the button.

v0.13.0 — improvements and fixes. Scroll down to reveal the button.

v0.12.0 — improvements and fixes. Scroll down to reveal the button.

v0.11.0 — improvements and fixes. Scroll down to reveal the button.

v0.10.0 — improvements and fixes. Scroll down to reveal the button.

v0.9.0 — improvements and fixes. Scroll down to reveal the button.

v0.8.0 — improvements and fixes. Scroll down to reveal the button.

v0.7.0 — improvements and fixes. Scroll down to reveal the button.

v0.6.0 — improvements and fixes. Scroll down to reveal the button.

v0.5.0 — improvements and fixes. Scroll down to reveal the button.

v0.4.0 — improvements and fixes. Scroll down to reveal the button.

v0.3.0 — improvements and fixes. Scroll down to reveal the button.

v0.2.0 — improvements and fixes. Scroll down to reveal the button.

v0.1.0 — improvements and fixes. Scroll down to reveal the button.

Props

PropTypeDescription
target 'window' | RefObject<HTMLElement> What to watch and scroll.
threshold number Pixels before it appears. Default 400.
label string Accessible name.
behavior ScrollBehavior smooth (instant under reduced motion).

Accessibility

ScrollTop keyboard support
KeyAction
Enter / Space Scroll to top

Code

ReactComing to Vue, Svelte and Angular.

ScrollTop · React
<ScrollTop />                       {/* window */}
<div ref={box} style={{ overflow: 'auto', height: 240 }}>
  …
  <ScrollTop target={box} threshold={100} />
</div>

Inplace Link to Inplace

Shows a read-only value that turns into an editor when activated.

Live demo
Project:

Props

PropTypeDescription
display ReactNode What shows when inactive.
children ReactNode | (close) => ReactNode Editor content.
active / onActiveChange boolean Controlled state.
closable boolean Adds a close button.

Accessibility

Inplace keyboard support
KeyAction
Enter / Space Activate
Escape Close and return focus to the display button

Code

ReactComing to Vue, Svelte and Angular.

Inplace · React
<Inplace display={name} closable>
  {(close) => <Input label="Name" value={name} onChange={(e) => setName(e.target.value)} onBlur={close} />}
</Inplace>

FocusTrap Link to FocusTrap

Keeps keyboard focus inside a region while it is active.

Live demo

Props

PropTypeDescription
active boolean Trap on / off.
autoFocus boolean Focus the first focusable element.
restoreFocus boolean Return focus when deactivated.
as ElementType Wrapper element.

Accessibility

FocusTrap keyboard support
KeyAction
Tab / Shift + Tab Wrap around inside the region

Code

ReactComing to Vue, Svelte and Angular.

FocusTrap · React
<FocusTrap active={editing}>
  <Input label="Title" /> <Button onClick={() => setEditing(false)}>Done</Button>
</FocusTrap>

AnimateOnScroll Link to AnimateOnScroll

Reveals content with an animation when it scrolls into view.

Live demo
Plan
Appears as it scrolls into view.
Design
Appears as it scrolls into view.
Build
Appears as it scrolls into view.

Props

PropTypeDescription
enterClass string Class added when visible.
once boolean Animate only the first time.
threshold / rootMargin number / string IntersectionObserver options.
as ElementType Wrapper element.

Accessibility

Content is in the DOM from the start and simply appears when prefers-reduced-motion is set.

Code

ReactComing to Vue, Svelte and Angular.

AnimateOnScroll · React
<AnimateOnScroll>
  <Card title="Fades in">…</Card>
</AnimateOnScroll>

Ripple Link to Ripple

An ink-ripple effect for any clickable element, as a component or hook.

Live demo

Props

PropTypeDescription
<Ripple /> component Drop inside the element: <button>Save<Ripple /></button>.
useRipple(enabled?) RefObject Attach to an element ref instead.

Accessibility

Purely decorative (aria-hidden) and disabled under prefers-reduced-motion.

Code

ReactComing to Vue, Svelte and Angular.

Ripple · React
<button className="pl-btn pl-btn--primary">Save<Ripple /></button>

const ref = useRipple<HTMLDivElement>();
<div ref={ref} className="tile">Click me</div>

Search Pelagic UI