.agents/skills/frontend-code-review/references/dify-ui.md
Use these rules whenever a review touches packages/dify-ui/ or code consuming @langgenius/dify-ui/*.
Before finalizing findings for those files, read the current local docs that apply:
packages/dify-ui/README.mdpackages/dify-ui/AGENTS.mdweb/docs/overlay.md for floating UIpackages/dify-ui/src/<primitive>/index.tsx for the primitive being changed or consumedFlag in packages/dify-ui:
web/.web/.packages/dify-ui is a primitive layer: Base UI headless components + cva + cn + Dify design tokens.
Flag:
@langgenius/dify-ui without a subpath.package.json#exports entry for a new primitive.Root suffix when no higher-level convenience component exists in the same subpath.Consumers use subpath exports such as @langgenius/dify-ui/button.
Canonical boundaries use the primitive name and matching public types (Select / SelectProps). Keep Root only to distinguish a low-level anatomy root from a higher-level convenience component (CheckboxRoot / Checkbox); implementation aliases should still show their Base UI source (BaseSelect.Root.Props).
Flag:
value / defaultValue, multiple / value, or clearable / onChange.data-* attributes or CSS variables.Select.Root<Value, Multiple>, RadioGroup<Value>, or Radio.Root<Value>.string while callers pass enums, unions, booleans, numbers, objects, or nullable placeholder values.Prefer Base UI/Dify UI data attributes and CSS variables for visual state: data-open, data-checked, data-disabled, data-highlighted, data-popup-open, group-data-*, peer-data-*, has-[:focus-visible], and primitive CSS variables such as anchor width or transform origin. Use JS conditional classes for product/business state that the primitive does not expose.
For non-string Select and RadioGroup values, prefer explicit domain generics at the root and at child value carriers. JSX children do not inherit the parent generic, so RadioGroup<PromptMode> should compose with Radio<PromptMode>, RadioItem<PromptMode>, or option values from a typed collection. For Select, prefer the Base UI items collection pattern for typed value-to-label rendering, and flag string coercion helpers used only to recover display labels.
Flag:
Input and Button pieces without a submit boundary.Field, FieldLabel, and FieldControl when using Dify UI form semantics.FieldLabel instead of SelectLabel.SliderLabel.Fieldset and FieldsetLegend.FieldDescription / FieldError relationships.Form is the submit boundary. Dify UI form primitives are not a form state-management framework; business validation and schema-driven behavior belong in web/.
Flag:
z-* overrides on overlays.isolation: isolate assumptions when debugging overlay stacking.All Dify UI body-portalled overlays use z-50. Toast uses z-60. DOM order handles stacking between overlays.
Flag:
Tabs used for simple mode/filter/view selection where SegmentedControl is the semantic primitive.SegmentedControl used where tablist / tabpanel semantics are required.Select used for searchable or free-form input.Combobox used for unrestricted search text where no selected option is remembered.Autocomplete used for closed-list selection.Use:
Autocomplete for free-form text with optional suggestions.Combobox for searchable selected values from a collection.Select for closed, scannable option sets.Popover for infotips, help text, rich content, or interactions.Flag:
@langgenius/dify-ui/* or web/app/components/base/*, such as buttons, inputs, toggle groups, popovers, dropdown menus, alert dialogs, switches, avatars, scroll areas, toasts, borders, focus states, disabled states, segmented controls, or existing feature components.web/ when a Dify UI primitive exists.div plus classes to match a screenshot.Tooltip because it is visually convenient when the content is actually help text or needs touch access.z-* override to make a child popup appear over a parent dialog.Input as a drop-in replacement for legacy inputs that include search, clear, copy, unit, localized placeholder, or number normalization behavior.data-open, data-checked, data-disabled, or highlighted states that Base UI already exposes.data-* selectors.Flag:
radius-* class names.borderRadius extension for Figma radius values.! important modifiers used to fight primitive styles instead of fixing the variant, selector, or component composition.min-w-(--anchor-width) on picker popups when it defeats viewport clamping.Use the Figma radius mapping from packages/dify-ui/AGENTS.md; for example --radius/sm maps to rounded-md, and --radius/md maps to rounded-lg.
Use ! only for a tightly scoped compatibility override after confirming the primitive API, data attributes, and selector structure cannot express the state.
Flag focus rings attached to the wrong element. For example, Base UI Slider.Thumb focuses an internal input[type=range], so the visible thumb wrapper needs has-[:focus-visible] rather than direct wrapper focus-visible.
Flag:
web/app/components/base/icons/src/... for custom SVG icons.i-custom-* icon class pipeline.packages/iconify-collections/custom-*/icons.json diffs where unrelated existing icons lost or changed intrinsic width or height.New custom SVG icons belong in packages/iconify-collections/assets/.... Regenerate with pnpm --filter @dify/iconify-collections generate, validate with pnpm --filter @dify/iconify-collections check:dimensions, and consume the generated icon with Tailwind i-custom-* classes.