Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 2s
128 lines
5.2 KiB
Plaintext
128 lines
5.2 KiB
Plaintext
---
|
|
title: Popover
|
|
description: Display contextual content anchored to a trigger.
|
|
---
|
|
|
|
import { StoryEmbed } from '/snippets/ui/StoryEmbed.mdx';
|
|
|
|
import PopoverReference from '/snippets/ui/generated/surfaces/popover.mdx';
|
|
|
|
Use `Popover` for contextual information or lightweight controls. `Popup` includes positioning and a portal, so you can compose content directly inside it.
|
|
|
|
<StoryEmbed
|
|
storyId="ui-surfaces-popover--documentation"
|
|
title="Popover example"
|
|
height={440}
|
|
/>
|
|
|
|
## Anatomy
|
|
|
|
Keep the trigger and popup inside `Popover.Root`. The popup can contain text, form controls, and actions.
|
|
|
|
```text
|
|
Popover.Root
|
|
├── Popover.Trigger
|
|
└── Popover.Popup
|
|
├── Popover.Title
|
|
├── Popover.Description
|
|
└── Popover.Close
|
|
```
|
|
|
|
| Part | Requirement | Purpose |
|
|
| ------------- | --------------------------------------- | --------------------------------------------------------------------- |
|
|
| `Root` | Required | Coordinates open state and interactions. |
|
|
| `Trigger` | Required for a trigger-anchored popover | Opens or closes the popup and supplies its anchor. |
|
|
| `Popup` | Required | Renders positioned content with focus management. |
|
|
| `Title` | Recommended | Supplies a visible popup name. An accessible name is always required. |
|
|
| `Description` | Optional | Associates explanatory text with the popup. |
|
|
| `Close` | Optional | Provides an explicit close action within the popup. |
|
|
|
|
`Popup` includes the portal and positioner. Set `arrow` on `Popup` to add its built-in arrow. All parts share their root's context even though the popup renders in a portal; the tree describes component nesting, not the final DOM placement.
|
|
|
|
## Uncontrolled state
|
|
|
|
Use `defaultOpen` to set the initial visibility. The popover owns subsequent changes from its trigger, close controls, and dismissal interactions.
|
|
|
|
```tsx
|
|
import { Popover } from 'twenty-ui/primitives/surfaces';
|
|
|
|
export const ImportHelp = () => (
|
|
<Popover.Root defaultOpen={false}>
|
|
<Popover.Trigger>Import help</Popover.Trigger>
|
|
<Popover.Popup arrow>
|
|
<Popover.Title>Import a CSV file</Popover.Title>
|
|
<Popover.Description>
|
|
Use a header row to identify your columns.
|
|
</Popover.Description>
|
|
<Popover.Close>Got it</Popover.Close>
|
|
</Popover.Popup>
|
|
</Popover.Root>
|
|
);
|
|
```
|
|
|
|
`defaultOpen` defaults to `false`, so it can be omitted. Use `Title` and `Description` to identify the popup. The trigger renders a button by default; `render` lets you supply a compatible element.
|
|
|
|
## Controlled state
|
|
|
|
Pass `open` and update it with `onOpenChange` to own the same popover's visibility in React state.
|
|
|
|
```tsx
|
|
import { useState } from 'react';
|
|
import { Popover } from 'twenty-ui/primitives/surfaces';
|
|
|
|
export const ImportHelp = () => {
|
|
const [open, setOpen] = useState(false);
|
|
|
|
return (
|
|
<Popover.Root open={open} onOpenChange={setOpen}>
|
|
<Popover.Trigger>Import help</Popover.Trigger>
|
|
<Popover.Popup arrow>
|
|
<Popover.Title>Import a CSV file</Popover.Title>
|
|
<Popover.Description>
|
|
Use a header row to identify your columns.
|
|
</Popover.Description>
|
|
<Popover.Close>Got it</Popover.Close>
|
|
</Popover.Popup>
|
|
</Popover.Root>
|
|
);
|
|
};
|
|
```
|
|
|
|
`onOpenChange` receives the next boolean and event details, including changes requested by the trigger, close controls, Escape, and outside interaction.
|
|
|
|
## Compose with buttons
|
|
|
|
Pass a Twenty UI `Button` through `render` to use it as the trigger or close control. The popover keeps its open state, keyboard behavior, and focus handling.
|
|
|
|
```tsx
|
|
import { Button } from 'twenty-ui/primitives/input';
|
|
import { Popover } from 'twenty-ui/primitives/surfaces';
|
|
|
|
export const ImportHelp = () => (
|
|
<Popover.Root>
|
|
<Popover.Trigger render={<Button variant="outline">Import help</Button>} />
|
|
<Popover.Popup arrow>
|
|
<Popover.Title>Import a CSV file</Popover.Title>
|
|
<Popover.Description>
|
|
Use a header row to identify your columns.
|
|
</Popover.Description>
|
|
<Popover.Close render={<Button>Got it</Button>} />
|
|
</Popover.Popup>
|
|
</Popover.Root>
|
|
);
|
|
```
|
|
|
|
`render` composes behavior onto the supplied button. Custom wrapper components must [forward the supplied props and ref](/ui/primitives/overview#custom-components) to preserve that behavior.
|
|
|
|
## Placement and focus
|
|
|
|
`Popup` defaults to `side="bottom"`, `align="center"`, and `sideOffset={8}`. Set `arrow` to show an arrow. Set `container` to override the theme's portal container; see [theming](/ui/theming).
|
|
|
|
Escape closes the popup and focus returns to the trigger. Outside interaction dismisses it by default. Use the focus props on `Popup` when its content needs a specific initial or return focus target.
|
|
|
|
## Props
|
|
|
|
The reference is generated from the public component types. Native attributes, including accessible names and event handlers, are also accepted on parts that render elements.
|
|
|
|
<PopoverReference />
|