YouBothAgent▾
You — Business rules and flows you own. Read these yourself.
Both — Know the idea; your agent follows the details.
Agent — Conventions and references your agent follows. Look up as needed.
CLI Reference▾
AkanJS Reference▾
UI Reference▾

Overlays UI

The overlay components in akanjs/ui: modal windows, confirmations, bottom sheets, menus, hints and a copy action. Start with Modal, and compose the headless Dialog only when you need your own layout.
Words used on this page
portal
Drawing an element elsewhere in the DOM, here at the end of document.body, so no parent clips it.
trigger
The element the user clicks to open the overlay, passed as trigger or as children.
controlled
You pass open and set it back in onCancel. Left out, the component keeps its own open state.
override slot
A name in _overrides.tsx that swaps a component for one route subtree.
scrim
A see-through layer behind a popover that catches the click outside it.
Pick a component
Component
Portalled
At trigger
Override slot
Windows over the page
Modal
✓
✓
A centred window with title, body and footer slots. The default for a modal flow.
Dialog
✓
The headless parts Modal is built from, for a custom layout or an agent-named dialog.
BottomSheet
A mobile panel that slides up from the bottom edge. Drawn in place, fixed to the screen.
Anchored to a trigger
Popconfirm
✓
✓
✓
A small OK/cancel popover before a destructive action.
Dropdown
✓
✓
✓
A short action menu, such as the actions on a list row.
Tooltip
✓
A hover or focus hint in pure CSS. At the screen edge it is clipped, not moved.
Navigation and helpers
Menu
✓
A navigation menu built from an items tree, for a sidebar or a top bar.
Portal
Renders its children into a host element named by id.
Copy
Copies text to the clipboard and shows a success toast.
✓Does itDoes not
  • A portalled overlay is never clipped. Modal, Dropdown, Popconfirm and Select render at document.body, so a scrolling modal body or a table's overflow container cannot cut them off.
  • Portal is the same idea with a name. It renders into a host element you pick by id instead of at the end of the body.
  • Tooltip does none of this on purpose. It is pure CSS, so it costs almost nothing, and near the screen edge it is clipped rather than moved.
Related pages

Dialog

The headless compound parts that Modal is built from. Compose them when Modal's fixed layout does not fit, or when the in-page agent should be able to open and close the dialog.
Props / API
Dialog{ open?, defaultOpen? = false, namespace?, className? }
The root that holds the open state. open is followed whenever it changes.
namespacestring
Names the dialog for the in-page agent. Without it, the dialog publishes no tool.
Dialog.Trigger{ className?, children }
Opens the dialog when anything inside it is clicked.
Dialog.Modal{ onCancel?, confirmClose?, closeButton?, className?, bodyClassName? }
The plain window Modal draws. Escape, a backdrop click and the corner button close it.
Dialog.LegacyModal{ onCancel?, confirmClose?, className?, bodyClassName? }
The previous window: spring open/close and drag-to-dismiss on touch.
Dialog.Title / Dialog.Action{ children }
Draw nothing where written; they hand their children to the header and footer rows.
Dialog.Content{ className?, children }
The body, a full-width block.
  • A namespace publishes three names. namespace="share" gives the agent openDialogInShare, closeDialogInShare and the dialogInShare state. Two dialogs on one screen need different names.
  • The agent closes it the way a person does. Its close goes through the window's own dismissal, so confirmClose and onCancel still run. Modal takes no namespace, so it publishes nothing.
Usage

Popconfirm

A small OK/cancel popover that stands in front of a destructive or irreversible action. Wrap the trigger in it and pass the action as onConfirm.
Props / API
titleReactNode
The question, in bold.
descriptionReactNode
Optional detail under the title.
onConfirm() => void
Called when the user presses OK. The popover closes first.
okText / cancelTextReactNode
Button labels. The defaults are the base.ok and base.cancel dictionary entries.
okButtonProps / cancelButtonPropsButtonHTMLAttributes & { loading? }
Attributes spread onto the two default buttons.
iconReactNode | false
The mark beside the message, a warning icon by default. false draws none.
actionsReactNode
Replaces the whole footer. The replacement owns both the confirm and the dismiss.
triggerClassName / decoClassNamestring
Classes for the trigger wrapper and for the pointer. decoClassName also takes over its position.
  • Never clipped. The popover portals to document.body and sits under the trigger's end edge. With no room below it flips above, and the pointer follows.
  • The scrim takes the outside click. Clicking outside, or Escape, only cancels the popover. A Dropdown or modal that opened it stays open.
  • Removing a model record? Model.RemoveWrapper already draws this popover and publishes the removal as an agent tool.
Usage

BottomSheet

The mobile overlay: a panel that slides up from the bottom edge. type decides almost everything; like Modal, it runs controlled or from its own trigger.
Props / API
type"full" | "half"
Required. half is 90% tall with a grab handle; full covers the screen with a close row.
open / onCancelboolean / () => void
Controlled state. Left out, the sheet keeps its own and opens from trigger or the ref.
triggerReactNode
Element that opens the sheet.
header / handle / closeReactNode
header replaces the whole top row; handle and close replace only the mark inside it.
className / bodyClassNamestring
Classes for the sheet surface and for its scrolling body.
refBottomSheetRef
{ open, close }, an imperative handle for opening the sheet without a trigger.
  • Four ways to close it: drag a half sheet's handle down past a third of its height, tap the backdrop, press Escape, or use a full sheet's close row. Each one calls onCancel.
Usage

Tooltip

A hint that appears on hover or keyboard focus, drawn in pure CSS. It is for hints only: content that must be read does not belong in a tooltip.
Props / API
contentReactNode
The hint. Empty, null or undefined renders children alone.
childrenReactNode
The trigger the bubble is anchored to.
side"top" | "right" | "bottom" | "left" = "top"
Which side of the trigger the bubble sits on.
variant"default" | "primary" | "info" = "default"
The bubble's colour. Field.Label uses info for the help icon beside a field description.
classNamestring
Classes for the bubble.
  • Light, but it never moves. No state, no portal and no position pass, so it works in the server-rendered HTML. The cost: near the viewport edge the bubble is clipped rather than flipped.
  • A conditional hint needs no wrapper. Pass an empty content and only the trigger renders. The bubble shows after 300 ms of hover, or at once on keyboard focus.
  • Need one that flips or follows the pointer? Tooltip is an override slot: bind your own in _overrides.tsx and every existing call site follows.
Usage

Portal

Renders children into an element the page already has, named by id. It is the wiring behind Layout.Navbar: a component deep in a route fills the top bar without either one knowing about the other.
Props / API
idstring
The host element's id. Nothing renders until that element is mounted.
childrenReactNode
What is rendered into the host.
  • Fill the frame's slots through their Layout component. Layout.Navbar, Layout.TopInset, Layout.TopLeftAction and Layout.BottomInset pick the right host in a CSR build, and all but TopLeftAction reserve the slot's height.
  • Frame slots are in the first HTML. During SSR their content is written into the shell instead of appearing after hydration. A host of your own is filled in the browser.
  • It is not a way out of a clipping parent. Modal already portals to document.body, and Dropdown, Popconfirm and Select also place themselves against their trigger.
Usage

Copy

Wraps a trigger so that clicking it copies text to the clipboard and shows a success toast.
Props / API
textstring = ""
Text written to the clipboard.
copyMessagestring
The success toast. Defaults to "Copied" in the reader's language.
childrenReactNode
The trigger. An element keeps its own onClick, which runs before the copy.
  • Works without the Clipboard API. Where navigator.clipboard is missing it falls back to a hidden text area. The toast goes through the store's showMessage.
Usage

Released under the MIT License

Connect your AI to these docs

MCPhttps://akanjs.com/mcp
Copyright © 2026 Akan.js All rights reserved.System managed bybassman