# @mezzanine-ui/react
> React component library for Mezzanine UI — a comprehensive set of accessible, themeable components built on top of @mezzanine-ui/core, @mezzanine-ui/icons, and @mezzanine-ui/system.
## Installation
```bash
npm install @mezzanine-ui/react @mezzanine-ui/core @mezzanine-ui/icons @mezzanine-ui/system react react-dom lodash
```
Peer dependencies: `react >= 18`, `react-dom >= 18`, `lodash >= 4`
## Related Packages
| Package | Role |
| ------------------------ | ------------------------------------------------- |
| `@mezzanine-ui/core` | CSS styles and TypeScript type definitions |
| `@mezzanine-ui/icons` | SVG icon definitions (plain objects) |
| `@mezzanine-ui/system` | Design tokens: palette, spacing, typography, etc. |
## Import Patterns
Individual component (preferred for tree-shaking):
```ts
import Button from '@mezzanine-ui/react/Button';
import Select from '@mezzanine-ui/react/Select';
```
Named exports from the barrel (hooks, types, utilities):
```ts
import { usePagination, useCheckboxControlValue, cx } from '@mezzanine-ui/react';
import type { ButtonProps, ButtonVariant } from '@mezzanine-ui/react';
```
Sub-path imports for component groups and core types:
```ts
// Navigation sub-components
import {
NavigationFooter,
NavigationHeader,
NavigationOption,
NavigationIconButton,
NavigationUserMenu,
} from '@mezzanine-ui/react/Navigation';
// ContentHeader (deprecated — sub-path import only, not in main barrel export)
// import ContentHeader from '@mezzanine-ui/react/ContentHeader';
// Form layout tokens from core (used with FormField)
import {
ControlFieldSlotLayout,
FormFieldLayout,
FormFieldLabelSpacing,
} from '@mezzanine-ui/core/form';
```
Spacing helpers in SCSS (from `@mezzanine-ui/system/spacing`):
```scss
@use '@mezzanine-ui/system/spacing';
.host {
padding: spacing.semantic-variable(padding, vertical, spacious)
spacing.semantic-variable(padding, horizontal, comfort-fixed);
row-gap: spacing.semantic-variable(gap, calm);
}
```
Required styles — create a `main.scss` and import it at your app entry point. All component styles are loaded at once via `@include mzn-core.styles()`:
```scss
@use '@mezzanine-ui/system' as mzn-system;
@use '@mezzanine-ui/core' as mzn-core;
:root {
@include mzn-system.common-variables('default');
@include mzn-system.colors();
}
/* Optional: light/dark palette theming */
:root { @include mzn-system.colors(light); }
[data-theme='dark'] { @include mzn-system.colors(dark); }
/* Optional: compact density */
[data-density='compact'] { @include mzn-system.common-variables(compact); }
@include mzn-core.styles();
```
> **Note:** The `~` prefix (e.g. `~@mezzanine-ui/core`) was required by older webpack 4 + sass-loader setups. Modern tooling (Next.js 13+, Vite) resolves node_modules without it — use bare paths as shown above.
## Component Categories
- **General** — Button, ButtonGroup, Cropper, Icon, Layout, Separator, Typography
- **Navigation** — Breadcrumb, Drawer, Navigation (+ sub-components), PageHeader, PageFooter, Stepper, Tab
- **Data Display** — Accordion, Badge, Cards (BaseCard, FourThumbnailCard, SingleThumbnailCard, QuickActionCard), Description, Empty, Pagination, Table, Tag, Tooltip
- **Data Entry** — AutoComplete, Checkbox, DatePicker, DateRangePicker, DateTimePicker, FilterArea, FormField, Input, Radio, Select, Slider, Toggle, Textarea, TimePicker, Upload, Cascader
- **Feedback** — InlineMessage, Message, Modal, NotificationCenter, Progress, ResultState, Skeleton, Spin
- **Others** — AlertBanner, Anchor, Backdrop, FloatingButton
- **Utility** — Calendar, Dropdown, Popper, Portal, TimePanel, Transition animations (Collapse, Fade, Rotate, Scale, Slide, Translate)
## Key Design Patterns
**Polymorphic `component` prop** — most components accept a `component` prop to override the rendered HTML element or pass a router link component:
```tsx
```
**Controlled/uncontrolled with control hooks** — pair components with their corresponding hook:
```tsx
const [value, onChange] = useCheckboxControlValue({ defaultValue: [] });
```
Available control hooks: `useAutoCompleteValueControl`, `useCheckboxControlValue`, `useInputControlValue`, `useInputWithClearControlValue`, `useRadioControlValue`, `useSelectValueControl`, `useSwitchControlValue`, `useCustomControlValue`.
**Portal-based overlays** — Modal, Drawer, and Tooltip render outside the component tree via `Portal`. Use the `container` prop to target a specific DOM node.
**Calendar adapter pattern** — Calendar components require wrapping the app with a date-adapter provider. Import from the library-specific entry point to avoid bundling unused date libraries:
```tsx
// Day.js (recommended)
import { CalendarConfigProviderDayjs, CalendarLocale } from '@mezzanine-ui/react/dayjs';
{children}
// Moment.js
import { CalendarConfigProviderMoment, CalendarLocale } from '@mezzanine-ui/react/moment';
// Luxon
import { CalendarConfigProviderLuxon, CalendarLocale } from '@mezzanine-ui/react/luxon';
```
**forwardRef** — all components forward their ref to the underlying DOM element.
**React Hook Form integration** — the recommended pattern is a `BaseField` wrapper that combines `FormField` with RHF's `formState.errors` for automatic error display. `ControlFieldSlotLayout.SUB` aligns the hint/error message with the input:
```tsx
import { useFormContext, get } from 'react-hook-form';
import FormField from '@mezzanine-ui/react/Form/FormField';
import { ControlFieldSlotLayout, FormFieldLayout } from '@mezzanine-ui/core/form';
function BaseField({ name, label, required, disabled, children }) {
const { formState } = useFormContext();
const error = get(formState.errors, name);
return (
{children}
);
}
```
**Message imperative API** — `Message` is a global singleton for toast notifications. Call it imperatively without rendering any JSX:
```tsx
import { Message } from '@mezzanine-ui/react';
Message.success('儲存成功');
Message.warning('請確認輸入資料');
Message.error('操作失敗,請稍後再試');
```
**Select inside Modal** — when rendering a `Select` (or `AutoComplete`) inside a `Modal` or `Drawer`, pass `dropdownZIndex` higher than the overlay (default modal z-index is ~1000):
```tsx
```
## Common Pitfalls for AI Assistants
**Typography `variant` only has h1–h3, not h4–h6.** The prop type is `TypographySemanticType` — a design-system semantic scale, not HTML heading levels. The complete set of valid values is:
| Group | Variants |
|-------|---------|
| Heading | `h1`, `h2`, `h3` |
| Body | `body`, `body-highlight`, `body-mono`, `body-mono-highlight` |
| Text link | `text-link-body`, `text-link-caption` |
| Caption | `caption`, `caption-highlight` |
| Annotation | `annotation`, `annotation-highlight` |
| Button | `button`, `button-highlight` |
| Input | `input`, `input-mono`, `input-highlight` |
| Label | `label-primary`, `label-primary-highlight`, `label-secondary` |
Never use `h4`, `h5`, or `h6` — they do not exist.
```tsx
Title // ✅
Bold // ✅
Link // ✅
Subtitle // ❌ h5 does not exist
```
**Button icons use `icon` + `iconType`, not `prefix`/`suffix` JSX.** Pass an icon definition object (from `@mezzanine-ui/icons`) to the `icon` prop and set position via `iconType`: `"leading"` | `"trailing"` | `"icon-only"`. Do not wrap `` in `prefix` or `suffix` props — those props do not exist on Button.
```tsx
import { PlusIcon } from '@mezzanine-ui/icons';
// ✅
}>新增 // ❌ prefix does not exist
```
**`TextField` is a low-level layout container, not a full form field.** It renders the border/background/affix shell around an `` but does not include a label, hint text, or error message. For a complete labeled form field, use `FormField` (which wraps `TextField` + `Input` + label + validation message).
```tsx
// Full labeled form field:
```
## Further Reference
- Full component index with descriptions: `packages/react/COMPONENTS.md`
- Common UI pattern examples (Layout, Form, Table, Dialog, etc.): `packages/react/PATTERNS.md`
- Complete prop types and JSDoc: `*.d.ts` files in the published package (or `packages/react/src//index.tsx`)
- GitHub: https://github.com/Mezzanine-UI/mezzanine