dify/web/docs/overlay.md

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 Dialog for modal surfaces that need focus containment, scroll locking, Escape handling, and outside-press dismissal.
  • Use AlertDialog only when a destructive or must-confirm decision requires an explicit response.
  • Use Drawer for side panels and setup or editor surfaces that follow the drawer interaction model.
  • Use DropdownMenu for a button-triggered action list and ContextMenu for pointer-context actions.
  • Choose Select, Combobox, or Autocomplete by the Dify UI search and picker contract, not because each renders a popup.
  • Use Popover or the web Infotip wrapper for explanatory content, long help text, rich layout, or interactive content.
  • Use Tooltip only for a short, non-interactive visual label. Its trigger must already have an accessible name.
  • Use PreviewCard only 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 open and onOpenChange when 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 render prop to render the final Button or IconButton. 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.