2.7 KiB
Overlay Best Practices
Use @langgenius/dify-ui/* primitives for ordinary overlays in new and modified web code. Choose by interaction semantics, not visual shape. A feature may compose business content around a primitive, but it must not recreate generic portal, backdrop, positioning, focus, or z-index behavior.
Primitive choice
- Use
Dialogfor modal surfaces that need focus containment, scroll locking, Escape handling, and outside-press dismissal. - Use
AlertDialogonly when a destructive or must-confirm decision requires an explicit response. - Use
Drawerfor side panels and setup or editor surfaces that follow the drawer interaction model. - Use
DropdownMenufor a button-triggered action list andContextMenufor pointer-context actions. - Choose
Select,Combobox, orAutocompleteby the Dify UI search and picker contract, not because each renders a popup. - Use
Popoveror the webInfotipwrapper for explanatory content, long help text, rich layout, or interactive content. - Use
Tooltiponly for a short, non-interactive visual label. Its trigger must already have an accessible name. - Use
PreviewCardonly as a non-interactive visual preview of a link destination. Essential information must remain available without the preview.
Composition
- Prefer the most specific semantic primitive over styling a generic
Dialog. - Use controlled
openandonOpenChangewhen business state, analytics, or cleanup reacts to visibility; otherwise let the primitive own its state. - For a button-like overlay trigger, keep the state-owning primitive outside and use its
renderprop to render the finalButtonorIconButton. Do not mirror open, pressed, or expanded state in the button. - Use the primitive-owned content or portal part. Do not wrap a Dify UI overlay in another manual portal.
- Keep shared overlay chrome in Dify UI and feature-specific content in the feature owner.
Feature-owned exception
The Step-by-step Tour coachmark is a deliberate feature-owned overlay because it targets arbitrary route content and owns spotlight geometry, pointer blockers, and target interaction policy. Its manual portal belongs to web/app/components/step-by-step-tour/coachmark.tsx; it is not a general overlay primitive or a pattern for ordinary dialogs and popovers.
Layering
Body-portalled Dify UI overlays use z-50; Toast uses z-60. The app root keeps an isolated stacking context, and overlays at the same layer rely on DOM order.
Do not add call-site z-index overrides such as z-9999. If an overlay is clipped or hidden, fix the owning overlay structure instead of raising a child primitive.