# @langgenius/dify-ui Shared UI primitives, design tokens, CSS-first Tailwind styles, and the `cn()` utility consumed by Dify's `web/` app. The primitives are thin, opinionated wrappers around [Base UI] headless components, styled with `cva` + `cn` and Dify design tokens. For upstream component docs, start from the [Base UI docs index]. > `private: true` — this package is consumed by `web/` via the pnpm workspace and is not published to npm. Treat the API as internal to Dify, but stable within the workspace. ## Installation Already wired as a workspace dependency in `web/package.json`. Nothing to install. For a new workspace consumer, add: ```jsonc { "dependencies": { "@langgenius/dify-ui": "workspace:*" } } ``` ## Imports Always import from a **subpath export** — there is no barrel: ```ts import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { Dialog, DialogContent, DialogTrigger } from '@langgenius/dify-ui/dialog' import { Drawer, DrawerPopup, DrawerTrigger } from '@langgenius/dify-ui/drawer' import { FieldControl, FieldLabel, FieldRoot } from '@langgenius/dify-ui/field' import { Form } from '@langgenius/dify-ui/form' import { Popover, PopoverContent, PopoverTrigger } from '@langgenius/dify-ui/popover' import { SegmentedControl, SegmentedControlItem } from '@langgenius/dify-ui/segmented-control' import { Textarea } from '@langgenius/dify-ui/textarea' import '@langgenius/dify-ui/styles.css' // once, in the app root ``` Importing from `@langgenius/dify-ui` (no subpath) is intentionally not supported — it keeps tree-shaking trivial and makes Storybook / test coverage attribution per-primitive. ## Primitives | Category | Subpath | Notes | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------ | | Actions | `./button` | Design-system CTA primitive with `cva` variants. | | Controls | `./segmented-control` | SegmentedControl for mode, filter, and view selection. | | Feedback | `./meter`, `./toast` | Meter is inline status; Toast owns the `z-60` layer. | | Form | `./form`, `./field`, `./fieldset`, `./input`, `./textarea`, `./checkbox`, `./checkbox-group`, `./radio`, `./radio-group`, `./number-field`, `./select`, `./slider`, `./switch` | Native form boundary, field semantics, and controls. | | Layout | `./scroll-area` | Custom-styled scrollbar over the host viewport. | | Media | `./avatar` | Avatar root, image, and fallback primitives. | | Navigation | `./pagination`, `./tabs` | Pagination for page navigation; Tabs for panels. | | Overlay / menu | `./alert-dialog`, `./context-menu`, `./dialog`, `./drawer`, `./dropdown-menu`, `./popover`, `./preview-card`, `./tooltip` | Portalled. See [Overlay & portal contract] below. | | Search / pickers | `./autocomplete`, `./combobox`, `./select` | Search input, searchable picker, and closed picker. | Utilities: - `./cn` — `clsx` + `tailwind-merge` wrapper. Use this for conditional class composition. - `./styles.css` — the one CSS entry that ships the design tokens, theme variables, and project utilities/components. Import it once from the app root. ## Segmented control contract `SegmentedControl` is Dify's design-system primitive for mode, filter, and view selection. It is built on Base UI `ToggleGroup` + `Toggle`, so use `Tabs` instead when the UI needs `tablist` / `tabpanel` semantics. Its value contract follows Base UI: `value`, `defaultValue`, and `onValueChange` use arrays, and single-selection mode may report an empty array when the active item is toggled off. ## Form contract Dify UI's form primitives are a Base UI composition layer for native form semantics, field accessibility, and design-system styling. They are intentionally not a form state-management framework. See the upstream [Base UI forms handbook], [Base UI Form], [Base UI Field], and [Base UI Fieldset] docs for the underlying component contracts. Use `Form` for the submit boundary. It renders a native `