# Popover

> Popover 是 React 颜色选择器打开时所用的定位浮层，已单独导出，方便你构建自己的触发器。在小屏幕上会变成底部面板。

Source: https://chroma-panel.jscrate.dev/zh/react/components/popover
Last updated: 2026-09-21

`Popover` 是 [ColorInput](https://chroma-panel.jscrate.dev/zh/react/components/color-input) 打开选择器时使用的浮层。把它导出，是为了让你能把选择器放在自己的触发器后面，比如一个文字按钮或一个菜单项。如果 `ColorInput` 渲染的色块按钮不是你想要的控件，就用它。

它根据 `anchor` 定位：下方空间够就显示在下方，不够就显示在上方。它会渲染到 `document.body` 中。打开后，焦点移入弹出层，按 Tab 也不会跑出去。按 Escape 或点击外部会调用 `onClose`，按 Escape 还会把焦点还给锚点元素。打开状态由你管理，所以要在 `onClose` 里把它设回 `false`。在里面放一个 [ChromaPanel](https://chroma-panel.jscrate.dev/zh/react/components/chroma-panel)，任何触发器都能打开 React 颜色选择器。

## 结构

```tsx
import { useState } from "react";
import { ChromaPanel, Popover } from "chroma-panel";

export function BrandColorButton() {
  const [anchor, setAnchor] = useState<HTMLButtonElement | null>(null);
  const [open, setOpen] = useState(false);

  return (
    <>
      <button
        ref={setAnchor}
        type="button"
        aria-haspopup="dialog"
        aria-expanded={open}
        onClick={() => setOpen(!open)}
      >
        Brand color
      </button>
      <Popover anchor={anchor} open={open} onClose={() => setOpen(false)}>
        <div role="dialog" aria-label="Brand color">
          <ChromaPanel onClose={() => setOpen(false)} />
        </div>
      </Popover>
    </>
  );
}
```

宽度小于 640px 时，它会变成底部面板。传入 `sheetOnMobile={false}`，就能在任何宽度下都使用锚定的弹出层。

## API 参考

### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `anchor` (required) | `HTMLElement \| null` | — | The element to position against. Pass `null` while the trigger has not mounted. |
| `open` (required) | `boolean` | — | Whether the surface is shown. |
| `onClose` (required) | `() => void` | — | Fires on Escape, on an outside click, and on the sheet being dismissed. You own the open state, so this is where you close it. |
| `offset` | `number` | `8` | Gap in pixels between the anchor and the surface. |
| `sheetOnMobile` | `boolean` | `true` | Below 640px, render as a bottom sheet with a grab handle and a scrim. Turn off for an anchored popover at every width. |
| `className` | `string` | — | Class on the surface. |
| `children` (required) | `React.ReactNode` | — | What the surface contains. |

## 相关内容

- [ColorInput](https://chroma-panel.jscrate.dev/zh/react/components/color-input)：基于这个弹出层的现成触发器
- [浏览器支持](https://chroma-panel.jscrate.dev/zh/react/handbook/browser-support)：底部面板在手机上的表现
- [无障碍功能](https://chroma-panel.jscrate.dev/zh/react/overview/accessibility)：整个选择器的焦点处理
