)
│ │ └── Table.Cell ()
│ └── Table.LoadMore (optional, infinite scroll)
│ └── Table.LoadMoreContent
└── Table.Footer (optional, pagination, etc.)
```
## Item Identity
**v2:** React's `key` was used for both list reconciliation and selection state.
**v3:** Use `id` on `Table.Row` and `Table.Column` for selection/sort state; keep React's `key` for lists.
## Summary
1. **Imports**: Separate named imports → single `Table` import with dot notation
2. **New Wrappers**: `Table.ScrollContainer` and `Table.Content` wrap the table structure
3. **Props Moved**: `aria-label`, `selectionMode`, `sortDescriptor`, etc. moved from `Table` to `Table.Content`
4. **Bottom Content**: `bottomContent` prop → `Table.Footer` compound component
5. **Top Content**: `topContent` prop → place content inside `Table` before `Table.ScrollContainer`
6. **Selection Checkboxes**: Auto-rendered → explicit `Checkbox` with `slot="selection"`
7. **Empty State**: `emptyContent` prop → `renderEmptyState` on `Table.Body`
8. **Loading**: `loadingState`/`loadingContent` → `Table.LoadMore` for infinite scroll
9. **Column Resizing**: New `Table.ResizableContainer` and `Table.ColumnResizer`
10. **Item Identity**: `key` → `id` on rows and columns
11. **Styling Props Removed**: `color`, `radius`, `shadow`, `isStriped`, `isCompact` → use Tailwind CSS
12. **ClassNames Removed**: Use `className` on individual compound components
# Tabs
**Category**: react
**URL**: https://heroui.com/en/docs/react/migration/tabs
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/react/migration/(components)/tabs.mdx
> Migration guide for Tabs from HeroUI v2 to v3
Refer to the [v3 Tabs documentation](/docs/react/components/tabs) for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.
## Structure Changes
In v2, Tabs used `Tab` component with `title` prop and children as panel content:
```tsx
import { Tabs, Tab } from "@heroui/react";
export default function App() {
return (
Content here
);
}
```
In v3, Tabs requires compound components with separate tab and panel:
```tsx
import { Tabs } from "@heroui/react";
export default function App() {
return (
Photos
Content here
);
}
```
## Key Changes
### 1. Component Structure
**v2:** `Tabs` with `Tab` children (title prop + children as panel)\
**v3:** Compound components (`Tabs.ListContainer`, `Tabs.List`, `Tabs.Tab`, `Tabs.Indicator`, `Tabs.Separator`, `Tabs.Panel`)
### 2. Prop Changes
| v2 Prop | v3 Location | Notes |
| ------------------------ | ----------------------- | ---------------------------------------------- |
| `key` (on Tab) | `id` (on Tab and Panel) | Changed prop name |
| `title` (on Tab) | — | Content goes directly in `Tabs.Tab` |
| `isVertical` | `orientation` | Changed to `"horizontal"` \| `"vertical"` |
| `placement` | — | Use `orientation` and layout |
| `variant` | `variant` | Simplified to `primary` \| `secondary` only |
| `color` | — | Removed (use Tailwind CSS) |
| `size` | — | Removed (use Tailwind CSS) |
| `radius` | — | Removed (use Tailwind CSS) |
| `classNames` | — | Use `className` props on individual components |
| `disableCursorAnimation` | — | Use `Tabs.Indicator` component |
| `disableAnimation` | — | Removed (animations handled differently) |
| `fullWidth` | — | Removed (use Tailwind CSS) |
### 3. Component Changes
* **Tab identification**: `key` → `id` (must match between `Tabs.Tab` and `Tabs.Panel`)
* **Tab content**: `title` prop → direct children in `Tabs.Tab`
* **Panel content**: Tab children → separate `Tabs.Panel` component
* **Indicator**: Automatic cursor → explicit `Tabs.Indicator` component
* **Separator**: New `Tabs.Separator` component to display separator lines between tabs
## Migration Examples
### Controlled Tabs
```tsx
import { useState } from "react";
const [selected, setSelected] = useState("photos");
Content
Content
```
```tsx
import { useState } from "react";
const [selected, setSelected] = useState("photos");
Photos
Music
Content
Content
```
### With Icons
```tsx
Photos>}>
Content
```
```tsx
Photos
Content
```
### With Separator
In v3, you can add `Tabs.Separator` inside each `Tabs.Tab` (except the first) to display separator lines between tabs. This is a new feature with no v2 equivalent.
```tsx
Photos
Music
Videos
Photos content
Music content
Videos content
```
## Component Anatomy
The v3 Tabs follows this structure:
```
Tabs (Root)
├── Tabs.ListContainer
│ └── Tabs.List
│ └── Tabs.Tab
│ ├── Tabs.Separator (optional, omit on first tab)
│ └── Tabs.Indicator (optional)
└── Tabs.Panel (one per tab, matching id)
```
## Summary
1. **Component Structure**: Must use compound components (`Tabs.ListContainer`, `Tabs.List`, `Tabs.Tab`, `Tabs.Indicator`, `Tabs.Separator`, `Tabs.Panel`)
2. **Tab Identification**: `key` → `id` (must match between tab and panel)
3. **Tab Content**: `title` prop removed - content goes directly in `Tabs.Tab`
4. **Panel Separation**: Panel content moved to separate `Tabs.Panel` component
5. **Indicator**: Must explicitly include `Tabs.Indicator` in each tab
6. **Orientation**: `isVertical` → `orientation` prop
7. **Styling**: `variant` simplified to `primary` | `secondary`; `color`, `size`, `radius`, `placement` removed - use Tailwind for more
8. **ClassNames Removed**: Use `className` props on individual components
9. **Separator (New)**: Use `Tabs.Separator` inside `Tabs.Tab` to display separator lines between tabs (no v2 equivalent)
# TimeInput
**Category**: react
**URL**: https://heroui.com/en/docs/react/migration/timeinput
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/react/migration/(components)/timeinput.mdx
> Migration guide for TimeInput to TimeField from HeroUI v2 to v3
Refer to the [v3 TimeField documentation](/docs/react/components/time-field) for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.
## Structure Changes
In v2, TimeInput was a single component with props:
```tsx
import { TimeInput } from "@heroui/react";
export default function App() {
return ;
}
```
In v3, TimeField requires compound components with DateInputGroup and a render prop for segments:
```tsx
import { TimeField, DateInputGroup, Label } from "@heroui/react";
export default function App() {
return (
Time
{(segment) => }
);
}
```
## Key Changes
### 1. Component Naming
**v2:** `TimeInput`\
**v3:** `TimeField`
### 2. Component Structure
**v2:** Single component with props\
**v3:** Compound components: `TimeField` (root) + `DateInputGroup` with `DateInputGroup.Input` (render prop) and `DateInputGroup.Segment`; optionally `DateInputGroup.Prefix` and `DateInputGroup.Suffix`
### 3. Prop Changes
| v2 Prop | v3 Location | Notes |
| ------------------------------------------------------------- | ------------------------------- | --------------------------------------------------------- |
| `label` | — | Use `Label` component |
| `description` | — | Use `Description` component |
| `errorMessage` | — | Use `FieldError` component |
| `value`, `defaultValue`, `onChange` | `TimeField` | Same (React Aria) |
| `minValue`, `maxValue`, `granularity`, `placeholderValue` | `TimeField` | Same |
| `isRequired`, `isDisabled`, `isReadOnly`, `isInvalid`, `name` | `TimeField` | Same |
| `validationBehavior`, `shouldForceLeadingZeros` | `TimeField` | Same |
| `variant` | `DateInputGroup` | Simplified to `primary` \| `secondary` only |
| `fullWidth` | `TimeField` or `DateInputGroup` | On root or group |
| `color` | — | Removed (use Tailwind CSS) |
| `size` | — | Removed (use Tailwind CSS) |
| `radius` | — | Removed (use Tailwind CSS) |
| `labelPlacement` | — | Handle with layout |
| `startContent` | `DateInputGroup.Prefix` | Use Prefix child |
| `endContent` | `DateInputGroup.Suffix` | Use Suffix child |
| `classNames` | — | Use `className` on `TimeField` and `DateInputGroup` parts |
| `groupProps` | — | Use `className` or DOM props on `DateInputGroup` |
| `labelProps` | — | Use `className` on `Label` |
| `fieldProps` | — | Use `className` on `DateInputGroup` |
| `innerWrapperProps` | — | Use `className` on group/input parts |
| `descriptionProps` | — | Use `className` on `Description` |
| `errorMessageProps` | — | Use `className` on `FieldError` |
| `inputRef` | — | Ref handled by `TimeField` / React Aria |
## Migration Examples
### With Description and Error
```tsx
```
```tsx
import { Description, FieldError, Label } from "@heroui/react";
Start time
{(segment) => }
Select start time
Time
{(segment) => }
Please enter a valid time
```
### Controlled
```tsx
import { parseTime } from "@internationalized/date";
import { useState } from "react";
const [value, setValue] = useState(null);
```
```tsx
import type { TimeValue } from "@internationalized/date";
import { useState } from "react";
const [value, setValue] = useState(null);
Time
{(segment) => }
```
### Min/Max and Granularity
```tsx
import { parseTime } from "@internationalized/date";
```
```tsx
import { parseTime } from "@internationalized/date";
Time
{(segment) => }
```
### Start/End Content
```tsx
}
label="Time"
name="time"
startContent={ }
/>
```
```tsx
Time
{(segment) => }
```
## Component Anatomy
The v3 TimeField follows this structure:
```
TimeField (Root)
├── Label (optional)
├── DateInputGroup
│ ├── DateInputGroup.Prefix (optional)
│ ├── DateInputGroup.Input → (segment) => DateInputGroup.Segment
│ └── DateInputGroup.Suffix (optional)
├── Description (optional)
└── FieldError (optional)
```
## Summary
1. **Component Renamed**: `TimeInput` → `TimeField`
2. **Component Structure**: Must use compound components: `TimeField` (root) and `DateInputGroup` with `DateInputGroup.Input` (render prop) and `DateInputGroup.Segment`
3. **Label/Description/Error**: Use separate components (`Label`, `Description`, `FieldError`)
4. **Time Props Unchanged**: `value`, `defaultValue`, `onChange`, `minValue`, `maxValue`, `granularity`, `placeholderValue`, `isRequired`, `isDisabled`, `isInvalid`, `name`, `validationBehavior`, `shouldForceLeadingZeros` stay on `TimeField`
5. **Variant on DateInputGroup**: v3 supports only `variant="primary"` and `variant="secondary"` on `DateInputGroup`; `color`, `size`, `radius` removed — use Tailwind CSS
6. **Start/End Content**: `startContent`/`endContent` → `DateInputGroup.Prefix` and `DateInputGroup.Suffix`
7. **Label Placement Removed**: `labelPlacement` removed — handle with layout
8. **DOM/Class Props**: `groupProps`, `labelProps`, `fieldProps`, `classNames` removed — use `className` (and standard DOM props) on the relevant parts
# Toast
**Category**: react
**URL**: https://heroui.com/en/docs/react/migration/toast
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/react/migration/(components)/toast.mdx
> Migration guide for Toast from HeroUI v2 to v3
Refer to the [v3 Toast documentation](/docs/react/components/toast) for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.
## Structure Changes
In v2, Toast used a provider and hook pattern:
```tsx
import { ToastProvider, useToast } from "@heroui/react";
function App() {
return (
);
}
function MyComponent() {
const { toast } = useToast();
return (
toast.show("Hello!")}>
Show Toast
);
}
```
In v3, Toast uses a provider component and a global `toast()` function:
```tsx
import { Toast } from "@heroui/react";
function App() {
return (
<>
>
);
}
function MyComponent() {
return (
toast("Hello!")}>
Show Toast
);
}
```
## Key Changes
### 1. Provider Pattern
**v2:** Required `ToastProvider` wrapper\
**v3:** Uses `Toast.Provider` component (can be placed anywhere)
### 2. Hook → Function
**v2:** Used `useToast()` hook\
**v3:** Uses `toast()` function directly
### 3. API Changes
**v2:** Used `toast.show()` method\
**v3:** `toast()` is a function with helper methods (`toast.success()`, `toast.danger()`, etc.)
### 4. Variant Names
**v2:** Variants like `success`, `error`, `warning`, `info`\
**v3:** Variants: `default`, `accent`, `success`, `warning`, `danger`
### 5. Compound Component Structure
**v3:** Toast uses compound components for custom rendering:
* `Toast` - Main toast container
* `Toast.Content` - Content wrapper
* `Toast.Title` - Title text
* `Toast.Description` - Description text
* `Toast.Indicator` - Icon/indicator
* `Toast.CloseButton` - Close button
* `Toast.ActionButton` - Action button
### 6. Promise Support
**v3:** Built-in promise support with `toast.promise()` for handling async operations
## Migration Examples
### Toast with Title and Description
```tsx
const { toast } = useToast();
toast.show({
title: "Success",
description: "Your changes have been saved",
variant: "success"
});
```
```tsx
import { toast } from "@heroui/react";
toast.success("Success", {
description: "Your changes have been saved"
});
```
### Helper Methods for Variants
```tsx
const { toast } = useToast();
toast.show({ variant: "success", title: "Success" });
toast.show({ variant: "error", title: "Error" });
toast.show({ variant: "warning", title: "Warning" });
toast.show({ variant: "info", title: "Info" });
```
```tsx
import { toast } from "@heroui/react";
toast.success("Success");
toast.danger("Error");
toast.warning("Warning");
toast.info("Info");
```
### Promise Support
```tsx
const { toast } = useToast();
const handleAsync = async () => {
try {
await someAsyncOperation();
toast.show({ title: "Success", variant: "success" });
} catch {
toast.show({ title: "Error", variant: "error" });
}
};
```
```tsx
import { toast } from "@heroui/react";
const handleAsync = async () => {
toast.promise(someAsyncOperation(), {
loading: "Processing...",
success: "Operation completed!",
error: "Operation failed"
});
};
```
### Custom Toast Rendering
```tsx
const { toast } = useToast();
toast.show({
title: "Custom",
render: (toast) => (
Custom content
)
});
```
```tsx
import { Toast, ToastContent, ToastTitle } from "@heroui/react";
{({ toast: toastItem }) => (
Custom content
)}
```
## Summary
* Replace `ToastProvider` with `Toast.Provider`
* Replace `useToast()` hook with `toast()` function
* Update variant names (`error` → `danger`, `info` → `accent`)
* Use helper methods: `toast.success()`, `toast.danger()`, etc.
* Use `toast.promise()` for async operations
* Compound component structure for custom rendering
* Better TypeScript support and queue management
# Tooltip
**Category**: react
**URL**: https://heroui.com/en/docs/react/migration/tooltip
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/react/migration/(components)/tooltip.mdx
> Migration guide for Tooltip from HeroUI v2 to v3
Refer to the [v3 Tooltip documentation](/docs/react/components/tooltip) for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.
## Structure Changes
In v2, Tooltip used a `content` prop:
```tsx
import { Tooltip, Button } from "@heroui/react";
export default function App() {
return (
Hover me
);
}
```
In v3, Tooltip requires compound components:
```tsx
import { Tooltip, Button } from "@heroui/react";
export default function App() {
return (
Hover me
I am a tooltip
);
}
```
## Key Changes
### 1. Component Structure
**v2:** Simple Tooltip with `content` prop and children as trigger\
**v3:** Compound components (`Tooltip.Trigger`, `Tooltip.Content`, `Tooltip.Arrow`)
### 2. Prop Changes
| v2 Prop | v3 Location | Notes |
| --------------------------------- | ------------------------ | -------------------------------------------------------- |
| `content` | — | Use `Tooltip.Content` children |
| `showArrow` | `showArrow` (on Content) | Moved to `Tooltip.Content` |
| `placement` | `placement` (on Content) | Moved to `Tooltip.Content` |
| `offset` | `offset` (on Content) | Moved to `Tooltip.Content` |
| `color` | — | Removed (use Tailwind CSS) |
| `size` | — | Removed (use Tailwind CSS) |
| `radius` | — | Removed (use Tailwind CSS) |
| `shadow` | — | Removed (use Tailwind CSS) |
| `classNames` | — | Use `className` props on individual components |
| `motionProps` | — | Removed (animations handled differently) |
| `trigger` | `trigger` (on root) | Still exists: `"hover"` \| `"focus"` (default `"hover"`) |
| `isDisabled` | `isDisabled` (on root) | New in v3: disables the tooltip entirely |
| `delay` | `delay` (on root) | Still exists (default changed from `0` to `700`) |
| `closeDelay` | `closeDelay` (on root) | Still exists (default `0`) |
| `portalContainer` | — | Not exposed |
| `updatePositionDeps` | — | Not exposed |
| `containerPadding`, `crossOffset` | — | Not exposed |
| `shouldFlip` | — | Handled automatically |
| `triggerScaleOnOpen` | — | Not available |
| `isKeyboardDismissDisabled` | — | Not available |
| `isDismissable` | — | Not available |
| `shouldCloseOnBlur` | — | Not available |
| `shouldCloseOnInteractOutside` | — | Not available |
| `onClose` | — | Use `onOpenChange` instead |
### 3. Props Moved to Tooltip.Content
* `showArrow` - Now on `Tooltip.Content`
* `placement` - Now on `Tooltip.Content`
* `offset` - Now on `Tooltip.Content`
## Migration Examples
### Content Configuration
```tsx
{/* With arrow */}
Hover me
{/* With placement */}
Hover me
{/* With offset */}
Hover me
```
```tsx
{/* With arrow */}
Hover me
I am a tooltip
{/* With placement */}
Hover me
Tooltip
{/* With offset */}
Hover me
Tooltip
```
### Controlled Tooltip
```tsx
import { useState } from "react";
const [isOpen, setIsOpen] = useState(false);
Hover me
```
```tsx
import { useState } from "react";
const [isOpen, setIsOpen] = useState(false);
Hover me
I am a tooltip
```
### With Delay
```tsx
Hover me
```
```tsx
Hover me
Tooltip
```
### Custom Content
```tsx
Title
Description
}
>
Hover me
```
```tsx
Hover me
```
### With Custom Trigger
```tsx
Custom trigger
```
```tsx
Custom trigger
Tooltip
```
## Component Anatomy
The v3 Tooltip follows this structure:
```
Tooltip (Root)
├── Tooltip.Trigger
│ └── [Trigger element]
└── Tooltip.Content
├── Tooltip.Arrow (optional)
└── [Tooltip content]
```
## New Props in v3
### isDisabled
The `isDisabled` prop allows you to completely disable the tooltip. When disabled, the tooltip will not appear on hover or focus:
```tsx
No tooltip
This will not show
```
### trigger
The `trigger` prop controls how the tooltip is activated. It accepts `"hover"` (default) or `"focus"`:
```tsx
{/* Show tooltip only on focus */}
Focus me
Shown on focus only
```
### Custom Render Function
`Tooltip.Content` and `Tooltip.Arrow` both support a `render` prop that allows you to override the default DOM element with a custom render function for advanced use cases.
## Important Notes
### Content Prop
* **v2:** Used `content` prop for tooltip text/content
* **v3:** Content goes as children of `Tooltip.Content` component
### Arrow
* **v2:** Controlled by `showArrow` prop on root
* **v3:** Use `showArrow` prop on `Tooltip.Content` and include `Tooltip.Arrow` component
### Placement and Offset
* **v2:** `placement` and `offset` props on root
* **v3:** `placement` and `offset` props moved to `Tooltip.Content`
### Trigger Element
* **v2:** Children were automatically used as trigger
* **v3:** Must wrap trigger element in `Tooltip.Trigger` component
### Default Delay
* **v2:** `delay` default was `0`
* **v3:** `delay` default is `700` (note: examples use `delay={0}` to match v2 behavior)
## Summary
1. **Component Structure**: Must use compound components (`Tooltip.Trigger`, `Tooltip.Content`, `Tooltip.Arrow`)
2. **Content Prop Removed**: `content` prop removed - use `Tooltip.Content` children
3. **Props Moved**: `showArrow`, `placement`, `offset` moved to `Tooltip.Content`
4. **Styling Props Removed**: `color`, `size`, `radius`, `shadow` - use Tailwind CSS
5. **ClassNames Removed**: Use `className` props on individual components
6. **Motion Props Removed**: `motionProps` removed - animations handled differently
7. **Advanced Props Removed**: Many positioning and behavior props removed
8. **Default Delay Changed**: Default delay changed from `0` to `700`
9. **isDisabled Prop**: New `isDisabled` prop to completely disable the tooltip
10. **trigger Prop**: Accepts `"hover"` (default) or `"focus"` to control activation method
11. **Render Props**: `Tooltip.Content` and `Tooltip.Arrow` support a `render` prop for custom DOM rendering
# User
**Category**: react
**URL**: https://heroui.com/en/docs/react/migration/user
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/react/migration/(components)/user.mdx
> Migration guide for User from HeroUI v2 to v3
The User component has been **removed** in HeroUI v3. Compose user displays manually using Avatar and text elements with Tailwind CSS classes.
## Key Changes
### 1. Component Removal
**v2:** `` component from `@heroui/react`\
**v3:** Manual composition using `Avatar` + text elements
### 2. Features Mapping
The v2 User component had the following features that need to be replaced:
| v2 Feature | v3 Equivalent | Notes |
| ------------------ | --------------------- | ----------------------------------------- |
| `name` prop | Text element | Render name as text or heading |
| `description` prop | Text element | Render description as text |
| `avatarProps` prop | `Avatar` component | Use v3 Avatar component directly |
| `isFocusable` prop | Manual focus handling | Add `tabIndex` and focus styles if needed |
| `classNames` prop | Tailwind classes | Apply classes directly to elements |
## Structure Changes
### v2: User Component
In v2, `User` was a convenience component combining Avatar with name:
```tsx
import { User } from "@heroui/react";
export default function App() {
return (
);
}
```
### v3: Manual Composition
In v3, compose user displays manually using Avatar and text elements:
```tsx
import { Avatar } from "@heroui/react";
export default function App() {
return (
);
}
```
## Migration Examples
### With Description
```tsx
import { User } from "@heroui/react";
```
```tsx
import { Avatar } from "@heroui/react";
JG
Junior Garcia
Software Engineer
```
### With Default Avatar (Initials)
```tsx
import { User } from "@heroui/react";
name
.split(" ")
.map((n) => n[0])
.join(""),
}}
/>
```
```tsx
import { Avatar } from "@heroui/react";
function getInitials(name: string) {
return name
.split(" ")
.map((n) => n[0])
.join("");
}
{getInitials("Junior Garcia")}
Junior Garcia
```
### With Link Description
```tsx
import { User, Link } from "@heroui/react";
@jrgarciadev
}
avatarProps={{
src: "https://example.com/avatar.jpg",
}}
/>
```
```tsx
import { Avatar, Link } from "@heroui/react";
JG
Junior Garcia
@jrgarciadev
```
### Clickable User
```tsx
import { User } from "@heroui/react";
{/* Focusable */}
{/* As button */}
```
```tsx
import { Avatar } from "@heroui/react";
{/* Focusable */}
JG
Junior Garcia
{/* As button */}
JG
Junior Garcia
```
## Creating a Reusable User Component (Recommended)
Since User displays are commonly needed, here's a reusable component:
```tsx
import { User } from "@heroui/react";
```
```tsx
import { Avatar, Link } from "@heroui/react";
import { ReactNode } from "react";
import { cn } from "@/lib/utils"; // or your cn utility
interface UserProps {
name: string | ReactNode;
description?: string | ReactNode;
avatarSrc?: string;
avatarAlt?: string;
avatarFallback?: string;
className?: string;
isFocusable?: boolean;
as?: "div" | "button" | "a";
href?: string;
onClick?: () => void;
}
function getInitials(name: string): string {
return name
.split(" ")
.map((n) => n[0])
.join("")
.toUpperCase()
.slice(0, 2);
}
export function User({
name,
description,
avatarSrc,
avatarAlt,
avatarFallback,
className,
isFocusable = false,
as = "div",
href,
onClick,
}: UserProps) {
const Component = as === "a" ? "a" : as === "button" ? "button" : "div";
const fallback = avatarFallback || (typeof name === "string" ? getInitials(name) : "?");
const content = (
<>
{avatarSrc && (
)}
{fallback}
{name}
{description && (
{description}
)}
>
);
const baseClasses = cn(
"inline-flex items-center gap-2 rounded-sm outline-none",
isFocusable && "focus-visible:ring-2 focus-visible:ring-focus",
className
);
if (Component === "button") {
return (
{content}
);
}
if (Component === "a") {
return (
{content}
);
}
return (
{content}
);
}
// Usage
```
## Styling Reference
The v2 User component used these base styles that you should replicate:
* **Base container**: `inline-flex items-center gap-2 rounded-sm`
* **Wrapper (for name/description)**: `inline-flex flex-col items-start`
* **Name**: `text-sm` (text-small)
* **Description**: `text-xs text-muted` (text-tiny text-foreground-400)
## Summary
1. **Component Removed**: `User` component no longer exists in v3
2. **Import Change**: Remove `import { User } from "@heroui/react"`
3. **Manual Composition**: Compose using Avatar + text elements
4. **Avatar Changes**: Use v3 Avatar compound component pattern
5. **Styling**: Apply Tailwind CSS classes directly
6. **Focus Handling**: Implement focus styles manually if needed
## Migration Steps
1. **Remove Import**: Remove `User` from `@heroui/react` imports
2. **Replace Component**: Replace all `` instances with manual composition
3. **Use Avatar**: Use v3 Avatar component with compound pattern
4. **Add Text Elements**: Add name and description as text elements
5. **Apply Styling**: Use Tailwind CSS classes for layout and styling
6. **Handle Focus**: Add focus styles if `isFocusable` was used
7. **Optional**: Create reusable User component for your application
## Common Patterns
### User List
```tsx
{users.map((user) => (
{getInitials(user.name)}
{user.name}
{user.role && (
{user.role}
)}
))}
```
### Clickable User
```tsx
handleUserClick(user)}
>
{getInitials(user.name)}
{user.name}
{user.email}
```
# Button
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/button
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(buttons)/button.mdx
> Interactive component that triggers an action when pressed.
## Import
```tsx
import { Button } from 'heroui-native';
```
## Anatomy
```tsx
...
```
* **Button**: Main container that handles press interactions, animations, and variants. Renders string children as label or accepts compound components for custom layouts.
* **Button.Background**: Optional theme-aware background container rendered behind the button surface. Mounted automatically for the `secondary` and `tertiary` variants when the active theme registers default background content (e.g. `glass`). Replace or remove it via the `background` prop.
* **Button.Label**: Text content of the button. Inherits size and variant styling from parent Button context.
## Usage
### Basic Usage
The Button component accepts string children that automatically render as label.
```tsx
Basic Button
```
### With Compound Parts
Use Button.Label for explicit control over the label component.
```tsx
Click me
```
### With Icons
Combine icons with labels for enhanced visual communication.
```tsx
Add Item
Download
```
### Icon Only
Create square icon-only buttons using the isIconOnly prop.
```tsx
```
### Sizes
Control button dimensions with three size options.
```tsx
Small
Medium
Large
```
### Variants
Choose from seven visual variants for different emphasis levels.
```tsx
Primary
Secondary
Tertiary
Outline
Ghost
Danger
Danger Soft
```
### Feedback Variants
The `feedbackVariant` prop controls which press feedback effects are rendered:
* `'scale-highlight'` (default): Built-in scale + highlight overlay
* `'scale-ripple'`: Built-in scale + ripple overlay
* `'scale'`: Built-in scale only (no overlay)
* `'none'`: No feedback animations at all
```tsx
{/* Scale + Highlight (default) */}
Highlight Effect
{/* Scale + Ripple */}
Ripple Effect
{/* Scale only */}
Scale Only
{/* No feedback */}
No Feedback
```
### Custom Animation
The `animation` prop controls individual sub-animations. Its shape depends on the `feedbackVariant`.
```tsx
{/* Customize scale and highlight (default feedbackVariant) */}
Custom Highlight
{/* Customize scale and ripple */}
Custom Ripple
```
### Disable Individual Animations
Disable specific sub-animations by setting them to `false`:
```tsx
{/* Disable scale, keep highlight */}
No Scale
{/* Disable highlight, keep scale */}
No Highlight
{/* Disable both */}
No Animations
```
### Disable All Animations
Use `animation={false}` to disable all feedback, or `animation="disable-all"` for cascading disable:
```tsx
Disabled
Disable All (cascading)
```
### Loading State with Spinner
Transform button to loading state with spinner animation.
```tsx
const themeColorAccentForeground = useThemeColor('accent-foreground');
{
setIsDownloading(true);
setTimeout(() => {
setIsDownloading(false);
}, 3000);
}}
isIconOnly={isDownloading}
className="self-center"
>
{isDownloading ? (
) : (
'Download now'
)}
;
```
### Custom Background with LinearGradient
Add gradient backgrounds using absolute positioned elements. Use `feedbackVariant="none"` to disable the default highlight overlay, or use `feedbackVariant="scale-ripple"` for a custom ripple effect.
```tsx
import { Button, PressableFeedback } from 'heroui-native';
import { LinearGradient } from 'expo-linear-gradient';
import { StyleSheet } from 'react-native';
{/* Gradient with no feedback overlay */}
Gradient
{/* Gradient with custom ripple effect */}
Gradient with Ripple
```
## Example
```tsx
import { Button, useThemeColor } from 'heroui-native';
import { Ionicons } from '@expo/vector-icons';
import { View } from 'react-native';
export default function ButtonExample() {
const [
themeColorAccentForeground,
themeColorAccentSoftForeground,
themeColorDangerForeground,
themeColorDefaultForeground,
] = useThemeColor([
'accent-foreground',
'accent-soft-foreground',
'danger-foreground',
'default-foreground',
]);
return (
Add Item
Learn More
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/button.tsx).
## API Reference
### Button
Button extends all props from [PressableFeedback](./pressable-feedback) (except `animation`, which is redefined) with additional button-specific props.
| prop | type | default | description |
| ----------------- | --------------------------------------------------------------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `variant` | `'primary' \| 'secondary' \| 'tertiary' \| 'outline' \| 'ghost' \| 'danger' \| 'danger-soft'` | `'primary'` | Visual variant of the button |
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size of the button |
| `isIconOnly` | `boolean` | `false` | Whether the button displays an icon only (square aspect ratio) |
| `feedbackVariant` | `'scale-highlight' \| 'scale-ripple' \| 'scale' \| 'none'` | `'scale-highlight'` | Determines which feedback effects are rendered |
| `animation` | `ButtonAnimation` | - | Animation configuration (shape depends on `feedbackVariant`) |
| `background` | `React.ReactNode` | - | Background layer behind the button surface. `undefined` renders the theme-aware default for the `secondary` and `tertiary` variants; custom node replaces it; `null` removes it |
For inherited props including `isDisabled`, `className`, `children`, and all Pressable props, see [PressableFeedback API Reference](./pressable-feedback#api-reference).
#### ButtonAnimation
The `animation` prop is a discriminated union based on `feedbackVariant`. It follows the `AnimationRoot` control flow:
* `true` or `undefined`: Use default animations
* `false` or `"disabled"`: Disable all feedback animations
* `"disable-all"`: Cascade-disable all animations including child compound parts
* `object`: Custom configuration with sub-animation keys (see below)
**When `feedbackVariant="scale-highlight"` (default):**
| prop | type | default | description |
| ----------- | ---------------------------------------- | ------- | ------------------------------------------------------------- |
| `scale` | `PressableFeedbackScaleAnimation` | - | Scale animation config (`false` to disable) |
| `highlight` | `PressableFeedbackHighlightAnimation` | - | Highlight overlay config (`false` to disable) |
| `state` | `'disabled' \| 'disable-all' \| boolean` | - | Control animation state while keeping config (runtime toggle) |
**When `feedbackVariant="scale-ripple"`:**
| prop | type | default | description |
| -------- | ---------------------------------------- | ------- | ------------------------------------------------------------- |
| `scale` | `PressableFeedbackScaleAnimation` | - | Scale animation config (`false` to disable) |
| `ripple` | `PressableFeedbackRippleAnimation` | - | Ripple overlay config (`false` to disable) |
| `state` | `'disabled' \| 'disable-all' \| boolean` | - | Control animation state while keeping config (runtime toggle) |
**When `feedbackVariant="scale"`:**
| prop | type | default | description |
| ------- | ---------------------------------------- | ------- | ------------------------------------------------------------- |
| `scale` | `PressableFeedbackScaleAnimation` | - | Scale animation config (`false` to disable) |
| `state` | `'disabled' \| 'disable-all' \| boolean` | - | Control animation state while keeping config (runtime toggle) |
**When `feedbackVariant="none"`:**
Only `'disable-all'` is accepted as a string value. All feedback effects are disabled.
For detailed animation sub-types (`PressableFeedbackScaleAnimation`, `PressableFeedbackHighlightAnimation`, `PressableFeedbackRippleAnimation`), see [PressableFeedback API Reference](./pressable-feedback#api-reference).
### Button.Background
Absolute-fill container rendered behind the button surface. With no children, the active library theme decides the default content (e.g. a glass blur layer); pass children to host custom content with the same positioning and clipping.
| prop | type | default | description |
| -------------- | ----------------- | ------- | ---------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom content inside the background container |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard View props are supported |
### Button.Label
| prop | type | default | description |
| -------------- | ----------------- | ------- | ------------------------------------- |
| `children` | `React.ReactNode` | - | Content to be rendered as label |
| `className` | `string` | - | Additional CSS classes |
| `...TextProps` | `TextProps` | - | All standard Text props are supported |
## Hooks
### useButton
Hook to access the Button context values. Returns the button's size, variant, and disabled state.
```tsx
import { useButton } from 'heroui-native';
const { size, variant, isDisabled } = useButton();
```
#### Return Value
| property | type | description |
| ------------ | --------------------------------------------------------------------------------------------- | ------------------------------ |
| `size` | `'sm' \| 'md' \| 'lg'` | Size of the button |
| `variant` | `'primary' \| 'secondary' \| 'tertiary' \| 'outline' \| 'ghost' \| 'danger' \| 'danger-soft'` | Visual variant of the button |
| `isDisabled` | `boolean` | Whether the button is disabled |
**Note:** This hook must be used within a `Button` component. It will throw an error if called outside of the button context.
# CloseButton
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/close-button
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(buttons)/close-button.mdx
> Button component for closing dialogs, modals, or dismissing content.
## Import
```tsx
import { CloseButton } from 'heroui-native';
```
## Usage
### Basic Usage
The CloseButton component renders a close icon button with default styling.
```tsx
```
### Custom Icon Color
Customize the icon color using the `iconProps` prop.
```tsx
```
### Custom Icon Size
Adjust the icon size using the `iconProps` prop.
```tsx
```
### Custom Children
Replace the default close icon with custom content.
```tsx
```
### Disabled State
Disable the button to prevent interactions.
```tsx
```
## Example
```tsx
import { CloseButton, useThemeColor } from 'heroui-native';
import { Ionicons } from '@expo/vector-icons';
import { View } from 'react-native';
import { withUniwind } from 'uniwind';
const StyledIonicons = withUniwind(Ionicons);
export default function CloseButtonExample() {
const themeColorForeground = useThemeColor('foreground');
const themeColorDanger = useThemeColor('danger');
return (
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/close-button.tsx).
## API Reference
### CloseButton
CloseButton extends all props from [Button](./button) component. It defaults to `variant='tertiary'`, `size='sm'`, and `isIconOnly=true`.
| prop | type | default | description |
| ----------- | ---------------------- | ------- | ------------------------------------------------ |
| `iconProps` | `CloseButtonIconProps` | - | Props for customizing the close icon |
| `children` | `React.ReactNode` | - | Custom content to replace the default close icon |
For inherited props including `isDisabled`, `className`, `animation`, `feedbackVariant` and all Pressable props, see [Button API Reference](./button#api-reference).
#### CloseButtonIconProps
| prop | type | default | description |
| ------- | -------- | ---------------------- | ----------------- |
| `size` | `number` | `20` | Size of the icon |
| `color` | `string` | Uses theme muted color | Color of the icon |
# LinkButton
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/link-button
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(buttons)/link-button.mdx
> A ghost-variant button with no highlight feedback, designed for inline link-style interactions.
## Import
```tsx
import { LinkButton } from 'heroui-native';
```
## Anatomy
```tsx
...
```
* **LinkButton**: Root pressable container. Renders a `Button` with the `ghost` variant and disabled highlight feedback enforced internally. These cannot be overridden by consumers.
* **LinkButton.Label**: Text content of the link button. Inherits size and variant styling from the parent context.
## Usage
### Basic Usage
The LinkButton component renders inline link-style text that responds to press events.
```tsx
Learn more
```
### Sizes
Control the text size with the `size` prop.
```tsx
Small
Medium
Large
```
### Disabled State
Disable the link button to prevent interaction.
```tsx
Disabled link
```
### Custom Styling
Apply custom styles using the `className` prop on both root and label.
```tsx
Styled link
```
### Inline with Text
Place link buttons inline alongside regular text for terms, policies, or contextual navigation.
```tsx
I agree to the
Terms of Service
and
Privacy Policy
```
## Example
```tsx
import { Button, Checkbox, ControlField, LinkButton } from 'heroui-native';
import React from 'react';
import { Alert, View } from 'react-native';
export default function LinkButtonExample() {
const [isAgreed, setIsAgreed] = React.useState(false);
const handleTermsPress = () => Alert.alert('Terms', 'Navigate to Terms');
const handlePrivacyPress = () =>
Alert.alert('Privacy', 'Navigate to Privacy Policy');
return (
I agree to the
Terms of Service
and
Privacy Policy
Sign up
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/link-button.tsx).
## API Reference
### LinkButton
Extends all [Button](./button#button) props except `variant` (enforced as `ghost` internally).
**Behavioral overrides applied internally:**
| override | value | description |
| ----------- | ------------ | --------------------------------------------------- |
| `variant` | `ghost` | Always renders as a ghost button, cannot be changed |
| `highlight` | `false` | Highlight feedback is disabled, cannot be changed |
| `className` | `h-auto p-0` | Removes default button height and padding |
### LinkButton.Label
Equivalent to [Button.Label](./button#buttonlabel). Accepts the same props.
# Menu
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/menu
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(collections)/menu.mdx
> A floating context menu with positioning, selection groups, and multiple presentation modes.
## Import
```tsx
import { Menu, SubMenu } from 'heroui-native';
```
## Anatomy
```tsx
...
...
...
...
...
...
...
```
* **Menu**: Main container that manages open/close state, positioning, and provides context to child components.
* **Menu.Trigger**: Clickable element that toggles the menu visibility.
* **Menu.Portal**: Renders menu content in a portal layer above other content.
* **Menu.Overlay**: Optional background overlay to capture outside clicks and close the menu.
* **Menu.Content**: Container for menu content with two presentation modes: floating popover with positioning and collision detection, or bottom sheet modal.
* **Menu.Close**: Close button that dismisses the menu when pressed.
* **Menu.Label**: Non-interactive section heading text within the menu.
* **Menu.Group**: Groups menu items with optional selection state (none, single, multiple).
* **Menu.Item**: Pressable menu item with animated press feedback. Standalone or within a Group for selection.
* **Menu.ItemTitle**: Primary label text for a menu item.
* **Menu.ItemDescription**: Secondary description text for a menu item.
* **Menu.ItemIndicator**: Visual selection indicator (checkmark or dot) for a menu item.
* **SubMenu**: Root container that manages the expand/collapse state and provides animation context to children.
* **SubMenu.Background**: Absolute-fill layer that paints the sub-menu surface while it is open. Rendered automatically; replaceable via the `background` prop on `SubMenu`.
* **SubMenu.Trigger**: Pressable row that toggles the submenu open/closed. Styled like a regular menu item.
* **SubMenu.TriggerIndicator**: Animated chevron icon (default: chevron-right) that rotates when the submenu opens/closes. Place inside `SubMenu.Trigger`.
* **SubMenu.Content**: Absolutely positioned container that animates its height when the submenu opens/closes. Place `Menu.Item` elements inside.
## Usage
### Basic Usage
The Menu component uses compound parts to create a floating context menu.
```tsx
...
View Profile
Settings
```
### With Item Descriptions
Add secondary description text to menu items alongside titles.
```tsx
...
New file
Create a new file
Copy link
Copy the file link
```
### Single Selection
Use `Menu.Group` with `selectionMode="single"` to allow one selected item at a time.
```tsx
const [theme, setTheme] = useState>(() => new Set(['system']));
...
Appearance
Light
Dark
System
;
```
### Multiple Selection
Use `selectionMode="multiple"` to allow selecting multiple items simultaneously.
```tsx
const [textStyles, setTextStyles] = useState>(
() => new Set(['bold', 'italic'])
);
...
Text Style
Bold
Italic
Underline
;
```
### With SubMenu
Nest a `SubMenu` inside `Menu.Content` to reveal additional items on press.
```tsx
Editor Menu
New Space
Focus
Zen Mode
Reader Mode
Lock Tab
Heading 1
```
### Danger Variant
Use `variant="danger"` on a menu item for destructive actions.
```tsx
...
Edit
Delete
```
### Placements
Control where the menu appears relative to the trigger.
```tsx
...
Option A
Option B
```
### Bottom Sheet Presentation
Use `presentation="bottom-sheet"` to display menu content as a bottom sheet modal.
```tsx
...
Option A
Option B
```
### Dot Indicator
Use `variant="dot"` on `Menu.ItemIndicator` to show a filled circle instead of a checkmark.
```tsx
...
Left
Center
Right
```
## Example
```tsx
import type { MenuKey } from 'heroui-native';
import { Button, Menu, Separator } from 'heroui-native';
import { useState } from 'react';
import { Text, View } from 'react-native';
export default function MenuExample() {
const [textStyles, setTextStyles] = useState>(
() => new Set(['bold', 'italic'])
);
const [alignment, setAlignment] = useState>(
() => new Set(['left'])
);
return (
Styles
Text Style
Bold
⌘ B
Italic
⌘ I
Underline
⌘ U
Text Alignment
Left
Center
Right
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/menu.tsx).
## API Reference
### Menu
| prop | type | default | description |
| --------------- | ----------------------------- | ----------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | The content of the menu |
| `presentation` | `'popover' \| 'bottom-sheet'` | `'popover'` | Presentation mode for the menu content |
| `isOpen` | `boolean` | - | Controlled open state of the menu |
| `isDefaultOpen` | `boolean` | - | Open state when initially rendered (uncontrolled) |
| `isDisabled` | `boolean` | - | Whether the menu is disabled |
| `animation` | `MenuRootAnimation` | - | Animation configuration for menu root |
| `onOpenChange` | `(open: boolean) => void` | - | Callback fired when the menu open state changes |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### MenuRootAnimation
Animation configuration for menu root component. Can be:
* `"disable-all"`: Disable all animations including children
* `true` or `undefined`: Use default animations
### Menu.Trigger
| prop | type | default | description |
| ------------------- | ----------------- | ------- | ------------------------------------------------------- |
| `children` | `React.ReactNode` | - | The trigger element content |
| `className` | `string` | - | Additional CSS class for the trigger |
| `isDisabled` | `boolean` | `false` | Whether the trigger is disabled |
| `asChild` | `boolean` | - | Render as child element using Slot pattern |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported |
### Menu.Portal
| prop | type | default | description |
| -------------------------------------------- | ----------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | The portal content |
| `className` | `string` | - | Additional CSS class for the portal container |
| `disableFullWindowOverlay` | `boolean` | `false` | Use a regular View instead of FullWindowOverlay on iOS |
| `unstable_accessibilityContainerViewIsModal` | `boolean` | `false` | Controls whether VoiceOver treats the overlay window as a modal container. When `true`, VoiceOver is restricted to elements inside the overlay. iOS only. Unstable: may change with react-native-screens updates |
| `hostName` | `string` | - | Optional name of the host element for the portal |
| `forceMount` | `boolean` | - | Force mount the portal regardless of open state |
### Menu.Overlay
| prop | type | default | description |
| ----------------------- | ---------------------- | ------- | ------------------------------------------------------------ |
| `className` | `string` | - | Additional CSS class for the overlay |
| `closeOnPress` | `boolean` | `true` | Whether to close the menu when the overlay is pressed |
| `animation` | `MenuOverlayAnimation` | - | Animation configuration for overlay |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `forceMount` | `boolean` | - | Force mount the overlay regardless of open state |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported |
#### MenuOverlayAnimation
Animation configuration for menu overlay component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ------------------------ | ----------------------- | ----------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `opacity.entering.value` | `EntryOrExitLayoutType` | `FadeIn.duration(200)` | Custom entering animation for overlay |
| `opacity.exiting.value` | `EntryOrExitLayoutType` | `FadeOut.duration(150)` | Custom exiting animation for overlay |
### Menu.Content (Popover)
Props when `presentation="popover"`.
| prop | type | default | description |
| ----------------- | ------------------------------------------------ | --------------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | The menu content |
| `presentation` | `'popover'` | - | Presentation mode (must match Menu root) |
| `placement` | `'top' \| 'bottom' \| 'left' \| 'right'` | `'bottom'` | Where the menu appears relative to the trigger |
| `align` | `'start' \| 'center' \| 'end'` | `'center'` | Alignment of the menu relative to the trigger |
| `avoidCollisions` | `boolean` | `true` | Whether to reposition to avoid screen edges |
| `offset` | `number` | `9` | Distance from the trigger element in pixels |
| `alignOffset` | `number` | `0` | Offset along the alignment axis in pixels |
| `width` | `'content-fit' \| 'trigger' \| 'full' \| number` | `'content-fit'` | Content width sizing strategy |
| `className` | `string` | - | Additional CSS class for the content container |
| `animation` | `MenuContentAnimation` | - | Animation configuration for content |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### MenuContentAnimation
Animation configuration for menu popover content component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ---------------- | ----------------------- | ------------------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `entering.value` | `EntryOrExitLayoutType` | Scale + fade entering animation | Custom entering animation for content |
| `exiting.value` | `EntryOrExitLayoutType` | Scale + fade exiting animation | Custom exiting animation for content |
### Menu.Content (Bottom Sheet)
Props when `presentation="bottom-sheet"`. Extends `@gorhom/bottom-sheet` BottomSheet props.
| prop | type | default | description |
| --------------------------- | ---------------------------------------- | ------- | ---------------------------------------------------- |
| `children` | `React.ReactNode` | - | The bottom sheet content |
| `presentation` | `'bottom-sheet'` | - | Presentation mode (must match Menu root) |
| `className` | `string` | - | Additional CSS class for the bottom sheet |
| `backgroundClassName` | `string` | - | Additional CSS class for the background |
| `handleIndicatorClassName` | `string` | - | Additional CSS class for the handle indicator |
| `contentContainerClassName` | `string` | - | Additional CSS class for the content container |
| `contentContainerProps` | `Omit` | - | Props for the content container |
| `animation` | `AnimationDisabled` | - | Set to `false` or `"disabled"` to disable animations |
| `...BottomSheetProps` | `Partial` | - | All `@gorhom/bottom-sheet` props are supported |
### Menu.Close
Extends `CloseButtonProps`. Automatically closes the menu when pressed.
| prop | type | default | description |
| ---------------- | ---------------------- | ------- | ------------------------------------ |
| `iconProps` | `CloseButtonIconProps` | - | Props for customizing the close icon |
| `...ButtonProps` | `ButtonRootProps` | - | All Button root props are supported |
### Menu.Group
| prop | type | default | description |
| --------------------- | ---------------------------------- | -------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | The group content (Menu.Item elements) |
| `selectionMode` | `'none' \| 'single' \| 'multiple'` | `'none'` | The type of selection allowed in the group |
| `selectedKeys` | `Iterable` | - | Currently selected keys (controlled) |
| `defaultSelectedKeys` | `Iterable` | - | Initially selected keys (uncontrolled) |
| `isDisabled` | `boolean` | `false` | Whether the entire group is disabled |
| `disabledKeys` | `Iterable` | - | Keys of items that should be disabled |
| `shouldCloseOnSelect` | `boolean` | - | Whether selecting an item should close the menu |
| `className` | `string` | - | Additional CSS class for the group container |
| `onSelectionChange` | `(keys: Set) => void` | - | Callback fired when the selection changes |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### Menu.Label
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | The label text content |
| `className` | `string` | - | Additional CSS class for the label |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
### Menu.Item
| prop | type | default | description |
| ----------------------- | ---------------------------------------------------------------- | ----------- | ------------------------------------------------------------ |
| `children` | `React.ReactNode \| ((props: MenuItemRenderProps) => ReactNode)` | - | Child elements or a render function |
| `id` | `MenuKey` | - | Unique identifier, required when inside a Menu.Group |
| `variant` | `'default' \| 'danger'` | `'default'` | Visual variant of the menu item |
| `isDisabled` | `boolean` | `false` | Whether the item is disabled |
| `isSelected` | `boolean` | - | Controlled selected state for standalone items |
| `shouldCloseOnSelect` | `boolean` | `true` | Whether pressing this item should close the menu |
| `className` | `string` | - | Additional CSS class for the item |
| `animation` | `MenuItemAnimation` | - | Animation configuration for press feedback |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `onSelectedChange` | `(selected: boolean) => void` | - | Callback when standalone item's selected state changes |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported |
#### MenuItemRenderProps
Props passed to the render function when `children` is a function.
| prop | type | description |
| ------------ | ----------------------- | --------------------------------------- |
| `isSelected` | `boolean` | Whether this item is currently selected |
| `isDisabled` | `boolean` | Whether the item is disabled |
| `isPressed` | `SharedValue` | Whether the item is currently pressed |
| `variant` | `'default' \| 'danger'` | Visual variant of the item |
#### MenuItemAnimation
Animation configuration for menu item press feedback. Can be:
* `false` or `"disabled"`: Disable all item animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ------------------------------ | ------------------ | -------------------------- | ---------------------------------------- |
| `scale.value` | `number` | `0.98` | Scale value when pressed |
| `scale.timingConfig` | `WithTimingConfig` | `{ duration: 150 }` | Spring animation configuration for scale |
| `backgroundColor.value` | `string` | `useThemeColor('default')` | Background color shown while pressed |
| `backgroundColor.timingConfig` | `WithTimingConfig` | `{ duration: 150 }` | Animation timing for background color |
### Menu.ItemTitle
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | The title text content |
| `className` | `string` | - | Additional CSS class for the item title |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
### Menu.ItemDescription
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | The description text content |
| `className` | `string` | - | Additional CSS class for the item description |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
### Menu.ItemIndicator
| prop | type | default | description |
| -------------- | ---------------------------- | ------------- | ------------------------------------------------------ |
| `children` | `React.ReactNode` | - | Custom indicator content, defaults to checkmark or dot |
| `variant` | `'checkmark' \| 'dot'` | `'checkmark'` | Visual variant of the indicator |
| `iconProps` | `MenuItemIndicatorIconProps` | - | Icon configuration (checkmark variant) |
| `forceMount` | `boolean` | `true` | Force mount the indicator regardless of selected state |
| `className` | `string` | - | Additional CSS class for the item indicator |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### MenuItemIndicatorIconProps
| prop | type | default | description |
| ------- | -------- | ------- | ---------------------------------------------- |
| `size` | `number` | `16` | Size of the indicator icon (8 for dot variant) |
| `color` | `string` | `muted` | Color of the indicator icon |
### SubMenu
| prop | type | default | description |
| --------------- | ------------------------- | ------- | -------------------------------------------------------- |
| `children` | `React.ReactNode` | - | The sub-menu content (trigger, content, and other items) |
| `isOpen` | `boolean` | - | Controlled open state of the sub-menu |
| `isDefaultOpen` | `boolean` | - | Open state when initially rendered (uncontrolled) |
| `isDisabled` | `boolean` | `false` | Whether the sub-menu is disabled |
| `className` | `string` | - | Additional CSS class for the root container |
| `background` | `React.ReactNode` | - | Background layer behind the open sub-menu surface |
| `animation` | `SubMenuRootAnimation` | - | Animation configuration for the sub-menu |
| `onOpenChange` | `(open: boolean) => void` | - | Callback fired when the sub-menu open state changes |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
##### SubMenuRootAnimation
Animation configuration for the SubMenu root component. Can be:
* `"disable-all"`: Disable all animations including children
* `false` or `"disabled"`: Disable only root animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ------------------------------- | ----------------------- | ------------------------------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `rootContent.marginHorizontal` | `number` | `-16` | Margin horizontal when sub-menu is open |
| `rootContent.marginVertical` | `number` | `-16` | Margin vertical when sub-menu is open |
| `rootContent.paddingHorizontal` | `number` | `6` | Padding horizontal when sub-menu is open |
| `rootContent.paddingTop` | `number` | `12` | Padding top when sub-menu is open |
| `rootContent.springConfig` | `WithSpringConfig` | `{ damping: 100, stiffness: 950, mass: 3 }` | Spring configuration for expand/collapse |
| `background.exiting` | `EntryOrExitLayoutType` | `FadeOut.duration(200)` | Exit animation for the background layer |
#### SubMenu.Background
Absolute-fill layer rendered behind the open sub-menu surface. It paints the sub-menu surface coat (`--color-overlay`) and, with no children, the layer chosen by the active library theme — a `GlassView` blur under the `glass` theme, nothing under the default theme.
The surface is mounted only while the sub-menu is open (and faded out on close) so the collapsed trigger row keeps the menu surface it sits on. That matters under themes with a translucent `--color-overlay`, where a permanent coat would tint the trigger row twice and make it read differently from its sibling `Menu.Item`s.
Replace it via the `background` prop on `SubMenu` — a custom node takes over the mount and exit transition as well, so wrap content in `SubMenu.Background` to keep the absolute-fill, surface coat, and clipping:
```tsx
}
>
...
```
Passing `background={null}` removes the layer entirely, leaving the open sub-menu transparent over the menu content.
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom content replacing the theme default layer |
| `className` | `string` | - | Additional CSS class for the background container |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### SubMenu.Trigger
| prop | type | default | description |
| ------------------- | ----------------- | ------- | ------------------------------------------------------- |
| `children` | `React.ReactNode` | - | The trigger content (title, icons, indicator, etc.) |
| `textValue` | `string` | - | Accessible text value announced by screen readers |
| `className` | `string` | - | Additional CSS class for the trigger |
| `isDisabled` | `boolean` | `false` | Whether the trigger is disabled |
| `asChild` | `boolean` | - | Render as child element using Slot pattern |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported |
#### SubMenu.TriggerIndicator
Animated indicator icon that rotates when the submenu opens/closes. Defaults to a chevron-right icon.
| prop | type | default | description |
| ----------------------- | ---------------------------------- | ------- | ------------------------------------------------------------ |
| `children` | `React.ReactNode` | - | Custom indicator content (replaces default chevron) |
| `className` | `string` | - | Additional CSS class for the indicator |
| `iconProps` | `SubMenuTriggerIndicatorIconProps` | - | Icon configuration for the default chevron |
| `animation` | `SubMenuTriggerIndicatorAnimation` | - | Animation configuration for indicator rotation |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
##### SubMenuTriggerIndicatorIconProps
| prop | type | default | description |
| ------- | -------- | ------- | --------------------------- |
| `size` | `number` | `14` | Size of the indicator icon |
| `color` | `string` | `muted` | Color of the indicator icon |
##### SubMenuTriggerIndicatorAnimation
Animation configuration for the trigger indicator rotation. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ----------------------- | ----------------------- | -------------------------------------------- | ------------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `rotation.value` | `[number, number]` | `[0, 90]` | Rotation values \[collapsed, expanded] in degrees |
| `rotation.springConfig` | `WithSpringConfig` | `{ damping: 140, stiffness: 1000, mass: 4 }` | Spring configuration for rotation |
#### SubMenu.Content
| prop | type | default | description |
| ------------------- | ----------------- | ------- | ------------------------------------------------------- |
| `children` | `React.ReactNode` | - | The submenu items (Menu.Item, Menu.Group, etc.) |
| `className` | `string` | - | Additional CSS class for the content container |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported |
## Hooks
### useMenu
Hook to access the menu root context. Must be used within a `Menu` component.
```tsx
import { useMenu } from 'heroui-native';
const { isOpen, onOpenChange, presentation, isDisabled } = useMenu();
```
#### Returns
| property | type | description |
| -------------- | ----------------------------- | --------------------------------------- |
| `isOpen` | `boolean` | Whether the menu is currently open |
| `onOpenChange` | `(open: boolean) => void` | Callback to change the open state |
| `presentation` | `'popover' \| 'bottom-sheet'` | Current presentation mode |
| `isDisabled` | `boolean \| undefined` | Whether the menu is disabled |
| `nativeID` | `string` | Unique identifier for the menu instance |
### useMenuItem
Hook to access the menu item context. Must be used within a `Menu.Item` component.
```tsx
import { useMenuItem } from 'heroui-native';
const { id, isSelected, isDisabled, variant } = useMenuItem();
```
#### Returns
| property | type | description |
| ------------ | ----------------------- | -------------------------------------- |
| `id` | `MenuKey \| undefined` | Item identifier |
| `isSelected` | `boolean` | Whether the item is currently selected |
| `isDisabled` | `boolean` | Whether the item is disabled |
| `variant` | `'default' \| 'danger'` | Visual variant of the item |
### useMenuAnimation
Hook to access the menu animation context. Must be used within a `Menu` component.
```tsx
import { useMenuAnimation } from 'heroui-native';
const { progress, isDragging } = useMenuAnimation();
```
#### Returns
| property | type | description |
| ------------ | ---------------------- | --------------------------------------------------------- |
| `progress` | `SharedValue` | Animation progress shared value (0=idle, 1=open, 2=close) |
| `isDragging` | `SharedValue` | Whether the bottom sheet is currently being dragged |
### useSubMenu
Hook to access the sub-menu context. Must be used within a `SubMenu` component.
```tsx
import { useSubMenu } from 'heroui-native';
const { isOpen, onOpenChange, isDisabled } = useSubMenu();
```
#### Returns
| property | type | description |
| -------------- | ------------------------- | ------------------------------------------- |
| `isOpen` | `boolean` | Whether the sub-menu is currently open |
| `onOpenChange` | `(open: boolean) => void` | Callback to change the open state |
| `isDisabled` | `boolean` | Whether the sub-menu is disabled |
| `nativeID` | `string` | Unique identifier for the sub-menu instance |
## Special Notes
### Element Inspector (iOS)
Menu uses FullWindowOverlay on iOS. To enable the React Native element inspector during development, set `disableFullWindowOverlay={true}` on `Menu.Portal`. Tradeoff: the menu will not appear above native modals when disabled.
### Native Modal (iOS)
When a `Menu` is opened inside a screen presented as a native modal (`presentation: 'modal' | 'formSheet' | 'pageSheet'`), the menu content may render shifted upward. In the new architecture (Fabric), `react-native-screens` marks `RNSModalScreen` as a Fabric root, so the trigger's position is reported relative to the modal's origin while `FullWindowOverlay` (where the menu is mounted) is anchored to the iOS application window. Compensate by adding `safeAreaInsets.top` to `offset`:
```tsx
import { useSafeAreaInsets } from 'react-native-safe-area-context';
const insets = useSafeAreaInsets();
...
;
```
# TagGroup
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/tag-group
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(collections)/tag-group.mdx
> A compound component for displaying and managing selectable tags with optional removal.
## Import
```tsx
import { TagGroup } from 'heroui-native';
```
## Anatomy
```tsx
...
```
* **TagGroup**: Main container that manages tag selection state, disabled keys, and remove functionality. Provides size and variant context to all child components.
* **TagGroup.List**: Container for rendering the list of tags with optional empty state rendering.
* **TagGroup.Item**: Individual tag within the group. Supports string children (auto-wrapped in TagGroup.ItemLabel), render function children, or custom layouts.
* **TagGroup.ItemBackground**: Optional theme-aware background container rendered behind the tag surface. Mounted automatically for unselected items when the active theme registers default background content (e.g. `glass`); the fallback color follows the variant (`surface` or `default`). Replace or remove it via the `background` prop on `TagGroup.Item`.
* **TagGroup.ItemLabel**: Text label for the tag. Automatically rendered when string children are provided, or can be used explicitly.
* **TagGroup.ItemRemoveButton**: Remove button for the tag. Must be placed explicitly when removal is needed. Only functional when `onRemove` is provided to TagGroup.
## Usage
### Basic Usage
Display a simple tag group with selectable items.
```tsx
News
Travel
Gaming
```
### Single Selection Mode
Allow only one tag to be selected at a time.
```tsx
News
Travel
Gaming
```
### Multiple Selection Mode
Allow multiple tags to be selected simultaneously.
```tsx
News
Travel
Gaming
```
### Controlled Selection
Control selection state with `selectedKeys` and `onSelectionChange`.
```tsx
const [selected, setSelected] = useState(new Set(['news']));
News
Travel
Gaming
;
```
### Variants
Apply different visual variants to the tags.
```tsx
News
Travel
News
Travel
```
### Sizes
Control the size of all tags in the group.
```tsx
News
News
News
```
### With Remove Button
Add remove buttons to tags by providing `onRemove` and placing `TagGroup.ItemRemoveButton` in each item.
```tsx
const [tags, setTags] = useState([
{ id: 'news', name: 'News' },
{ id: 'travel', name: 'Travel' },
]);
const onRemove = (keys) => {
setTags((prev) => prev.filter((tag) => !keys.has(tag.id)));
};
{tags.map((tag) => (
{tag.name}
))}
;
```
### Render Function Children
Use a render function to access `isSelected` and `isDisabled` for custom layouts.
```tsx
{({ isSelected }) => (
<>
News
>
)}
```
### Empty State
Render custom content when the list has no tags.
```tsx
(
No categories found
)}
>
{tags.map((tag) => (
{tag.name}
))}
```
### Disabled Tags
Disable individual tags or the entire group.
```tsx
News
Travel
Gaming
```
## Example
```tsx
import { TagGroup, Label, Description, FieldError } from 'heroui-native';
import { useState, useMemo } from 'react';
import { View } from 'react-native';
export default function TagGroupExample() {
const [selected, setSelected] = useState(new Set());
const isInvalid = useMemo(
() => Array.from(selected).length === 0,
[selected]
);
return (
Amenities
Laundry
Fitness center
Parking
Swimming pool
Breakfast
{`Selected: ${Array.from(selected).join(', ')}`}
Please select at least one category
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/tag-group.tsx).
## API Reference
### TagGroup
| prop | type | default | description |
| --------------------- | ---------------------------------- | ----------- | ---------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Child elements to render inside the tag group |
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size of all tags in the group |
| `variant` | `'default' \| 'surface'` | `'default'` | Visual variant of all tags in the group |
| `selectionMode` | `'none' \| 'single' \| 'multiple'` | `'none'` | The type of selection allowed in the tag group |
| `selectedKeys` | `Iterable` | - | The currently selected keys (controlled) |
| `defaultSelectedKeys` | `Iterable` | - | The initial selected keys (uncontrolled) |
| `disabledKeys` | `Iterable` | - | Keys of tags that should be disabled |
| `isDisabled` | `boolean` | `false` | Whether the entire tag group is disabled |
| `isInvalid` | `boolean` | `false` | Whether the tag group is in an invalid state |
| `isRequired` | `boolean` | `false` | Whether the tag group is required |
| `className` | `string` | - | Additional CSS classes for the tag group container |
| `style` | `StyleProp` | - | Additional styles for the tag group container |
| `animation` | `"disable-all" \| undefined` | - | Use `"disable-all"` to disable all animations including children |
| `onSelectionChange` | `(keys: Set) => void` | - | Handler called when the selection changes |
| `onRemove` | `(keys: Set) => void` | - | Handler called when tags are removed |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### TagKey
`string | number` — Key type for identifying tags within a TagGroup.
#### Animation
Use `animation="disable-all"` to disable all animations including children. Omit or use `undefined` for default animations.
### TagGroup.List
| prop | type | default | description |
| ------------------ | ----------------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Child elements to render inside the list |
| `className` | `string` | - | Additional CSS classes for the list container |
| `style` | `StyleProp` | - | Additional styles for the list container |
| `renderEmptyState` | `() => React.ReactNode` | - | Function to render when the list has no tags |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### TagGroup.Item
| prop | type | default | description |
| ------------------- | ----------------------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode \| ((renderProps: TagRenderProps) => React.ReactNode)` | - | Tag content: string, elements, or a render function receiving TagRenderProps |
| `id` | `TagKey` | - | Unique identifier for this tag |
| `isDisabled` | `boolean` | - | Whether this specific tag is disabled |
| `className` | `string` | - | Additional CSS classes for the tag |
| `style` | `StyleProp` | - | Additional styles for the tag |
| `background` | `React.ReactNode` | - | Background layer behind the tag surface. `undefined` renders the theme-aware default while unselected (fallback color follows the variant); custom node replaces it; `null` removes it |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported |
#### TagRenderProps
| prop | type | description |
| ------------ | --------- | --------------------------------------------------------------------------- |
| `isSelected` | `boolean` | Whether the tag is currently selected |
| `isDisabled` | `boolean` | Whether the tag is disabled (merged from root, disabledKeys, and item prop) |
### TagGroup.ItemBackground
Absolute-fill container rendered behind the tag surface. With no children, the active library theme decides the default content (e.g. a glass blur layer); pass children to host custom content with the same positioning and clipping. The fallback color follows the active variant (`surface` → surface token, `default` → default token).
| prop | type | default | description |
| -------------- | ----------------- | ------- | ---------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom content inside the background container |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard View props are supported |
### TagGroup.ItemLabel
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Text content to render |
| `className` | `string` | - | Additional CSS classes for the label |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
### TagGroup.ItemRemoveButton
| prop | type | default | description |
| ------------------- | -------------------------- | ------- | ---------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom icon or content for the remove button. Defaults to close icon when omitted |
| `className` | `string` | - | Additional CSS classes for the remove button |
| `iconProps` | `TagRemoveButtonIconProps` | - | Props for customizing the default close icon. Only applies when no children are provided |
| `hitSlop` | `number` | `8` | Extends the touchable area |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported |
#### TagRemoveButtonIconProps
| prop | type | default | description |
| ------- | -------- | ------- | ----------------- |
| `size` | `number` | `12` | Size of the icon |
| `color` | `string` | - | Color of the icon |
## Hooks
### useTagGroup
Hook to access the tag group root context. Must be used within a `TagGroup` component.
```tsx
import { useTagGroup } from 'heroui-native';
const {
selectedKeys,
disabledKeys,
selectionMode,
onSelectionChange,
onRemove,
isDisabled,
isInvalid,
isRequired,
} = useTagGroup();
```
#### Returns
| property | type | description |
| ------------------- | -------------------------------------------- | ---------------------------------------------- |
| `selectionMode` | `'none' \| 'single' \| 'multiple'` | The type of selection allowed in the tag group |
| `selectedKeys` | `Set` | Currently selected tag keys |
| `disabledKeys` | `Set` | Keys of disabled tags |
| `onSelectionChange` | `(keys: Set) => void` | Callback when selection changes |
| `onRemove` | `((keys: Set) => void) \| undefined` | Callback when tags are removed |
| `isDisabled` | `boolean` | Whether the entire tag group is disabled |
| `isInvalid` | `boolean` | Whether the tag group is in an invalid state |
| `isRequired` | `boolean` | Whether the tag group is required |
### useTagGroupItem
Hook to access the tag item context. Must be used within a `TagGroup.Item` component.
```tsx
import { useTagGroupItem } from 'heroui-native';
const { id, isSelected, isDisabled, allowsRemoving } = useTagGroupItem();
```
#### Returns
| property | type | description |
| ---------------- | --------- | --------------------------------------------------------------------------- |
| `id` | `TagKey` | Unique identifier for this tag |
| `isSelected` | `boolean` | Whether the tag is currently selected |
| `isDisabled` | `boolean` | Whether the tag is disabled |
| `allowsRemoving` | `boolean` | Whether the tag can be removed (true when onRemove is provided to TagGroup) |
# Chip
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/chip
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(data-display)/chip.mdx
> Displays a compact element in a capsule shape.
## Import
```tsx
import { Chip } from 'heroui-native';
```
## Anatomy
```tsx
...
```
* **Chip**: Main container that displays a compact element
* **Chip.Background**: Optional theme-aware background container rendered behind the chip surface. Mounted automatically for the `secondary` variant, and for the `primary`/`soft` variants with `color="default"`, when the active theme registers default background content (e.g. `glass`). Replace or remove it via the `background` prop.
* **Chip.Label**: Text content of the chip
## Usage
### Basic Usage
The Chip component displays text or custom content in a capsule shape.
```tsx
Basic Chip
```
### Sizes
Control the chip size with the `size` prop.
```tsx
Small
Medium
Large
```
### Variants
Choose between different visual styles with the `variant` prop.
```tsx
Primary
Secondary
Tertiary
Soft
```
### Colors
Apply different color themes with the `color` prop.
```tsx
Accent
Default
Success
Warning
Danger
```
### With Icons
Add icons or custom content alongside text using compound components.
```tsx
Featured
Close
```
### Custom Styling
Apply custom styles using className or style props.
```tsx
Custom
```
### Disable All Animations
Disable all animations including children by using the `"disable-all"` value for the `animation` prop.
```tsx
{
/* Disable all animations including children */
}
No Animations ;
```
## Example
```tsx
import { Chip } from 'heroui-native';
import { View, Text } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
export default function ChipExample() {
return (
Small
Medium
Large
Primary
Success
Premium
Remove
Custom
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/chip.tsx).
## API Reference
### Chip
| prop | type | default | description |
| ------------------- | ------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Content to render inside the chip |
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size of the chip |
| `variant` | `'primary' \| 'secondary' \| 'tertiary' \| 'soft'` | `'primary'` | Visual variant of the chip |
| `color` | `'accent' \| 'default' \| 'success' \| 'warning' \| 'danger'` | `'accent'` | Color theme of the chip |
| `className` | `string` | - | Additional CSS classes to apply |
| `animation` | `"disable-all" \| undefined` | `undefined` | Animation configuration. Use `"disable-all"` to disable all animations including children |
| `background` | `React.ReactNode` | - | Background layer behind the chip surface. `undefined` renders the theme-aware default for the `secondary` variant and the `primary`/`soft` variants with `color="default"`; custom node replaces it; `null` removes it |
| `...PressableProps` | `PressableProps` | - | All Pressable props are supported |
### Chip.Background
Absolute-fill container rendered behind the chip surface. With no children, the active library theme decides the default content (e.g. a glass blur layer); pass children to host custom content with the same positioning and clipping.
| prop | type | default | description |
| -------------- | ----------------- | ------- | ---------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom content inside the background container |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard View props are supported |
### Chip.Label
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------- |
| `children` | `React.ReactNode` | - | Text or content to render as the label |
| `className` | `string` | - | Additional CSS classes to apply |
| `...TextProps` | `TextProps` | - | All standard Text props are supported |
## Hooks
### useChip
Hook to access the Chip context values. Returns the chip's size, variant, and color.
```tsx
import { useChip } from 'heroui-native';
const { size, variant, color } = useChip();
```
#### Return Value
| property | type | description |
| --------- | ------------------------------------------------------------- | -------------------------- |
| `size` | `'sm' \| 'md' \| 'lg'` | Size of the chip |
| `variant` | `'primary' \| 'secondary' \| 'tertiary' \| 'soft'` | Visual variant of the chip |
| `color` | `'accent' \| 'default' \| 'success' \| 'warning' \| 'danger'` | Color theme of the chip |
**Note:** This hook must be used within a `Chip` component. It will throw an error if called outside of the chip context.
# Slider
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/slider
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(controls)/slider.mdx
> A draggable input for selecting a value or range within a bounded interval.
## Import
```tsx
import { Slider } from 'heroui-native';
```
## Anatomy
```tsx
```
* **Slider**: Main container that manages slider value state, orientation, and provides context to all sub-components. Supports single value and range modes.
* **Slider.Output**: Optional display of the current value(s). Supports render functions for custom formatting. Shows a formatted value label by default.
* **Slider.Track**: Sizing container for Fill and Thumb elements. Reports its layout size for position calculations. Supports tap-to-position and render-function children for dynamic content (e.g. multiple thumbs for range sliders).
* **Slider.TrackBackground**: Optional theme-aware background container rendered behind the track surface. Mounted automatically whenever the active theme registers default background content (e.g. `glass`) — the track background always uses the default color. Replace or remove it via the `background` prop on `Slider.Track`.
* **Slider.Fill**: Responsive fill bar that stretches the full cross-axis of the Track. Only the main-axis position and size are computed.
* **Slider.Thumb**: Draggable thumb element using react-native-gesture-handler. Centered on the cross-axis by the Track layout. Animates scale on press via react-native-reanimated. Each thumb gets `role="slider"` with full `accessibilityValue`.
## Usage
### Basic Usage
The Slider component uses compound parts to create a draggable value input.
```tsx
```
### With Label and Output
Display a label alongside the current value output.
```tsx
Volume
```
### Vertical Orientation
Render the slider vertically by setting `orientation` to `"vertical"`.
```tsx
```
### Range Slider
Pass an array as the value and use a render function on `Slider.Track` to create multiple thumbs.
```tsx
Price range
{({ state }) => (
<>
{state.values.map((_, i) => (
))}
>
)}
```
### Controlled Value
Use `value` and `onChange` for controlled mode. The `onChangeEnd` callback fires when a drag or tap interaction completes.
```tsx
const [volume, setVolume] = useState(50);
save(v)}>
;
```
### Custom Styling
Apply custom styles using `className`, `classNames`, or `styles` on the thumb and other sub-components.
```tsx
```
### Disabled
Disable the entire slider to prevent interaction.
```tsx
```
## Example
```tsx
import { Label, Slider } from 'heroui-native';
import { useState } from 'react';
import { View, Text } from 'react-native';
export default function SliderExample() {
const [price, setPrice] = useState([200, 800]);
return (
Volume
Price range
{({ state }) => (
<>
{state.values.map((_, i) => (
))}
>
)}
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/slider.tsx).
## API Reference
### Slider
| prop | type | default | description |
| --------------- | ------------------------------------- | -------------- | --------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside the slider |
| `value` | `number \| number[]` | - | Current slider value (controlled mode) |
| `defaultValue` | `number \| number[]` | `0` | Default slider value (uncontrolled mode) |
| `minValue` | `number` | `0` | Minimum value of the slider |
| `maxValue` | `number` | `100` | Maximum value of the slider |
| `step` | `number` | `1` | Step increment for the slider |
| `formatOptions` | `Intl.NumberFormatOptions` | - | Number format options for value label formatting |
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Orientation of the slider |
| `isDisabled` | `boolean` | `false` | Whether the slider is disabled |
| `className` | `string` | - | Additional CSS classes |
| `animation` | `AnimationRootDisableAll` | - | Animation configuration for the slider |
| `onChange` | `(value: number \| number[]) => void` | - | Callback fired when the slider value changes during interaction |
| `onChangeEnd` | `(value: number \| number[]) => void` | - | Callback fired when an interaction completes (drag end or tap) |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### AnimationRootDisableAll
Animation configuration for the slider root component. Can be:
* `"disable-all"`: Disable all animations including children
* `undefined`: Use default animations
### Slider.Output
| prop | type | default | description |
| -------------- | -------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode \| ((props: SliderRenderProps) => React.ReactNode)` | - | Custom content or render function receiving slider state. Defaults to formatted value label |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### SliderRenderProps
| prop | type | description |
| ------------- | ------------------- | ------------------------------ |
| `state` | `SliderState` | Current slider state |
| `orientation` | `SliderOrientation` | Orientation of the slider |
| `isDisabled` | `boolean` | Whether the slider is disabled |
#### SliderState
| prop | type | description |
| -------------------- | --------------------------- | ---------------------------------------------- |
| `values` | `number[]` | Current slider value(s) by thumb index |
| `getThumbValueLabel` | `(index: number) => string` | Returns the formatted string label for a thumb |
### Slider.Track
| prop | type | default | description |
| -------------- | -------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode \| ((props: SliderRenderProps) => React.ReactNode)` | - | Content or render function receiving slider state for dynamic thumb rendering |
| `className` | `string` | - | Additional CSS classes |
| `hitSlop` | `number` | `8` | Extra touch area around the track |
| `background` | `React.ReactNode` | - | Background layer behind the track surface. `undefined` renders the theme-aware default whenever the active theme registers default background content; custom node replaces it; `null` removes it |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### Slider.TrackBackground
Absolute-fill container rendered behind the track surface. With no children, the active library theme decides the default content (e.g. a glass blur layer); pass children to host custom content with the same positioning and clipping.
| prop | type | default | description |
| -------------- | ----------------- | ------- | ---------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom content inside the background container |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard View props are supported |
### Slider.Fill
| prop | type | default | description |
| -------------- | ----------- | ------- | -------------------------------------------------- |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### Slider.Thumb
| prop | type | default | description |
| -------------- | ---------------------------------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom thumb content. Defaults to an animated knob |
| `index` | `number` | `0` | Index of this thumb within the slider |
| `isDisabled` | `boolean` | - | Whether this individual thumb is disabled |
| `className` | `string` | - | Additional CSS classes for the thumb container |
| `classNames` | `ElementSlots` | - | Additional CSS classes for thumb slots |
| `styles` | `Partial>` | - | Inline styles for thumb slots |
| `hitSlop` | `number` | `12` | Extra touch area around the thumb |
| `animation` | `SliderThumbAnimation` | - | Animation configuration for the thumb knob |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### ElementSlots\
| prop | type | description |
| ---------------- | -------- | ----------------------------------------------- |
| `thumbContainer` | `string` | Custom class name for the outer thumb container |
| `thumbKnob` | `string` | Custom class name for the inner thumb knob |
#### styles
| prop | type | description |
| ---------------- | ----------- | ------------------------------------ |
| `thumbContainer` | `ViewStyle` | Styles for the outer thumb container |
| `thumbKnob` | `ViewStyle` | Styles for the inner thumb knob |
#### SliderThumbAnimation
Animation configuration for the thumb knob scale effect. Can be:
* `false` or `"disabled"`: Disable thumb animation
* `undefined`: Use default animations
* `object`: Custom scale animation configuration
| prop | type | default | description |
| -------------------- | ------------------ | -------------------------------------------- | ----------------------------------------------- |
| `scale.value` | `[number, number]` | `[1, 0.9]` | Scale values \[idle, dragging] |
| `scale.springConfig` | `WithSpringConfig` | `{ damping: 15, stiffness: 200, mass: 0.5 }` | Spring animation configuration for scale effect |
## Hooks
### useSlider
Hook to access the slider context. Must be used within a `Slider` component.
```tsx
import { useSlider } from 'heroui-native';
const { values, orientation, isDisabled, getThumbValueLabel } = useSlider();
```
#### Returns
| property | type | description |
| -------------------- | -------------------------------------------- | -------------------------------------------------------------- |
| `values` | `number[]` | Current slider values (one per thumb) |
| `minValue` | `number` | Minimum value of the slider |
| `maxValue` | `number` | Maximum value of the slider |
| `step` | `number` | Step increment |
| `orientation` | `'horizontal' \| 'vertical'` | Current orientation |
| `isDisabled` | `boolean` | Whether the slider is disabled |
| `formatOptions` | `Intl.NumberFormatOptions \| undefined` | Number format options for labels |
| `getThumbPercent` | `(index: number) => number` | Returns the percentage position (0–1) for a given thumb index |
| `getThumbValueLabel` | `(index: number) => string` | Returns the formatted label for a given thumb index |
| `getThumbMinValue` | `(index: number) => number` | Returns the minimum allowed value for a thumb |
| `getThumbMaxValue` | `(index: number) => number` | Returns the maximum allowed value for a thumb |
| `updateValue` | `(index: number, newValue: number) => void` | Updates a thumb value by index |
| `isThumbDragging` | `(index: number) => boolean` | Returns whether a given thumb is currently being dragged |
| `setThumbDragging` | `(index: number, dragging: boolean) => void` | Sets the dragging state of a thumb |
| `trackSize` | `number` | Track layout width (horizontal) or height (vertical) in pixels |
| `thumbSize` | `number` | Measured thumb size (main-axis dimension) in pixels |
# Switch
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/switch
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(controls)/switch.mdx
> A toggle control that allows users to switch between on and off states.
## Import
```tsx
import { Switch } from 'heroui-native';
```
## Anatomy
```tsx
...
...
...
```
* **Switch**: Main container that handles toggle state and user interaction. Renders default thumb if no children provided. Animates scale (on press) and background color based on selection state. Acts as a pressable area for toggling.
* **Switch.Background**: Optional theme-aware background container rendered behind the switch content. Mounted automatically while the switch is unselected (selection animates an opaque accent color) when the active theme registers default background content (e.g. `glass`). Replace or remove it via the `background` prop.
* **Switch.Thumb**: Optional sliding thumb element that moves between positions. Uses spring animation for smooth transitions. Can contain custom content like icons or be customized with different styles and animations.
* **Switch.StartContent**: Optional content displayed on the left side of the switch. Typically used for icons or text that appear when switch is off. Positioned absolutely within the switch container.
* **Switch.EndContent**: Optional content displayed on the right side of the switch. Typically used for icons or text that appear when switch is on. Positioned absolutely within the switch container.
## Usage
### Basic Usage
The Switch component renders with default thumb if no children provided.
```tsx
```
### With Custom Thumb
Replace the default thumb with custom content using the Thumb component.
```tsx
...
```
### With Start and End Content
Add icons or text that appear on each side of the switch.
```tsx
...
...
```
### With Render Function
Use render functions for dynamic content based on switch state.
```tsx
{({ isSelected, isDisabled }) => (
<>
{({ isSelected }) => (isSelected ? : )}
>
)}
```
### With Custom Animations
Customize animations for the switch root and thumb components.
```tsx
```
### Disable Animations
Disable animations entirely or only for specific components.
```tsx
{
/* Disable all animations including children */
}
;
{
/* Disable only root animations, thumb can still animate */
}
;
```
## Example
```tsx
import { Switch } from 'heroui-native';
import { Ionicons } from '@expo/vector-icons';
import React from 'react';
import { View } from 'react-native';
import Animated, { ZoomIn } from 'react-native-reanimated';
export default function SwitchExample() {
const [darkMode, setDarkMode] = React.useState(false);
return (
{darkMode && (
)}
{!darkMode && (
)}
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/switch.tsx).
## API Reference
### Switch
| prop | type | default | description |
| --------------------------- | -------------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode \| ((props: SwitchRenderProps) => React.ReactNode)` | `undefined` | Content to render inside the switch, or a render function |
| `isSelected` | `boolean` | `undefined` | Whether the switch is currently selected |
| `isDisabled` | `boolean` | `false` | Whether the switch is disabled and cannot be interacted with |
| `className` | `string` | `undefined` | Custom class name for the switch |
| `animation` | `SwitchRootAnimation` | - | Animation configuration |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `onSelectedChange` | `(isSelected: boolean) => void` | - | Callback fired when the switch selection state changes |
| `background` | `React.ReactNode` | - | Background layer behind the switch content. `undefined` renders the theme-aware default while unselected; custom node replaces it; `null` removes it |
| `...AnimatedPressableProps` | `AnimatedProps` | - | All React Native Reanimated Pressable props are supported |
#### SwitchRenderProps
| prop | type | description |
| ------------ | --------- | ------------------------------ |
| `isSelected` | `boolean` | Whether the switch is selected |
| `isDisabled` | `boolean` | Whether the switch is disabled |
#### SwitchRootAnimation
Animation configuration for Switch component. Can be:
* `false` or `"disabled"`: Disable only root animations
* `"disable-all"`: Disable all animations including children
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ------------------------------ | ---------------------------------------- | -------------------------------------------------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| 'disable-all' \| boolean` | - | Disable animations while customizing properties |
| `scale.value` | `[number, number]` | `[1, 0.96]` | Scale values \[unpressed, pressed] |
| `scale.timingConfig` | `WithTimingConfig` | `{ duration: 150 }` | Animation timing configuration |
| `backgroundColor.value` | `[string, string]` | Uses theme colors | Background color values \[unselected, selected] |
| `backgroundColor.timingConfig` | `WithTimingConfig` | `{ duration: 175, easing: Easing.bezier(0.25, 0.1, 0.25, 1) }` | Animation timing configuration |
### Switch.Background
Absolute-fill container rendered behind the switch content. With no children, the active library theme decides the default content (e.g. a glass blur layer); pass children to host custom content with the same positioning and clipping.
| prop | type | default | description |
| -------------- | ----------------- | ------- | ---------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom content inside the background container |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard View props are supported |
### Switch.Thumb
| prop | type | default | description |
| ----------------------- | -------------------------------------------------------------------- | ----------- | ------------------------------------------------------------ |
| `children` | `React.ReactNode \| ((props: SwitchRenderProps) => React.ReactNode)` | `undefined` | Content to render inside the thumb, or a render function |
| `className` | `string` | `undefined` | Custom class name for the thumb element |
| `animation` | `SwitchThumbAnimation` | - | Animation configuration |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### SwitchThumbAnimation
Animation configuration for Switch.Thumb component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ------------------------------ | ----------------------- | -------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `left.value` | `number` | `2` | Offset value from the edges (left when unselected, right when selected) |
| `left.springConfig` | `WithSpringConfig` | `{ damping: 120, stiffness: 1600, mass: 2 }` | Spring animation configuration for thumb position |
| `backgroundColor.value` | `[string, string]` | `['white', theme accent-foreground color]` | Background color values \[unselected, selected] |
| `backgroundColor.timingConfig` | `WithTimingConfig` | `{ duration: 175, easing: Easing.bezier(0.25, 0.1, 0.25, 1) }` | Animation timing configuration |
### Switch.StartContent
| prop | type | default | description |
| -------------- | ----------------- | ----------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | `undefined` | Content to render inside the switch content |
| `className` | `string` | `undefined` | Custom class name for the content element |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### Switch.EndContent
| prop | type | default | description |
| -------------- | ----------------- | ----------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | `undefined` | Content to render inside the switch content |
| `className` | `string` | `undefined` | Custom class name for the content element |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
## Hooks
### useSwitch
A hook that provides access to the Switch context. This is useful when building custom switch components or when you need to access switch state in child components.
**Returns:**
| Property | Type | Description |
| ------------ | --------- | ------------------------------ |
| `isSelected` | `boolean` | Whether the switch is selected |
| `isDisabled` | `boolean` | Whether the switch is disabled |
**Example:**
```tsx
import { useSwitch } from 'heroui-native';
function CustomSwitchContent() {
const { isSelected, isDisabled } = useSwitch();
return (
Status: {isSelected ? 'On' : 'Off'}
{isDisabled && Disabled }
);
}
// Usage
;
```
## Special Notes
### Border Styling
If you need to apply a border to the switch root, use the `outline` style properties instead of `border`. This ensures the border doesn't affect the internal layout calculations for the thumb position:
```tsx
```
Using `outline` keeps the border visual without impacting the switch's internal width calculations, ensuring the thumb animates correctly.
### Integration with ControlField
The Switch component integrates seamlessly with ControlField for press state sharing:
```tsx
import { Description, ControlField, Label } from 'heroui-native';
Enable notifications
Receive push notifications
```
When wrapped in ControlField, the Switch will automatically respond to press events on the entire ControlField container, creating a larger touch target and better user experience.
# Alert
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/alert
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(feedback)/alert.mdx
> Displays important messages and notifications to users with status indicators.
## Import
```tsx
import { Alert } from 'heroui-native';
```
## Anatomy
```tsx
...
...
```
* **Alert**: Main container with `role="alert"` and status-based styling. Provides status context to sub-components via a primitive context.
* **Alert.Indicator**: Renders a status-appropriate icon by default. Accepts custom children to override the default icon. Supports `iconProps` for customising size and color.
* **Alert.Content**: Wrapper for the title and description. Provides layout structure for text content.
* **Alert.Title**: Heading text with status-based color. Connected to root via `aria-labelledby`.
* **Alert.Description**: Body text rendered with muted color. Connected to root via `aria-describedby`.
## Usage
### Basic Usage
The Alert component uses compound parts to display a notification with an icon, title, and description.
```tsx
New features available
Check out our latest updates including dark mode support and improved
accessibility features.
```
### Status Variants
Set the `status` prop to control the icon and title color. Available statuses are `default`, `accent`, `success`, `warning`, and `danger`.
```tsx
Success
...
Scheduled maintenance
...
Unable to connect
...
```
### Title Only
Omit `Alert.Description` for a compact single-line alert.
```tsx
Profile updated successfully
```
### With Action Buttons
Place additional elements like buttons alongside the content.
```tsx
Update available
A new version of the application is available.
Refresh
```
### Custom Indicator
Replace the default status icon by passing custom children to `Alert.Indicator`.
```tsx
Processing your request
Please wait while we sync your data.
```
### Custom Styling
Apply custom styles using the `className` prop on the root and compound parts.
```tsx
...
...
```
## Example
```tsx
import { Alert, Button, CloseButton } from 'heroui-native';
import { View } from 'react-native';
export default function AlertExample() {
return (
Update available
A new version of the application is available. Please refresh to get
the latest features and bug fixes.
Refresh
Unable to connect to server
Unable to connect to the server. Check your internet connection and
try again.
Retry
Profile updated successfully
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/alert.tsx).
## API Reference
### Alert
| prop | type | default | description |
| -------------- | ------------------------------------------------------------- | ----------- | ----------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to render inside the alert |
| `status` | `'default' \| 'accent' \| 'success' \| 'warning' \| 'danger'` | `'default'` | Status controlling the icon and color treatment |
| `id` | `string \| number` | - | Unique identifier for the alert. Auto-generated when not provided |
| `className` | `string` | - | Additional CSS classes |
| `style` | `ViewStyle` | - | Additional styles applied to the root container |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### Alert.Indicator
| prop | type | default | description |
| -------------- | ----------------- | ------- | ------------------------------------------------------------------ |
| `children` | `React.ReactNode` | - | Custom children to render instead of the default status icon |
| `className` | `string` | - | Additional CSS classes |
| `iconProps` | `AlertIconProps` | - | Props passed to the default status icon (size and color overrides) |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### AlertIconProps
| prop | type | default | description |
| ------- | -------- | ------------ | ---------------------- |
| `size` | `number` | `18` | Icon size in pixels |
| `color` | `string` | status color | Icon color as a string |
### Alert.Content
| prop | type | default | description |
| -------------- | ----------------- | ------- | --------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements (typically Alert.Title and Alert.Description) |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### Alert.Title
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Title text content |
| `className` | `string` | - | Additional CSS classes |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
### Alert.Description
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Description text content |
| `className` | `string` | - | Additional CSS classes |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
## Hooks
### useAlert
Hook to access the alert root context. Must be used within an `Alert` component.
```tsx
import { useAlert } from 'heroui-native';
const { status, nativeID } = useAlert();
```
#### Returns
| property | type | description |
| ---------- | ------------------------------------------------------------- | ------------------------------------------------------------ |
| `status` | `'default' \| 'accent' \| 'success' \| 'warning' \| 'danger'` | Current alert status for sub-component styling |
| `nativeID` | `string` | Unique identifier used for accessibility and ARIA attributes |
# SkeletonGroup
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/skeleton-group
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(feedback)/skeleton-group.mdx
> Coordinates multiple skeleton loading placeholders with centralized animation control.
## Import
```tsx
import { SkeletonGroup } from 'heroui-native';
```
## Anatomy
```tsx
```
* **SkeletonGroup**: Root container that provides centralized control for all skeleton items
* **SkeletonGroup.Item**: Individual skeleton item that inherits props from the parent group
## Usage
### Basic Usage
The SkeletonGroup component manages multiple skeleton items with shared loading state and animation.
```tsx
```
### With Container Layout
Use className on the group to control layout of skeleton items.
```tsx
```
### With isSkeletonOnly for Pure Skeleton Layouts
Use `isSkeletonOnly` when the group contains only skeleton placeholders with layout wrappers (like View) that have no content to render in the loaded state. This prop hides the entire group when `isLoading` is false, preventing empty containers from affecting your layout.
```tsx
{/* This View is only for layout, no content */}
```
### With Animation Variants
Control animation style for all items in the group.
```tsx
```
### With Custom Animation Configuration
Configure shimmer or pulse animations for the entire group.
```tsx
```
### With Enter/Exit Animations
Apply Reanimated transitions when the group appears or disappears.
```tsx
```
## Example
```tsx
import { Card, SkeletonGroup, Avatar } from 'heroui-native';
import { useState } from 'react';
import { Text, View, Image } from 'react-native';
export default function SkeletonGroupExample() {
const [isLoading, setIsLoading] = useState(true);
return (
John Doe
@johndoe
This is the first line of the post content.
Second line with more interesting content to read.
Last line is shorter.
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/skeleton-group.tsx).
## API Reference
### SkeletonGroup
| prop | type | default | description |
| ----------------------- | -------------------------------- | ----------- | ---------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | SkeletonGroup.Item components and layout elements |
| `isLoading` | `boolean` | `true` | Whether the skeleton items are currently loading |
| `isSkeletonOnly` | `boolean` | `false` | Hides entire group when isLoading is false (for skeleton-only layouts) |
| `variant` | `'shimmer' \| 'pulse' \| 'none'` | `'shimmer'` | Animation variant for all items in the group |
| `animation` | `SkeletonRootAnimation` | - | Animation configuration |
| `className` | `string` | - | Additional CSS classes for the group container |
| `style` | `StyleProp` | - | Custom styles for the group container |
| `...Animated.ViewProps` | `AnimatedProps` | - | All Reanimated Animated.View props are supported |
#### SkeletonRootAnimation
Animation configuration for SkeletonGroup component. Can be:
* `false` or `"disabled"`: Disable only root animations
* `"disable-all"`: Disable all animations including children
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ------------------------ | ---------------------------------------- | --------------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| 'disable-all' \| boolean` | - | Disable animations while customizing properties |
| `entering.value` | `EntryOrExitLayoutType` | `FadeIn` | Custom entering animation |
| `exiting.value` | `EntryOrExitLayoutType` | `FadeOut` | Custom exiting animation |
| `shimmer.duration` | `number` | `1500` | Animation duration in milliseconds |
| `shimmer.speed` | `number` | `1` | Speed multiplier for the animation |
| `shimmer.highlightColor` | `string` | - | Highlight color for the shimmer effect |
| `shimmer.easing` | `EasingFunction` | `Easing.linear` | Easing function for the animation |
| `pulse.duration` | `number` | `1000` | Animation duration in milliseconds |
| `pulse.minOpacity` | `number` | `0.5` | Minimum opacity value |
| `pulse.maxOpacity` | `number` | `1` | Maximum opacity value |
| `pulse.easing` | `EasingFunction` | `Easing.inOut(Easing.ease)` | Easing function for the animation |
### SkeletonGroup.Item
| prop | type | default | description |
| ----------------------- | -------------------------------- | --------- | ------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Content to show when not loading |
| `isLoading` | `boolean` | inherited | Whether the skeleton is currently loading (overrides group setting) |
| `variant` | `'shimmer' \| 'pulse' \| 'none'` | inherited | Animation variant (overrides group setting) |
| `animation` | `SkeletonRootAnimation` | inherited | Animation configuration (overrides group setting) |
| `className` | `string` | - | Additional CSS classes for styling the item |
| `...Animated.ViewProps` | `AnimatedProps` | - | All Reanimated Animated.View props are supported |
## Special Notes
### Props Inheritance
SkeletonGroup.Item components inherit all animation-related props from their parent SkeletonGroup:
* `isLoading`
* `variant`
* `animation`
Individual items can override any inherited prop by providing their own value.
# Skeleton
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/skeleton
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(feedback)/skeleton.mdx
> Displays a loading placeholder with shimmer or pulse animation effects.
## Import
```tsx
import { Skeleton } from 'heroui-native';
```
## Anatomy
The Skeleton component is a simple wrapper that renders a placeholder for content that is loading. It does not have any child components.
```tsx
```
## Usage
### Basic Usage
The Skeleton component creates an animated placeholder while content is loading.
```tsx
```
### With Content
Show skeleton while loading, then display content when ready.
```tsx
Loaded Content
```
### Animation Variants
Control the animation style with the `variant` prop.
```tsx
```
### Custom Shimmer Configuration
Customize the shimmer effect with duration, speed, and highlight color.
```tsx
...
```
### Custom Pulse Configuration
Configure pulse animation with duration and opacity range.
```tsx
...
```
### Shape Variations
Create different skeleton shapes using className for styling.
```tsx
```
### Custom Enter/Exit Animations
Apply custom Reanimated transitions when skeleton appears or disappears.
```tsx
...
```
## Example
```tsx
import { Avatar, Card, Skeleton } from 'heroui-native';
import { useState } from 'react';
import { Image, Text, View } from 'react-native';
export default function SkeletonExample() {
const [isLoading, setIsLoading] = useState(true);
return (
John Doe
@johndoe
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/skeleton.tsx).
## API Reference
### Skeleton
| prop | type | default | description |
| ----------------------- | -------------------------------- | ----------- | ------------------------------------------------------------ |
| `children` | `React.ReactNode` | - | Content to show when not loading |
| `isLoading` | `boolean` | `true` | Whether the skeleton is currently loading |
| `variant` | `'shimmer' \| 'pulse' \| 'none'` | `'shimmer'` | Animation variant |
| `animation` | `SkeletonRootAnimation` | - | Animation configuration |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `className` | `string` | - | Additional CSS classes for styling |
| `...Animated.ViewProps` | `AnimatedProps` | - | All Reanimated Animated.View props are supported |
#### SkeletonRootAnimation
Animation configuration for Skeleton component. Can be:
* `false` or `"disabled"`: Disable only root animations
* `"disable-all"`: Disable all animations including children
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ------------------------ | ---------------------------------------- | --------------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| 'disable-all' \| boolean` | - | Disable animations while customizing properties |
| `entering.value` | `EntryOrExitLayoutType` | `FadeIn` | Custom entering animation |
| `exiting.value` | `EntryOrExitLayoutType` | `FadeOut` | Custom exiting animation |
| `shimmer.duration` | `number` | `1500` | Animation duration in milliseconds |
| `shimmer.speed` | `number` | `1` | Speed multiplier for the animation |
| `shimmer.highlightColor` | `string` | - | Highlight color for the shimmer effect |
| `shimmer.easing` | `EasingFunction` | `Easing.linear` | Easing function for the animation |
| `pulse.duration` | `number` | `1000` | Animation duration in milliseconds |
| `pulse.minOpacity` | `number` | `0.5` | Minimum opacity value |
| `pulse.maxOpacity` | `number` | `1` | Maximum opacity value |
| `pulse.easing` | `EasingFunction` | `Easing.inOut(Easing.ease)` | Easing function for the animation |
# Spinner
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/spinner
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(feedback)/spinner.mdx
> Displays an animated loading indicator.
## Import
```tsx
import { Spinner } from 'heroui-native';
```
## Anatomy
```tsx
...
```
* **Spinner**: Main container that controls loading state, size, and color. Renders a default animated indicator if no children provided.
* **Spinner.Indicator**: Optional sub-component for customizing animation configuration and icon appearance. Accepts custom children to replace the default icon.
## Usage
### Basic Usage
The Spinner component displays a rotating loading indicator.
```tsx
```
### Sizes
Control the spinner size with the `size` prop.
```tsx
```
### Colors
Use predefined color variants or custom colors.
```tsx
```
### Loading State
Control the visibility of the spinner with the `isLoading` prop.
```tsx
```
### Animation Speed
Customize the rotation speed using the `animation` prop on the Indicator component.
```tsx
```
### Custom Icon
Replace the default spinner icon with custom content.
```tsx
const themeColorForeground = useThemeColor('foreground')
⏳
```
## Example
```tsx
import { Spinner } from 'heroui-native';
import { Ionicons } from '@expo/vector-icons';
import React from 'react';
import { Text, TouchableOpacity, View } from 'react-native';
export default function SpinnerExample() {
const [isLoading, setIsLoading] = React.useState(true);
return (
Loading content...
Processing...
setIsLoading(!isLoading)}>
{isLoading ? 'Tap to stop' : 'Tap to start'}
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/spinner.tsx).
## API Reference
### Spinner
| prop | type | default | description |
| -------------- | ----------------------------------------------------------- | ----------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | `undefined` | Content to render inside the spinner |
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size of the spinner |
| `color` | `'default' \| 'success' \| 'warning' \| 'danger' \| string` | `'default'` | Color theme of the spinner |
| `isLoading` | `boolean` | `true` | Whether the spinner is loading |
| `className` | `string` | `undefined` | Custom class name for the spinner |
| `animation` | `SpinnerRootAnimation` | - | Animation configuration |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### SpinnerRootAnimation
Animation configuration for Spinner component. Can be:
* `false` or `"disabled"`: Disable only root animations
* `"disable-all"`: Disable all animations including children
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ---------------- | ---------------------------------------- | ---------------------------------------------------------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| 'disable-all' \| boolean` | - | Disable animations while customizing properties |
| `entering.value` | `EntryOrExitLayoutType` | `FadeIn` `.duration(200)` `.easing(Easing.out(Easing.ease))` | Custom entering animation |
| `exiting.value` | `EntryOrExitLayoutType` | `FadeOut` `.duration(100)` | Custom exiting animation |
### Spinner.Indicator
| prop | type | default | description |
| ----------------------- | --------------------------- | ----------- | ------------------------------------------------------------ |
| `children` | `React.ReactNode` | `undefined` | Content to render inside the indicator |
| `iconProps` | `SpinnerIconProps` | `undefined` | Props for the default icon |
| `className` | `string` | `undefined` | Custom class name for the indicator element |
| `animation` | `SpinnerIndicatorAnimation` | - | Animation configuration |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `...Animated.ViewProps` | `Animated.ViewProps` | - | All Reanimated Animated.View props are supported |
#### SpinnerIndicatorAnimation
Animation configuration for Spinner.Indicator component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ----------------- | ---------------------------- | --------------- | ----------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `rotation.speed` | `number` | `1.1` | Rotation speed multiplier |
| `rotation.easing` | `WithTimingConfig['easing']` | `Easing.linear` | Animation easing configuration |
### SpinnerIconProps
| prop | type | default | description |
| -------- | ------------------ | ---------------- | ------------------ |
| `width` | `number \| string` | `24` | Width of the icon |
| `height` | `number \| string` | `24` | Height of the icon |
| `color` | `string` | `'currentColor'` | Color of the icon |
# Checkbox
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/checkbox
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(forms)/checkbox.mdx
> A selectable control that allows users to toggle between checked and unchecked states.
## Import
```tsx
import { Checkbox } from 'heroui-native';
```
## Anatomy
```tsx
...
```
* **Checkbox**: Main container that handles selection state and user interaction. Renders default indicator with animated checkmark if no children provided. Automatically detects surface context for proper styling. Features press scale animation that can be customized or disabled. Supports render function children to access state (`isSelected`, `isInvalid`, `isDisabled`).
* **Checkbox.Background**: Optional theme-aware background container rendered behind the checkbox content. Mounted automatically for the `secondary` variant while not invalid, when the active theme registers default background content (e.g. `glass`). Replace or remove it via the `background` prop.
* **Checkbox.Indicator**: Optional checkmark container with default slide, scale, opacity, and border radius animations when selected. Renders animated check icon with SVG path drawing animation if no children provided. All animations can be individually customized or disabled. Supports render function children to access state.
## Usage
### Basic Usage
The Checkbox component renders with a default animated indicator if no children are provided. It automatically detects whether it's on a surface background for proper styling.
```tsx
```
### With Custom Indicator
Use a render function in the Indicator to show/hide custom icons based on state.
```tsx
{({ isSelected }) => (isSelected ? : null)}
```
### Invalid State
Show validation errors with the `isInvalid` prop, which applies danger color styling.
```tsx
```
### Custom Animations
Customize or disable animations for both the root checkbox and indicator.
```tsx
{
/* Disable all animations (root and indicator) */
}
;
{
/* Disable only root animation */
}
;
{
/* Disable only indicator animation */
}
;
{
/* Custom animation configuration */
}
;
```
## Example
```tsx
import {
Checkbox,
Description,
ControlField,
Label,
Separator,
Surface,
} from "heroui-native";
import React from 'react';
import { View, Text } from 'react-native';
interface CheckboxFieldProps {
isSelected: boolean;
onSelectedChange: (value: boolean) => void;
title: string;
description: string;
}
const CheckboxField: React.FC = ({
isSelected,
onSelectedChange,
title,
description,
}) => {
return (
{title}
{description}
);
};
export default function BasicUsage() {
const [fields, setFields] = React.useState({
newsletter: true,
marketing: false,
terms: false,
});
const fieldConfigs: Record<
keyof typeof fields,
{ title: string; description: string }
> = {
newsletter: {
title: 'Subscribe to newsletter',
description: 'Get weekly updates about new features and tips',
},
marketing: {
title: 'Marketing communications',
description: 'Receive promotional emails and special offers',
},
terms: {
title: 'Accept terms and conditions',
description: 'Agree to our Terms of Service and Privacy Policy',
},
};
const handleFieldChange = (key: keyof typeof fields) => (value: boolean) => {
setFields((prev) => ({ ...prev, [key]: value }));
};
const fieldKeys = Object.keys(fields) as Array;
return (
{fieldKeys.map((key, index) => (
{index > 0 && }
))}
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/checkbox.tsx).
## API Reference
### Checkbox
| prop | type | default | description |
| ----------------------- | ---------------------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode \| ((props: CheckboxRenderProps) => React.ReactNode)` | `undefined` | Child elements or render function to customize the checkbox |
| `isSelected` | `boolean` | `undefined` | Whether the checkbox is currently selected |
| `onSelectedChange` | `(isSelected: boolean) => void` | `undefined` | Callback fired when the checkbox selection state changes |
| `isDisabled` | `boolean` | `false` | Whether the checkbox is disabled and cannot be interacted with |
| `isInvalid` | `boolean` | `false` | Whether the checkbox is invalid (shows danger color) |
| `variant` | `'primary' \| 'secondary'` | `'primary'` | Variant style for the checkbox |
| `hitSlop` | `number` | `6` | Hit slop for the pressable area |
| `animation` | `CheckboxRootAnimation` | - | Animation configuration |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `className` | `string` | `undefined` | Additional CSS classes to apply |
| `background` | `React.ReactNode` | - | Background layer behind the checkbox content. `undefined` renders the theme-aware default for the `secondary` variant while not invalid; custom node replaces it; `null` removes it |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported (except disabled) |
#### CheckboxRenderProps
| prop | type | description |
| ------------ | --------- | -------------------------------- |
| `isSelected` | `boolean` | Whether the checkbox is selected |
| `isInvalid` | `boolean` | Whether the checkbox is invalid |
| `isDisabled` | `boolean` | Whether the checkbox is disabled |
#### CheckboxRootAnimation
Animation configuration for checkbox root component. Can be:
* `false` or `"disabled"`: Disable only root animations
* `"disable-all"`: Disable all animations including children
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| -------------------- | ---------------------------------------- | ------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| 'disable-all' \| boolean` | - | Disable animations while customizing properties |
| `scale.value` | `[number, number]` | `[1, 0.96]` | Scale values \[unpressed, pressed] |
| `scale.timingConfig` | `WithTimingConfig` | `{ duration: 150 }` | Animation timing configuration |
### Checkbox.Background
Absolute-fill container rendered behind the checkbox content. With no children, the active library theme decides the default content (e.g. a glass blur layer); pass children to host custom content with the same positioning and clipping.
| prop | type | default | description |
| -------------- | ----------------- | ------- | ---------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom content inside the background container |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard View props are supported |
### Checkbox.Indicator
| prop | type | default | description |
| ----------------------- | ---------------------------------------------------------------------- | ----------- | ------------------------------------------------------------ |
| `children` | `React.ReactNode \| ((props: CheckboxRenderProps) => React.ReactNode)` | `undefined` | Content or render function for the checkbox indicator |
| `className` | `string` | `undefined` | Additional CSS classes for the indicator |
| `iconProps` | `CheckboxIndicatorIconProps` | `undefined` | Custom props for the default animated check icon |
| `animation` | `CheckboxIndicatorAnimation` | - | Animation configuration |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `...AnimatedViewProps` | `AnimatedProps` | - | All standard React Native Animated View props are supported |
#### CheckboxIndicatorIconProps
Props for customizing the default animated check icon.
| prop | type | description |
| --------------- | -------- | ------------------------------------------------ |
| `size` | `number` | Icon size |
| `strokeWidth` | `number` | Icon stroke width |
| `color` | `string` | Icon color (defaults to theme accent-foreground) |
| `enterDuration` | `number` | Duration of enter animation (check appearing) |
| `exitDuration` | `number` | Duration of exit animation (check disappearing) |
#### CheckboxIndicatorAnimation
Animation configuration for checkbox indicator component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| --------------------------- | ----------------------- | ------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `opacity.value` | `[number, number]` | `[0, 1]` | Opacity values \[unselected, selected] |
| `opacity.timingConfig` | `WithTimingConfig` | `{ duration: 100 }` | Animation timing configuration |
| `borderRadius.value` | `[number, number]` | `[8, 0]` | Border radius values \[unselected, selected] |
| `borderRadius.timingConfig` | `WithTimingConfig` | `{ duration: 50 }` | Animation timing configuration |
| `translateX.value` | `[number, number]` | `[-4, 0]` | TranslateX values \[unselected, selected] |
| `translateX.timingConfig` | `WithTimingConfig` | `{ duration: 100 }` | Animation timing configuration |
| `scale.value` | `[number, number]` | `[0.8, 1]` | Scale values \[unselected, selected] |
| `scale.timingConfig` | `WithTimingConfig` | `{ duration: 100 }` | Animation timing configuration |
## Hooks
### useCheckbox
Hook to access checkbox context values within custom components or compound components.
```tsx
import { useCheckbox } from 'heroui-native';
const CustomIndicator = () => {
const { isSelected, isInvalid, isDisabled } = useCheckbox();
// ... your implementation
};
```
**Returns:** `UseCheckboxReturn`
| property | type | description |
| ------------------ | ---------------------------------------------- | -------------------------------------------------------------- |
| `isSelected` | `boolean \| undefined` | Whether the checkbox is currently selected |
| `onSelectedChange` | `((isSelected: boolean) => void) \| undefined` | Callback function to change the checkbox selection state |
| `isDisabled` | `boolean` | Whether the checkbox is disabled and cannot be interacted with |
| `isInvalid` | `boolean` | Whether the checkbox is invalid (shows danger color) |
| `nativeID` | `string \| undefined` | Native ID for the checkbox element |
**Note:** This hook must be used within a `Checkbox` component. It will throw an error if called outside of the checkbox context.
# ControlField
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/control-field
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(forms)/control-field.mdx
> A field component that combines a label, description (or other content), and a control component (Switch or Checkbox) into a single pressable area.
## Import
```tsx
import { ControlField } from 'heroui-native';
```
## Anatomy
```tsx
...
...
...
...
```
* **ControlField**: Root container that manages layout and state propagation
* **Label**: Primary text label for the control (from [Label](./label) component)
* **Description**: Secondary descriptive helper text (from [Description](./description) component)
* **ControlField.Indicator**: Container for the form control component ([Switch](./switch), [Checkbox](./checkbox), [Radio](./radio))
* **FieldError**: Validation error message display (from [FieldError](./field-error) component)
## Usage
### Basic Usage
ControlField wraps form controls to provide consistent layout and state management.
```tsx
Label text
```
### With Description
Add helper text below the label using the Description component.
```tsx
Enable notifications
Receive push notifications about your account activity
```
### With Error Message
Display validation errors using the ErrorMessage component.
```tsx
I agree to the terms
By checking this box, you agree to our Terms of Service
This field is required
```
### Disabled State
Control interactivity with the disabled prop.
```tsx
Disabled field
This field is disabled
```
### Disabling All Animations
Disable all animations including children by using `"disable-all"`. This cascades down to all child components.
```tsx
Label text
Description text
```
## Example
```tsx
import {
Checkbox,
Description,
FieldError,
ControlField,
Label,
Switch,
} from 'heroui-native';
import React from 'react';
import { ScrollView, View } from 'react-native';
export default function ControlFieldExample() {
const [notifications, setNotifications] = React.useState(false);
const [terms, setTerms] = React.useState(false);
const [newsletter, setNewsletter] = React.useState(true);
return (
Enable notifications
Receive push notifications about your account activity
I agree to the terms and conditions
By checking this box, you agree to our Terms of Service
This field is required
Subscribe to newsletter
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/control-field.tsx).
## API Reference
### ControlField
| prop | type | default | description |
| ----------------- | -------------------------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------- |
| children | `React.ReactNode \| ((props: ControlFieldRenderProps) => React.ReactNode)` | - | Content to render inside the form control, or a render function |
| isSelected | `boolean` | `undefined` | Whether the control is selected/checked |
| isDisabled | `boolean` | `false` | Whether the form control is disabled |
| isInvalid | `boolean` | `false` | Whether the form control is invalid |
| isRequired | `boolean` | `false` | Whether the form control is required |
| className | `string` | - | Custom class name for the root element |
| onSelectedChange | `(isSelected: boolean) => void` | - | Callback when selection state changes |
| animation | `"disable-all" \| undefined` | `undefined` | Animation configuration. Use `"disable-all"` to disable all animations including children |
| ...PressableProps | `PressableProps` | - | All React Native Pressable props are supported |
### Label
The `Label` component automatically consumes form state (`isDisabled`, `isInvalid`) from the ControlField context.
**Note**: For complete prop documentation, see the [Label component documentation](./label).
### Description
The `Description` component automatically consumes form state (`isDisabled`, `isInvalid`) from the ControlField context.
**Note**: For complete prop documentation, see the [Description component documentation](./description).
### ControlField.Indicator
| prop | type | default | description |
| ------------ | ----------------------------------- | ---------- | ---------------------------------------------------------- |
| children | `React.ReactNode` | - | Control component to render (Switch, Checkbox, Radio) |
| variant | `'checkbox' \| 'radio' \| 'switch'` | `'switch'` | Variant of the control to render when no children provided |
| className | `string` | - | Custom class name for the indicator element |
| ...ViewProps | `ViewProps` | - | All React Native View props are supported |
**Note**: When children are provided, the component automatically passes down `isSelected`, `onSelectedChange`, `isDisabled`, and `isInvalid` props from the ControlField context if they are not already present on the child component. When using the `radio` variant, the Radio component renders in standalone mode (outside of a RadioGroup).
### FieldError
The `FieldError` component automatically consumes form state (`isInvalid`) from the ControlField context.
**Note**: For complete prop documentation, see the [FieldError component documentation](./field-error). The error message visibility is controlled by the `isInvalid` state of the parent ControlField.
## Hooks
### useControlField
**Returns:**
| property | type | description |
| ------------------ | ---------------------------------------------- | ---------------------------------------------- |
| `isSelected` | `boolean \| undefined` | Whether the control is selected/checked |
| `onSelectedChange` | `((isSelected: boolean) => void) \| undefined` | Callback when selection state changes |
| `isDisabled` | `boolean` | Whether the form control is disabled |
| `isInvalid` | `boolean` | Whether the form control is invalid |
| `isPressed` | `SharedValue` | Reanimated shared value indicating press state |
# Description
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/description
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(forms)/description.mdx
> Text component for providing accessible descriptions and helper text for form fields and other UI elements.
## Import
```tsx
import { Description } from 'heroui-native';
```
## Anatomy
```tsx
...
```
* **Description**: Text component that displays description or helper text with muted styling. Can be linked to form fields via `nativeID` for accessibility support.
## Usage
### Basic Usage
Display description text with default muted styling.
```tsx
This is a helpful description.
```
### With Form Fields
Provide accessible descriptions for form fields using the `nativeID` prop.
```tsx
Email address
We'll never share your email with anyone else.
```
### Accessibility Linking
Link descriptions to form fields for screen reader support by using `nativeID` and `aria-describedby`.
```tsx
Password
Use at least 8 characters with a mix of letters, numbers, and symbols.
```
### Hiding on Invalid State
Control whether the description should be hidden when the form field is invalid using the `hideOnInvalid` prop.
```tsx
Email
We'll never share your email with anyone else.
Please enter a valid email address
```
When `hideOnInvalid` is `true`, the description will be hidden when the field is invalid. When `false` (default), the description remains visible even when invalid.
## Example
```tsx
import { Description, TextField } from 'heroui-native';
import { View } from 'react-native';
export default function DescriptionExample() {
return (
Email address
We'll never share your email with anyone else.
Password
Use at least 8 characters with a mix of letters, numbers, and symbols.
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/description.tsx).
## API Reference
### Description
| prop | type | default | description |
| --------------- | ----------------------------------- | ------- | ------------------------------------------------------------------------------------------ |
| `children` | `React.ReactNode` | - | Description text content |
| `className` | `string` | - | Additional CSS classes to apply |
| `nativeID` | `string` | - | Native ID for accessibility. Used to link description to form fields via aria-describedby. |
| `isInvalid` | `boolean` | - | Whether the description is in an invalid state (overrides context) |
| `isDisabled` | `boolean` | - | Whether the description is disabled (overrides context) |
| `hideOnInvalid` | `boolean` | `false` | Whether to hide the description when invalid |
| `animation` | `DescriptionAnimation \| undefined` | - | Animation configuration for description transitions |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
# FieldError
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/field-error
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(forms)/field-error.mdx
> Displays validation error message content with smooth animations.
## Import
```tsx
import { FieldError } from 'heroui-native';
```
## Anatomy
```tsx
Error message content
```
* **FieldError**: Main container that displays error messages with smooth animations. Accepts string children which are automatically wrapped with Text component, or custom React components for more complex layouts. Controls visibility through the `isInvalid` prop and supports custom entering/exiting animations.
## Usage
### Basic Usage
The FieldError component displays error messages when validation fails.
```tsx
This field is required
```
### Controlled Visibility
Control when the error appears using the `isInvalid` prop. When used inside a form field component (like TextField), FieldError automatically consumes the form-item-state context.
```tsx
const [isInvalid, setIsInvalid] = useState(false);
Please enter a valid email address ;
```
### With Form Fields
FieldError automatically consumes form state from TextField via the form-item-state context.
```tsx
import { FieldError, Label, TextField } from 'heroui-native';
Email
Please enter a valid email address
```
### Custom Content
Pass custom React components as children instead of strings.
```tsx
Invalid input
```
### Custom Animations
Override default entering and exiting animations using the `animation` prop.
```tsx
import { SlideInDown, SlideOutUp } from 'react-native-reanimated';
Field validation failed
;
```
Disable animations entirely:
```tsx
Field validation failed
```
### Custom Styling
Apply custom styles to the container and text elements.
```tsx
Password must be at least 8 characters
```
### Custom Text Props
Pass additional props to the Text component when children is a string.
```tsx
This is a very long error message that might need to be truncated
```
## Example
```tsx
import { Description, FieldError, Label, TextField } from 'heroui-native';
import { useState } from 'react';
import { View } from 'react-native';
export default function FieldErrorExample() {
const [email, setEmail] = useState('');
const [isInvalid, setIsInvalid] = useState(false);
const isValidEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
const handleBlur = () => {
setIsInvalid(email !== '' && !isValidEmail);
};
return (
Email Address
We'll use this to contact you
Please enter a valid email address
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/field-error.tsx).
## API Reference
### FieldError
| prop | type | default | description |
| ---------------------- | --------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | `undefined` | The content of the error field. String children are wrapped with Text |
| `isInvalid` | `boolean` | `undefined` | Controls the visibility of the error field (overrides form-item-state context). When used inside TextField, automatically consumes form state |
| `animation` | `FieldErrorRootAnimation` | - | Animation configuration |
| `className` | `string` | `undefined` | Additional CSS classes for the container |
| `classNames` | `ElementSlots` | `undefined` | Additional CSS classes for different parts of the component |
| `styles` | `{ container?: ViewStyle; text?: TextStyle }` | `undefined` | Styles for different parts of the field error |
| `textProps` | `TextProps` | `undefined` | Additional props to pass to the Text component when children is a string |
| `...AnimatedViewProps` | `AnimatedProps` | - | All Reanimated Animated.View props are supported |
**classNames prop:** `ElementSlots` provides type-safe CSS classes for different parts of the field error component. Available slots: `container`, `text`.
#### `styles`
| prop | type | description |
| ----------- | ----------- | --------------------------- |
| `container` | `ViewStyle` | Styles for the container |
| `text` | `TextStyle` | Styles for the text content |
#### FieldErrorRootAnimation
Animation configuration for field error root component. Can be:
* `false` or `"disabled"`: Disable only root animations
* `"disable-all"`: Disable all animations including children
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ---------------- | ---------------------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| 'disable-all' \| boolean` | - | Disable animations while customizing properties |
| `entering.value` | `EntryOrExitLayoutType` | `FadeIn` `.duration(150)` `.easing(Easing.out(Easing.ease))` | Custom entering animation for field error |
| `exiting.value` | `EntryOrExitLayoutType` | `FadeOut` `.duration(100)` `.easing(Easing.out(Easing.ease))` | Custom exiting animation for field error |
# InputGroup
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/input-group
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(forms)/input-group.mdx
> A compound layout component that groups an input with optional prefix and suffix decorators.
## Import
```tsx
import { InputGroup } from 'heroui-native';
```
## Anatomy
```tsx
...
...
```
* **InputGroup**: Layout container that wraps Prefix, Input, and Suffix. Provides animation settings and a measurement context so Prefix/Suffix widths are automatically applied as padding on the Input.
* **InputGroup.Prefix**: Absolutely positioned View anchored to the left side of the Input. Its measured width is applied as `paddingLeft` on InputGroup.Input automatically.
* **InputGroup.Suffix**: Absolutely positioned View anchored to the right side of the Input. Its measured width is applied as `paddingRight` on InputGroup.Input automatically.
* **InputGroup.Input**: Pass-through to the Input component. Accepts all Input props directly. Automatically receives paddingLeft/paddingRight from measured Prefix/Suffix.
## Usage
### Basic Usage
The InputGroup component uses compound parts to attach prefix and suffix content to an input.
```tsx
...
...
```
### With Prefix Only
Attach leading content such as icons to the input.
```tsx
```
### With Suffix Only
Attach trailing content such as icons to the input.
```tsx
```
### Decorative vs Interactive
Set `isDecorative` on Prefix or Suffix to make touches pass through to the Input and hide the content from screen readers. Omit it when the decorator contains interactive elements.
```tsx
```
### Disabled State
Disable the entire input group. The disabled state cascades to all child components.
```tsx
```
### With TextField Integration
Combine with TextField, Label, and Description for full form field support.
```tsx
Email
We'll never share your email
```
## Example
```tsx
import { InputGroup } from 'heroui-native';
import { Ionicons } from '@expo/vector-icons';
import { useState } from 'react';
import { Pressable, View } from 'react-native';
export default function InputGroupExample() {
const [value, setValue] = useState('');
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
return (
setIsPasswordVisible(!isPasswordVisible)}
hitSlop={20}
>
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/input-group.tsx).
## API Reference
### InputGroup
| prop | type | default | description |
| -------------- | ------------------------- | ------- | ------------------------------------------------------------ |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside the input group |
| `className` | `string` | - | Additional CSS classes |
| `isDisabled` | `boolean` | `false` | Whether the entire input group and its children are disabled |
| `animation` | `AnimationRootDisableAll` | - | Animation configuration for input group |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### AnimationRootDisableAll
Animation configuration for the InputGroup root component. Can be:
* `"disable-all"`: Disable all animations including children (cascades down)
* `undefined`: Use default animations
### InputGroup.Prefix
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Content to render inside the prefix |
| `className` | `string` | - | Additional CSS classes |
| `isDecorative` | `boolean` | `false` | When true, touches pass through to the Input and content is hidden from screen readers |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### InputGroup.Suffix
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Content to render inside the suffix |
| `className` | `string` | - | Additional CSS classes |
| `isDecorative` | `boolean` | `false` | When true, touches pass through to the Input and content is hidden from screen readers |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### InputGroup.Input
Pass-through to the [Input](./input) component. Accepts all Input props directly.
# InputOTP
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/input-otp
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(forms)/input-otp.mdx
> Input component for entering one-time passwords (OTP) with individual character slots, animations, and validation support.
## Import
```tsx
import { InputOTP } from 'heroui-native';
```
## Anatomy
```tsx
```
* **InputOTP**: Main container that manages OTP input state, handles text changes, and provides context to child components. Manages focus, validation, and character input.
* **InputOTP.Group**: Container for grouping multiple slots together. Use this to visually group related slots (e.g., groups of 3 digits).
* **InputOTP.Slot**: Individual slot that displays a single character or placeholder. Each slot must have a unique index matching its position in the OTP sequence. When no children are provided, automatically renders SlotPlaceholder, SlotValue, and SlotCaret.
* **InputOTP.SlotBackground**: Optional theme-aware background container rendered behind the slot content. Mounted automatically, with the active theme deciding the default content (e.g. `glass`); the fallback color follows the slot variant (`primary` → field token, `secondary` → default token). Replace or remove it via the `background` prop on `InputOTP.Slot`.
* **InputOTP.SlotPlaceholder**: Text component that displays the placeholder character for a slot when it's empty. Used by default in Slot if no children provided.
* **InputOTP.SlotValue**: Text component that displays the actual character value for a slot with animations. Used by default in Slot if no children provided.
* **InputOTP.SlotCaret**: Animated caret indicator that shows the current input position. Place this inside a Slot to show where the user is currently typing.
* **InputOTP.Separator**: Visual separator between groups of slots. Use this to visually separate different groups of OTP digits.
## Usage
### Basic Usage
Create a 6-digit OTP input with grouped slots and separator.
```tsx
console.log(code)}>
```
### Four Digits
Create a simple 4-digit PIN input.
```tsx
console.log(code)}>
```
### With Placeholder
Provide custom placeholder characters for each slot position.
```tsx
console.log(code)}
>
{({ slots }) => (
<>
{slots.map((slot) => (
))}
>
)}
```
### Controlled Value
Control the OTP value programmatically.
```tsx
const [value, setValue] = useState('');
;
```
### With Validation
Display validation errors when the OTP is invalid.
```tsx
```
### With Pattern
Restrict input to specific character patterns using regex. Three predefined patterns are available: `REGEXP_ONLY_DIGITS` (matches digits 0-9), `REGEXP_ONLY_CHARS` (matches alphabetic characters a-z, A-Z), and `REGEXP_ONLY_DIGITS_AND_CHARS` (matches both digits and alphabetic characters).
```tsx
import { InputOTP, REGEXP_ONLY_CHARS } from 'heroui-native';
console.log(code)}
>
;
```
### Custom Layout
Use render props in Group to create custom slot layouts.
```tsx
{({ slots, isFocused, isInvalid }) => (
<>
{slots.map((slot) => (
))}
>
)}
```
### Inside a Bottom Sheet
When rendering an InputOTP inside a `BottomSheet`, use the `useBottomSheetAwareHandlers` hook to wire keyboard avoidance handlers. Pass the returned `onFocus` and `onBlur` to InputOTP.
> **Note**: `useBottomSheetAwareHandlers` must be used inside a `BottomSheet`. Call it from a child component rendered inside `BottomSheet.Content` — outside of a `BottomSheet` context the returned handlers are no-ops.
```tsx
import { InputOTP, useBottomSheetAwareHandlers } from 'heroui-native';
const BottomSheetOTPInput = () => {
const { onFocus, onBlur } = useBottomSheetAwareHandlers();
return (
);
};
```
## Example
```tsx
import { InputOTP, Label, Description, type InputOTPRef } from 'heroui-native';
import { View } from 'react-native';
import { useRef } from 'react';
export default function InputOTPExample() {
const ref = useRef(null);
const onComplete = (code: string) => {
console.log('OTP completed:', code);
setTimeout(() => {
ref.current?.clear();
}, 1000);
};
return (
Verify account
We've sent a code to a****@gmail.com
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/input-otp.tsx).
## API Reference
### InputOTP
| prop | type | default | description |
| -------------------------- | ----------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------- |
| `maxLength` | `number` | - | Maximum length of the OTP (required) |
| `value` | `string` | - | Controlled value for the OTP input |
| `defaultValue` | `string` | - | Default value for uncontrolled usage |
| `onChange` | `(value: string) => void` | - | Callback when value changes |
| `onComplete` | `(value: string) => void` | - | Handler called when all slots are filled |
| `isDisabled` | `boolean` | `false` | Whether the input is disabled |
| `isInvalid` | `boolean` | `false` | Whether the input is in an invalid state |
| `pattern` | `string` | - | Regex pattern for allowed characters (e.g., REGEXP\_ONLY\_DIGITS, REGEXP\_ONLY\_CHARS) |
| `inputMode` | `TextInputProps['inputMode']` | `'numeric'` | Input mode for the input |
| `placeholder` | `string` | - | Placeholder text for the input. Each character corresponds to a slot position |
| `placeholderTextColor` | `string` | - | Placeholder text color for all slots |
| `placeholderTextClassName` | `string` | - | Placeholder text class name for all slots |
| `pasteTransformer` | `(text: string) => string` | - | Transform pasted text (e.g., remove hyphens). Defaults to removing non-matching characters |
| `onFocus` | `(e: FocusEvent) => void` | - | Handler for focus events |
| `onBlur` | `(e: BlurEvent) => void` | - | Handler for blur events |
| `textInputProps` | `Omit` | - | Additional props to pass to the underlying TextInput component |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside the InputOTP |
| `className` | `string` | - | Additional CSS classes to apply |
| `style` | `PressableProps['style']` | - | Style to pass to the container Pressable component |
| `isBottomSheetAware` | `boolean` | `true` | Whether the InputOTP automatically handles keyboard state when rendered inside a BottomSheet. Set to `false` to disable |
| `animation` | `"disable-all" \| undefined` | `undefined` | Animation configuration. Use `"disable-all"` to disable all animations including children |
### InputOTP.Group
| prop | type | default | description |
| -------------- | --------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------ |
| `children` | `React.ReactNode \| ((props: InputOTPGroupRenderProps) => React.ReactNode)` | - | Children elements to be rendered inside the group, or a render function that receives slot data and other context values |
| `className` | `string` | - | Additional CSS classes to apply |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### InputOTPGroupRenderProps
| prop | type | description |
| ------------ | ------------ | ---------------------------------------- |
| `slots` | `SlotData[]` | Array of slot data for each position |
| `maxLength` | `number` | Maximum length of the OTP |
| `value` | `string` | Current OTP value |
| `isFocused` | `boolean` | Whether the input is currently focused |
| `isDisabled` | `boolean` | Whether the input is disabled |
| `isInvalid` | `boolean` | Whether the input is in an invalid state |
### InputOTP.Slot
| prop | type | default | description |
| -------------- | ----------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `index` | `number` | - | Zero-based index of the slot (required). Must be between 0 and maxLength - 1 |
| `children` | `React.ReactNode` | - | Custom slot content. If not provided, defaults to SlotPlaceholder, SlotValue, and SlotCaret |
| `className` | `string` | - | Additional CSS classes to apply |
| `style` | `ViewStyle` | - | Additional styles to apply |
| `background` | `React.ReactNode` | - | Background layer behind the slot content. `undefined` renders the theme-aware default (fallback color follows the variant: primary → field token, secondary → default token); custom node replaces it; `null` removes it |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### InputOTP.SlotBackground
Absolute-fill container rendered behind the slot content. With no children, the active library theme decides the default content (e.g. a glass blur layer); pass children to host custom content with the same positioning and clipping.
| prop | type | default | description |
| --------------- | ----------------- | --------- | ---------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom content inside the background container |
| `className` | `string` | - | Additional CSS classes |
| `fallbackColor` | `ThemeColor` | `'field'` | Theme color token used as the opaque fallback on platforms without native blur (Android / web) |
| `...ViewProps` | `ViewProps` | - | All standard View props are supported |
### InputOTP.SlotPlaceholder
| prop | type | default | description |
| -------------- | ----------- | ------- | -------------------------------------------------------------------- |
| `children` | `string` | - | Text content to display (optional, defaults to slot.placeholderChar) |
| `className` | `string` | - | Additional CSS classes to apply |
| `style` | `TextStyle` | - | Additional styles to apply |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
### InputOTP.SlotValue
| prop | type | default | description |
| -------------- | ---------------------------- | ------- | --------------------------------------------------------- |
| `children` | `string` | - | Text content to display (optional, defaults to slot.char) |
| `className` | `string` | - | Additional CSS classes to apply |
| `animation` | `InputOTPSlotValueAnimation` | - | Animation configuration for SlotValue |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
#### InputOTPSlotValueAnimation
Animation configuration for InputOTP.SlotValue component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ------------------ | ----------------------- | ---------------------------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `wrapper.entering` | `EntryOrExitLayoutType` | `FadeIn.duration(250)` | Entering animation for wrapper |
| `wrapper.exiting` | `EntryOrExitLayoutType` | `FadeOut.duration(100)` | Exiting animation for wrapper |
| `text.entering` | `EntryOrExitLayoutType` | `FlipInXDown.duration(250).easing(...)` | Entering animation for text |
| `text.exiting` | `EntryOrExitLayoutType` | `FlipOutXDown.duration(250).easing(...)` | Exiting animation for text |
### InputOTP.SlotCaret
| prop | type | default | description |
| ----------------------- | ---------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `className` | `string` | - | Additional CSS classes to apply |
| `style` | `ViewStyle` | - | Additional styles to apply |
| `animation` | `InputOTPSlotCaretAnimation` | - | Animation configuration for SlotCaret |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active. When `false`, the animated style is removed and you can implement custom logic |
| `pointerEvents` | `'none' \| 'auto' \| ...` | `'none'` | Pointer events configuration |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### InputOTPSlotCaretAnimation
Animation configuration for InputOTP.SlotCaret component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ------------------ | ----------------------- | ---------- | ----------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `opacity.value` | `[number, number]` | `[0, 1]` | Opacity values \[min, max] |
| `opacity.duration` | `number` | `500` | Animation duration in milliseconds |
| `height.value` | `[number, number]` | `[16, 18]` | Height values \[min, max] in pixels |
| `height.duration` | `number` | `500` | Animation duration in milliseconds |
### InputOTP.Separator
| prop | type | default | description |
| -------------- | ----------- | ------- | -------------------------------------------------- |
| `className` | `string` | - | Additional CSS classes to apply |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
## Hooks
### useInputOTP
Hook to access the InputOTP root context. Must be used within an `InputOTP` component.
```tsx
const { value, maxLength, isFocused, isDisabled, isInvalid, slots } =
useInputOTP();
```
### useInputOTPSlot
Hook to access the InputOTP.Slot context. Must be used within an `InputOTP.Slot` component.
```tsx
const { slot, isActive, isCaretVisible } = useInputOTPSlot();
```
# Input
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/input
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(forms)/input.mdx
> A text input component with styled border and background for collecting user input.
## Import
```tsx
import { Input } from 'heroui-native';
```
## Usage
### Basic Usage
Input can be used standalone or within a TextField component.
```tsx
import { Input } from 'heroui-native';
;
```
### Within TextField
Input works seamlessly with TextField for complete form structure.
```tsx
import { Input, Label, TextField } from 'heroui-native';
Email
;
```
### With Validation
Display error state when the input is invalid.
```tsx
import { FieldError, Input, Label, TextField } from 'heroui-native';
Email
Please enter a valid email
;
```
### With Local Invalid State Override
Override the context's invalid state for the input.
```tsx
import { FieldError, Input, Label, TextField } from 'heroui-native';
Email
Email format is incorrect
;
```
### Disabled State
Disable the input to prevent interaction.
```tsx
import { Input, Label, TextField } from 'heroui-native';
Disabled Field
;
```
### With Variant
Use different variants to style the input based on context.
```tsx
import { Input, Label, TextField } from 'heroui-native';
Primary Variant
Secondary Variant
```
### Custom Styling
Customize the input appearance using className.
```tsx
import { Input, Label, TextField } from 'heroui-native';
Custom Styled
;
```
### Inside a Bottom Sheet
When rendering an Input inside a `BottomSheet`, use the `useBottomSheetAwareHandlers` hook to wire keyboard avoidance handlers. Pass the returned `onFocus` and `onBlur` to the Input.
> **Note**: `useBottomSheetAwareHandlers` must be used inside a `BottomSheet`. Call it from a child component rendered inside `BottomSheet.Content` — outside of a `BottomSheet` context the returned handlers are no-ops.
```tsx
import { Input, TextField, useBottomSheetAwareHandlers } from 'heroui-native';
const BottomSheetTextInput = () => {
const { onFocus, onBlur } = useBottomSheetAwareHandlers();
return (
);
};
```
## Example
```tsx
import { Ionicons } from '@expo/vector-icons';
import { Description, Input, Label, TextField } from 'heroui-native';
import { useState } from 'react';
import { Pressable, View } from 'react-native';
import { withUniwind } from 'uniwind';
const StyledIonicons = withUniwind(Ionicons);
export const TextInputContent = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
return (
Email
We'll never share your email with anyone else.
New password
setIsPasswordVisible(!isPasswordVisible)}
>
Password must be at least 6 characters
);
};
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/input.tsx).
## API Reference
### Input
| prop | type | default | description |
| ------------------------- | -------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| isInvalid | `boolean` | `undefined` | Whether the input is in an invalid state (overrides context) |
| variant | `'primary' \| 'secondary'` | `'primary'` | Variant style for the input |
| className | `string` | - | Custom class name for the input |
| selectionColorClassName | `string` | `"accent-accent"` | Custom className for the selection color |
| placeholderColorClassName | `string` | `"field-placeholder"` | Custom className for the placeholder text color |
| isBottomSheetAware | `boolean` | `true` | Whether the input automatically handles keyboard state when rendered inside a BottomSheet. Set to `false` to disable |
| animation | `AnimationRoot` | `undefined` | Animation configuration for the input |
| background | `React.ReactNode` | - | Background layer behind the text input. `undefined` renders the theme-aware default when the active theme registers default background content (fallback color follows the variant: primary → field token, secondary → default token); custom node replaces it; `null` removes it |
| ...TextInputProps | `TextInputProps` | - | All standard React Native TextInput props are supported |
> **Note**: When used within a TextField component, Input automatically consumes form state (isDisabled, isInvalid) from TextField via the form-item-state context.
### Input.Background
Absolute-fill container rendered behind the text input. With no children, the active library theme decides the default content (e.g. a glass blur layer); pass children to host custom content with the same positioning and clipping.
| prop | type | default | description |
| ------------- | ----------------- | --------- | ---------------------------------------------------------------------------------------------- |
| children | `React.ReactNode` | - | Custom content inside the background container |
| className | `string` | - | Additional CSS classes |
| fallbackColor | `ThemeColor` | `'field'` | Theme color token used as the opaque fallback on platforms without native blur (Android / web) |
| ...ViewProps | `ViewProps` | - | All standard View props are supported |
# Label
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/label
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(forms)/label.mdx
> Text component for labeling form fields and other UI elements with support for required indicators and validation states.
## Import
```tsx
import { Label } from 'heroui-native';
```
## Anatomy
```tsx
...
```
* **Label**: Root container that manages label state and provides context to child components. When string children are provided, automatically renders as Label.Text. Supports disabled, required, and invalid states.
* **Label.Text**: Text content of the label. Displays the label text and automatically shows an asterisk when the label is required. Changes color when invalid or disabled.
## Usage
### Basic Usage
Display a label with text content. String children are automatically rendered as Label.Text.
```tsx
Username
```
### With Form Fields
Use Label with form fields to provide accessible labels.
```tsx
Username
```
### Required Fields
Show an asterisk indicator for required fields using the `isRequired` prop.
```tsx
Password
```
### Invalid State
Display labels in an invalid state to indicate validation errors.
```tsx
import { FieldError, Label, TextField } from 'heroui-native';
Confirm password
Passwords do not match
```
### Disabled State
Disable labels to indicate non-interactive fields.
```tsx
Subscription plan
```
### Custom Layout
Use compound components for custom label layouts.
```tsx
Custom label
```
### Custom Styling
Apply custom styles using className, classNames, or styles props.
```tsx
Custom styled label
```
## Example
```tsx
import { FieldError, Label, TextField } from 'heroui-native';
import { View } from 'react-native';
export default function LabelExample() {
return (
Username
Password
Confirm password
Passwords do not match
Subscription plan
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/label.tsx).
## API Reference
### Label
| prop | type | default | description |
| ------------------- | ---------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Label content. When string is provided, automatically renders as Label.Text. Otherwise renders children as-is |
| `isRequired` | `boolean` | `false` | Whether the label is required. Shows asterisk indicator when true |
| `isInvalid` | `boolean` | `false` | Whether the label is in an invalid state. Changes text color to danger |
| `isDisabled` | `boolean` | `false` | Whether the label is disabled. Applies disabled styling and prevents interaction |
| `className` | `string` | - | Additional CSS classes to apply |
| `animation` | `"disable-all" \| undefined` | `undefined` | Animation configuration. Use `"disable-all"` to disable all animations including children |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported |
### Label.Text
| prop | type | default | description |
| -------------- | ---------------------------------------- | ------- | ---------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Label text content |
| `className` | `string` | - | Additional CSS classes to apply to the text element |
| `classNames` | `ElementSlots` | - | Additional CSS classes for different parts of the label |
| `styles` | `Partial>` | - | Styles for different parts of the label |
| `nativeID` | `string` | - | Native ID for accessibility. Used to link label to form fields via aria-labelledby |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
#### `ElementSlots`
| prop | type | description |
| ---------- | -------- | ------------------------------ |
| `text` | `string` | CSS classes for the label text |
| `asterisk` | `string` | CSS classes for the asterisk |
#### `styles`
| prop | type | description |
| ---------- | ----------- | ------------------------- |
| `text` | `TextStyle` | Styles for the label text |
| `asterisk` | `TextStyle` | Styles for the asterisk |
# RadioGroup
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/radio-group
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(forms)/radio-group.mdx
> A set of radio buttons where only one option can be selected at a time.
## Import
```tsx
import { RadioGroup } from 'heroui-native';
```
## Anatomy
```tsx
...
...
...
```
* **RadioGroup**: Container that manages the selection state of radio items. Supports both horizontal and vertical orientations.
* **RadioGroup.Item**: Individual radio option within a RadioGroup. Must be used inside RadioGroup. Handles selection state and renders a default ` ` indicator when text children are provided. Supports render function children to access state (`isSelected`, `isInvalid`, `isDisabled`).
* **Label**: Optional clickable text label for the radio option. Linked to the radio for accessibility. Use the [Label](./label) component directly.
* **Description**: Optional secondary text below the label. Provides additional context about the radio option. Use the [Description](./description) component directly.
* **Radio**: The [Radio](./radio) component used inside `RadioGroup.Item` to render the radio indicator. Automatically detects the `RadioGroupItem` context and derives `isSelected`, `isDisabled`, `isInvalid`, and `variant` from it.
* **Radio.Indicator**: Optional container for the radio circle. Renders default thumb if no children provided. Manages the visual selection state. See [Radio](./radio) for full API.
* **Radio.IndicatorBackground**: Optional theme-aware background container rendered behind the indicator content. Mounted automatically for the `secondary` variant while unselected and not invalid, when the active theme registers default background content (e.g. `glass`). Replace or remove it via the `background` prop on `Radio.Indicator`.
* **Radio.IndicatorThumb**: Optional inner circle that appears when selected. Animates scale based on selection. Can be replaced with custom content. See [Radio](./radio) for full API.
* **FieldError**: Error message displayed when radio group is invalid. Shown with animation below the radio group content. Use the [FieldError](./field-error) component directly.
## Usage
### Basic Usage
RadioGroup with simple string children automatically renders title and indicator.
```tsx
Option 1
Option 2
Option 3
```
### With Descriptions
Add descriptive text below each radio option for additional context.
```tsx
import { RadioGroup, Radio, Label, Description } from 'heroui-native';
import { View } from 'react-native';
Standard Shipping
Delivered in 5-7 business days
Express Shipping
Delivered in 2-3 business days
;
```
### Custom Indicator
Replace the default indicator thumb with custom content using `Radio` sub-components.
```tsx
import { RadioGroup, Radio, Label } from 'heroui-native';
{({ isSelected }) => (
<>
Custom Option
{isSelected && (
)}
>
)}
;
```
### With Render Function
Use a render function on RadioGroup.Item to access state and customize the entire content.
```tsx
import { RadioGroup, Radio, Label } from 'heroui-native';
{({ isSelected, isInvalid, isDisabled }) => (
<>
Option 1
{isSelected && }
>
)}
;
```
### With Error Message
Display validation errors below the radio group.
```tsx
import { RadioGroup, FieldError } from 'heroui-native';
function RadioGroupWithError() {
const [value, setValue] = React.useState(undefined);
return (
I agree to the terms
I do not agree
Please select an option to continue
);
}
```
## Example
```tsx
import {
Description,
Label,
Radio,
RadioGroup,
Separator,
Surface,
} from 'heroui-native';
import React from 'react';
import { View } from 'react-native';
export default function RadioGroupExample() {
const [selection, setSelection] = React.useState('desc1');
return (
Standard Shipping
Delivered in 5-7 business days
Express Shipping
Delivered in 2-3 business days
Overnight Shipping
Delivered next business day
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/radio-group.tsx).
## API Reference
### RadioGroup
| prop | type | default | description |
| --------------- | ---------------------------- | ----------- | ----------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | `undefined` | Radio group content |
| `value` | `string \| undefined` | `undefined` | The currently selected value of the radio group |
| `onValueChange` | `(val: string) => void` | `undefined` | Callback fired when the selected value changes |
| `isDisabled` | `boolean` | `false` | Whether the entire radio group is disabled |
| `isInvalid` | `boolean` | `false` | Whether the radio group is invalid |
| `variant` | `'primary' \| 'secondary'` | `undefined` | Variant style for the radio group (inherited by items if not set on item) |
| `animation` | `"disable-all" \| undefined` | `undefined` | Animation configuration. Use `"disable-all"` to disable all animations including children |
| `className` | `string` | `undefined` | Custom class name |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### RadioGroup.Item
| prop | type | default | description |
| ------------------- | ---------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------- |
| `children` | `React.ReactNode \| ((props: RadioGroupItemRenderProps) => React.ReactNode)` | `undefined` | Radio item content or render function to customize the radio item |
| `value` | `string` | `undefined` | The value associated with this radio item |
| `isDisabled` | `boolean` | `false` | Whether this specific radio item is disabled |
| `isInvalid` | `boolean` | `false` | Whether the radio item is invalid |
| `variant` | `'primary' \| 'secondary'` | `'primary'` | Variant style for the radio item |
| `hitSlop` | `number` | `6` | Hit slop for the pressable area |
| `className` | `string` | `undefined` | Custom class name |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported (except disabled) |
#### RadioGroupItemRenderProps
| prop | type | description |
| ------------ | --------- | ---------------------------------- |
| `isSelected` | `boolean` | Whether the radio item is selected |
| `isInvalid` | `boolean` | Whether the radio item is invalid |
| `isDisabled` | `boolean` | Whether the radio item is disabled |
### Radio (inside RadioGroup.Item)
The `Radio` component is used inside `RadioGroup.Item` to render the radio indicator. When placed inside a `RadioGroup.Item`, the Radio component automatically detects the `RadioGroupItem` context and derives `isSelected`, `isDisabled`, `isInvalid`, and `variant` from it — no manual prop passing is needed.
Use ` ` for the default indicator, or compose with `Radio.Indicator` and `Radio.IndicatorThumb` for custom styling.
| prop | type | default | description |
| ------------------- | ------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------- |
| `children` | `React.ReactNode \| ((props: RadioRenderProps) => React.ReactNode)` | `undefined` | Child elements or render function to customize the radio |
| `variant` | `'primary' \| 'secondary'` | `'primary'` | Variant style for the radio |
| `isSelected` | `boolean` | `undefined` | Whether the radio is currently selected |
| `isDisabled` | `boolean` | `undefined` | Whether the radio is disabled and cannot be interacted with |
| `isInvalid` | `boolean` | `false` | Whether the radio is invalid (shows danger color) |
| `className` | `string` | `undefined` | Additional CSS classes to apply |
| `animation` | `RadioRootAnimation` | - | Animation configuration for radio |
| `onSelectedChange` | `(isSelected: boolean) => void` | `undefined` | Callback fired when the radio selection state changes |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported (except disabled) |
#### RadioRenderProps
| prop | type | description |
| ------------ | --------- | ----------------------------- |
| `isSelected` | `boolean` | Whether the radio is selected |
| `isDisabled` | `boolean` | Whether the radio is disabled |
| `isInvalid` | `boolean` | Whether the radio is invalid |
#### RadioRootAnimation
Animation configuration for radio root component. Can be:
* `"disable-all"`: Disable all animations including children (Indicator, IndicatorThumb)
* `undefined`: Use default animations
### Radio.Indicator
| prop | type | default | description |
| ---------------------- | -------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | `undefined` | Content for the radio indicator |
| `className` | `string` | `undefined` | Additional CSS classes for the indicator |
| `background` | `React.ReactNode` | - | Background layer behind the indicator content. `undefined` renders the theme-aware default for the `secondary` variant while unselected and not invalid; custom node replaces it; `null` removes it |
| `...AnimatedViewProps` | `AnimatedProps` | - | All Reanimated Animated.View props are supported |
### Radio.IndicatorBackground
Absolute-fill container rendered behind the indicator content. With no children, the active library theme decides the default content (e.g. a glass blur layer); pass children to host custom content with the same positioning and clipping.
| prop | type | default | description |
| -------------- | ----------------- | ------- | ---------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom content inside the background container |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard View props are supported |
### Radio.IndicatorThumb
| prop | type | default | description |
| ----------------------- | ------------------------------ | ----------- | ------------------------------------------------------------ |
| `className` | `string` | `undefined` | Additional CSS classes for the thumb |
| `animation` | `RadioIndicatorThumbAnimation` | - | Animation configuration for the thumb |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `...AnimatedViewProps` | `AnimatedProps` | - | All Reanimated Animated.View props are supported |
#### RadioIndicatorThumbAnimation
Animation configuration for radio indicator thumb component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| -------------------- | ----------------------- | ---------------------------------------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `scale.value` | `[number, number]` | `[1.5, 1]` | Scale values \[unselected, selected] |
| `scale.timingConfig` | `WithTimingConfig` | `{ duration: 300, easing: Easing.out(Easing.ease) }` | Animation timing configuration |
**Note:** For labels, descriptions, and error messages, use the base components directly:
* Use [Label](../label/label.md) component for labels
* Use [Description](../description/description.md) component for descriptions
* Use [FieldError](../field-error/field-error.md) component for error messages
## Hooks
### useRadioGroup
**Returns:**
| Property | Type | Description |
| --------------- | -------------------------- | ---------------------------------------------- |
| `value` | `string \| undefined` | Currently selected value |
| `isDisabled` | `boolean` | Whether the radio group is disabled |
| `isInvalid` | `boolean` | Whether the radio group is in an invalid state |
| `variant` | `'primary' \| 'secondary'` | Variant style for the radio group |
| `onValueChange` | `(value: string) => void` | Function to change the selected value |
### useRadioGroupItem
**Returns:**
| Property | Type | Description |
| ------------------ | ---------------------------------------------- | ----------------------------------------------------------------------- |
| `isSelected` | `boolean` | Whether the radio item is selected |
| `isDisabled` | `boolean \| undefined` | Whether the radio item is disabled |
| `isInvalid` | `boolean \| undefined` | Whether the radio item is invalid |
| `variant` | `'primary' \| 'secondary' \| undefined` | Variant style for the radio item |
| `onSelectedChange` | `((isSelected: boolean) => void) \| undefined` | Callback to change the selection state (selects this item in the group) |
# SearchField
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/search-field
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(forms)/search-field.mdx
> A compound search input for filtering and querying content.
## Import
```tsx
import { SearchField } from 'heroui-native';
```
## Anatomy
```tsx
```
* **SearchField**: Root container that accepts `value` and `onChange`, providing them to children via context. Also provides form field state (isDisabled, isInvalid, isRequired) and animation settings.
* **SearchField.Group**: Flex-row container that positions the search icon, input, and clear button horizontally.
* **SearchField.SearchIcon**: *(Optional)* Magnifying glass icon positioned absolutely on the left side of the input. Supports custom children to replace the default icon. When omitted, the Input does not reserve leading space.
* **SearchField.Input**: Wraps the Input component with search-specific defaults. Reads `value` and `onChangeText` from the SearchField context automatically. Reserves leading and trailing space only when SearchIcon and ClearButton are composed.
* **SearchField.ClearButton**: *(Optional)* Small icon-only button to clear the search input. Automatically hidden when value is empty. Calls `onChange("")` from context on press. When omitted, the Input does not reserve trailing space; when composed but hidden (empty value), trailing padding stays so text does not jump on first keystroke.
## Usage
### Basic Usage
The SearchField component uses compound parts to create a search input. Pass `value` and `onChange` to the root; the Input and ClearButton consume them via context.
```tsx
```
### Without Search Icon
Omit `SearchField.SearchIcon` to drop the leading magnifier and its reserved padding. The Input reclaims the space automatically.
```tsx
```
Omitting `ClearButton` as well removes the trailing space. When `ClearButton` is composed but hidden (the value is empty), trailing padding stays so text does not jump on the first keystroke.
Add a Label and Description outside the Group to provide context for the search field.
```tsx
Find products
Search by name, category, or SKU
```
### With Validation
Use `isInvalid` and `isRequired` on the root to control validation state. Pair with FieldError to display error messages.
```tsx
Search users
Enter at least 3 characters to search
No results found. Please try a different search term.
```
### Custom Search Icon
Replace the default magnifying glass icon by passing children to `SearchField.SearchIcon`.
```tsx
🔍
```
### Disabled
Set `isDisabled` on the root to disable all child components via context.
```tsx
Disabled search
Search is temporarily unavailable
```
## Example
```tsx
import { Description, Label, SearchField } from 'heroui-native';
import { useState } from 'react';
import { View } from 'react-native';
export default function SearchFieldExample() {
const [searchValue, setSearchValue] = useState('');
return (
Find products
Search by name, category, or SKU
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/search-field.tsx).
## API Reference
### SearchField
| prop | type | default | description |
| -------------- | ------------------------- | ------- | -------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside the search field |
| `value` | `string` | - | Controlled search text value |
| `onChange` | `(value: string) => void` | - | Callback fired when the search text changes |
| `isDisabled` | `boolean` | `false` | Whether the search field is disabled |
| `isInvalid` | `boolean` | `false` | Whether the search field is in an invalid state |
| `isRequired` | `boolean` | `false` | Whether the search field is required |
| `className` | `string` | - | Additional CSS classes |
| `animation` | `AnimationRootDisableAll` | - | Animation configuration for the search field |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### AnimationRootDisableAll
Animation configuration for the SearchField root component. Can be:
* `"disable-all"`: Disable all animations including children (cascades down)
* `undefined`: Use default animations
### SearchField.Group
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside the group |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### SearchField.SearchIcon
| prop | type | default | description |
| -------------- | -------------------------------- | ------- | ---------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom content to replace the default search icon |
| `className` | `string` | - | Additional CSS classes |
| `iconProps` | `SearchFieldSearchIconIconProps` | - | Props for customizing the default search icon (ignored when children are provided) |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### SearchFieldSearchIconIconProps
| prop | type | default | description |
| ------- | -------- | ------------------- | ----------------- |
| `size` | `number` | `16` | Size of the icon |
| `color` | `string` | Theme `muted` color | Color of the icon |
### SearchField.Input
Extends [Input](./input) props with search-specific defaults (`placeholder="Search..."`, `returnKeyType="search"`, `accessibilityRole="search"`). Omits `value` and `onChangeText` because they are provided by the SearchField context.
### SearchField.ClearButton
Automatically hidden when the controlled `value` is an empty string. Calls `onChange("")` from context on press. Additional `onPress` handlers passed via props are called after clearing.
| prop | type | default | description |
| ---------------- | --------------------------------- | ------- | ------------------------------------------------ |
| `children` | `React.ReactNode` | - | Custom content to replace the default close icon |
| `iconProps` | `SearchFieldClearButtonIconProps` | - | Props for customizing the clear button icon |
| `className` | `string` | - | Additional CSS classes |
| `...ButtonProps` | `ButtonRootProps` | - | All Button root props are supported |
#### SearchFieldClearButtonIconProps
| prop | type | default | description |
| ------- | -------- | ------------------- | ----------------- |
| `size` | `number` | `14` | Size of the icon |
| `color` | `string` | Theme `muted` color | Color of the icon |
## Hooks
### useSearchField
Hook to access the search field state from context. Must be used within a `SearchField` component.
```tsx
import { useSearchField } from 'heroui-native';
const { value, onChange, isDisabled, isInvalid, isRequired } = useSearchField();
```
#### Returns
| property | type | description |
| ------------ | ---------------------------------------- | ----------------------------------------------- |
| `value` | `string \| undefined` | Current controlled search text value |
| `onChange` | `((value: string) => void) \| undefined` | Callback to update the search text |
| `isDisabled` | `boolean` | Whether the search field is disabled |
| `isInvalid` | `boolean` | Whether the search field is in an invalid state |
| `isRequired` | `boolean` | Whether the search field is required |
# Select
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/select
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(forms)/select.mdx
> Displays a list of options for the user to pick from — triggered by a button.
## Import
```tsx
import { Select } from 'heroui-native';
```
## Anatomy
```tsx
...
...
```
* **Select**: Main container that manages open/close state, value selection and provides context to child components.
* **Select.Trigger**: Clickable element that toggles the select visibility. Wraps any child element with press handlers. Supports `variant` prop (`'default'` or `'unstyled'`).
* **Select.Value**: Displays the selected value or placeholder text. Automatically updates when selection changes. Styling changes based on selection state.
* **Select.TriggerIndicator**: Optional visual indicator showing open/close state. Renders an animated chevron icon by default that rotates when the select opens/closes.
* **Select.Portal**: Renders select content in a portal layer above other content. Ensures proper stacking and positioning.
* **Select.Overlay**: Optional background overlay. Can be transparent or semi-transparent to capture outside clicks.
* **Select.Content**: Container for select content with three presentation modes: popover (floating with positioning), bottom sheet modal, or dialog modal.
* **Select.Close**: Close button for the select. Can accept custom children or uses default close icon.
* **Select.ListLabel**: Label for the list of items with pre-styled typography.
* **Select.Item**: Selectable option item. Handles selection state and press events.
* **Select.ItemLabel**: Displays the label text for an item.
* **Select.ItemDescription**: Optional description text for items with muted styling.
* **Select.ItemIndicator**: Optional indicator shown for selected items. Renders a check icon by default.
## Usage
### Basic Usage
The Select component uses compound parts to create dropdown selection interfaces.
```tsx
...
```
### With Value Display
Display the selected value in the trigger using the Value component.
```tsx
```
### Popover Presentation
Use popover presentation for floating content with automatic positioning.
```tsx
...
```
### Width Control
Control the width of the select content using the `width` prop. This only works with popover presentation.
```tsx
{
/* Fixed width in pixels */
}
...
;
{
/* Match trigger width */
}
...
;
{
/* Full width (100%) */
}
...
;
{
/* Auto-size to content (default) */
}
...
;
```
### Bottom Sheet Presentation
Use bottom sheet for mobile-optimized selection experience.
```tsx
...
```
### Dialog Presentation
Use dialog presentation for centered modal-style selection.
```tsx
...
Choose an option
```
### Custom Item Content
Customize item appearance with custom content and indicators.
```tsx
...
🇺🇸
🇬🇧
```
### With Render Function
Use a render function on `Select.Item` to access state and customize content based on selection.
```tsx
...
{({ isSelected, value, isDisabled }) => (
<>
🇺🇸
>
)}
{({ isSelected }) => (
<>
🇬🇧
>
)}
```
### With Item Description
Add descriptions to items for additional context.
```tsx
...
Essential features for personal use
```
### With Trigger Indicator
Add a visual indicator to show the open/close state of the select. The indicator rotates when the select opens/closes.
```tsx
```
### Custom Trigger with Unstyled Variant
Use the `unstyled` variant when composing a custom trigger with other components like Button.
```tsx
```
### Controlled Mode
Control the select state programmatically.
```tsx
const [value, setValue] = useState();
const [isOpen, setIsOpen] = useState(false);
;
```
## Example
```tsx
import { Select, Separator } from 'heroui-native';
import React, { useState } from 'react';
type SelectOption = {
value: string;
label: string;
};
const US_STATES: SelectOption[] = [
{ value: 'CA', label: 'California' },
{ value: 'NY', label: 'New York' },
{ value: 'TX', label: 'Texas' },
{ value: 'FL', label: 'Florida' },
];
export default function SelectExample() {
const [value, setValue] = useState();
return (
Choose a state
{US_STATES.map((state, index) => (
{index < US_STATES.length - 1 && }
))}
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/select.tsx).
## API Reference
### Select
| prop | type | default | description |
| --------------- | ------------------------------------------------- | ----------- | ---------------------------------------------------------------------- |
| `children` | `ReactNode` | - | The content of the select |
| `value` | `SelectOption \| SelectOption[]` | - | The selected value(s) (controlled mode) |
| `onValueChange` | `(value: SelectOption \| SelectOption[]) => void` | - | Callback when the value changes |
| `defaultValue` | `SelectOption \| SelectOption[]` | - | The default selected value(s) (uncontrolled mode) |
| `isOpen` | `boolean` | - | Whether the select is open (controlled mode) |
| `isDefaultOpen` | `boolean` | - | Whether the select is open when initially rendered (uncontrolled mode) |
| `onOpenChange` | `(isOpen: boolean) => void` | - | Callback when the select open state changes |
| `isDisabled` | `boolean` | `false` | Whether the select is disabled |
| `presentation` | `'popover' \| 'bottom-sheet' \| 'dialog'` | `'popover'` | Presentation mode for the select content |
| `animation` | `SelectRootAnimation` | - | Animation configuration |
| `asChild` | `boolean` | `false` | Whether to render as a child element |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### SelectRootAnimation
Animation configuration for Select component. Can be:
* `false` or `"disabled"`: Disable only root animations
* `"disable-all"`: Disable all animations including children
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ---------------- | ------------------------------------------------ | ------- | ----------------------------------------------- |
| `state` | `'disabled' \| 'disable-all' \| boolean` | - | Disable animations while customizing properties |
| `entering.value` | `SpringAnimationConfig \| TimingAnimationConfig` | - | Animation configuration for when select opens |
| `exiting.value` | `SpringAnimationConfig \| TimingAnimationConfig` | - | Animation configuration for when select closes |
#### SpringAnimationConfig
| prop | type | default | description |
| -------- | ------------------ | ------- | ----------------------------------------- |
| `type` | `'spring'` | - | Animation type (must be `'spring'`) |
| `config` | `WithSpringConfig` | - | Reanimated spring animation configuration |
#### TimingAnimationConfig
| prop | type | default | description |
| -------- | ------------------ | ------- | ----------------------------------------- |
| `type` | `'timing'` | - | Animation type (must be `'timing'`) |
| `config` | `WithTimingConfig` | - | Reanimated timing animation configuration |
### Select.Trigger
| prop | type | default | description |
| ------------------- | ------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------- |
| `variant` | `'default' \| 'unstyled'` | `'default'` | The variant of the trigger. `'default'` applies pre-styled container styles, `'unstyled'` removes default styling |
| `children` | `ReactNode` | - | The trigger element content |
| `className` | `string` | - | Additional CSS classes for the trigger |
| `asChild` | `boolean` | `true` | Whether to render as a child element |
| `isDisabled` | `boolean` | - | Whether the trigger is disabled |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported |
### Select.Value
| prop | type | default | description |
| -------------- | ----------- | ------- | -------------------------------------------------- |
| `placeholder` | `string` | - | Placeholder text when no value is selected |
| `className` | `string` | - | Additional CSS classes for the value |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
**Note:** The value component automatically applies different text colors based on selection state:
* When a value is selected: `text-foreground`
* When no value is selected (placeholder): `text-field-placeholder`
### Select.TriggerIndicator
| prop | type | default | description |
| ----------------------- | --------------------------------- | ------- | ------------------------------------------------------------ |
| `children` | `ReactNode` | - | Custom indicator content. Defaults to animated chevron icon |
| `className` | `string` | - | Additional CSS classes for the trigger indicator |
| `style` | `ViewStyle` | - | Custom styles for the trigger indicator |
| `iconProps` | `SelectTriggerIndicatorIconProps` | - | Chevron icon configuration |
| `animation` | `SelectTriggerIndicatorAnimation` | - | Animation configuration |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
**Note:** The following style properties are occupied by animations and cannot be set via className:
* `transform` (specifically `rotate`) - Animated for open/close rotation transitions
To customize this property, use the `animation` prop. To completely disable animated styles and use your own via className or style prop, set `isAnimatedStyleActive={false}`.
#### SelectTriggerIndicatorIconProps
| prop | type | default | description |
| ------- | -------- | ------- | ------------------------------------------------------ |
| `size` | `number` | `16` | Size of the icon |
| `color` | `string` | - | Color of the icon (defaults to foreground theme color) |
#### SelectTriggerIndicatorAnimation
Animation configuration for Select.TriggerIndicator component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations (rotation from 0° to -180°)
* `object`: Custom animation configuration
| prop | type | default | description |
| ----------------------- | ----------------------- | -------------------------------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `rotation.value` | `[number, number]` | `[0, -180]` | Rotation values \[closed, open] in degrees |
| `rotation.springConfig` | `WithSpringConfig` | `{ damping: 140, stiffness: 1000, mass: 4 }` | Spring animation configuration for rotation |
### Select.Portal
| prop | type | default | description |
| -------------------------------------------- | ----------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | `ReactNode` | - | The portal content (required) |
| `disableFullWindowOverlay` | `boolean` | `false` | When true on iOS, uses View instead of FullWindowOverlay. Enables element inspector; overlay won't appear above native modals |
| `unstable_accessibilityContainerViewIsModal` | `boolean` | `false` | Controls whether VoiceOver treats the overlay window as a modal container. When `true`, VoiceOver is restricted to elements inside the overlay. iOS only. Unstable: may change with react-native-screens updates |
| `className` | `string` | - | Additional CSS classes for the portal container |
| `hostName` | `string` | - | Optional name of the host element for the portal |
| `forceMount` | `boolean` | - | Whether to force mount the component in the DOM |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### Select.Overlay
| prop | type | default | description |
| ----------------------- | ------------------------ | ------- | ------------------------------------------------------------ |
| `className` | `string` | - | Additional CSS classes for the overlay |
| `animation` | `SelectOverlayAnimation` | - | Animation configuration |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `closeOnPress` | `boolean` | `true` | Whether to close the select when overlay is pressed |
| `forceMount` | `boolean` | - | Whether to force mount the component in the DOM |
| `asChild` | `boolean` | `false` | Whether to render as a child element |
| `...Animated.ViewProps` | `Animated.ViewProps` | - | All Reanimated Animated.View props are supported |
#### SelectOverlayAnimation
Animation configuration for Select.Overlay component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations (progress-based opacity for bottom-sheet/dialog, Keyframe animations for popover)
* `object`: Custom animation configuration
| prop | type | default | description |
| --------------- | -------------------------- | ----------- | ---------------------------------------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `opacity.value` | `[number, number, number]` | `[0, 1, 0]` | Opacity values \[idle, open, close] (for bottom-sheet/dialog presentation) |
| `entering` | `EntryOrExitLayoutType` | - | Custom Keyframe animation for entering transition (for popover presentation) |
| `exiting` | `EntryOrExitLayoutType` | - | Custom Keyframe animation for exiting transition (for popover presentation) |
### Select.Content (Popover Presentation)
| prop | type | default | description |
| ----------------------- | ------------------------------------------------ | --------------- | ------------------------------------------------------ |
| `children` | `ReactNode` | - | The select content |
| `width` | `number \| 'trigger' \| 'content-fit' \| 'full'` | `'content-fit'` | Width sizing strategy for the content |
| `presentation` | `'popover'` | `'popover'` | Presentation mode for the select |
| `placement` | `'top' \| 'bottom' \| 'left' \| 'right'` | `'bottom'` | Placement of the content relative to trigger |
| `align` | `'start' \| 'center' \| 'end'` | `'center'` | Alignment along the placement axis |
| `avoidCollisions` | `boolean` | `true` | Whether to flip placement when close to viewport edges |
| `offset` | `number` | `8` | Distance from trigger element in pixels |
| `alignOffset` | `number` | `0` | Offset along the alignment axis in pixels |
| `className` | `string` | - | Additional CSS classes for the content container |
| `animation` | `SelectContentPopoverAnimation` | - | Animation configuration |
| `forceMount` | `boolean` | - | Whether to force mount the component in the DOM |
| `insets` | `Insets` | - | Screen edge insets to respect when positioning |
| `asChild` | `boolean` | `false` | Whether to render as a child element |
| `...Animated.ViewProps` | `Animated.ViewProps` | - | All Reanimated Animated.View props are supported |
#### SelectContentPopoverAnimation
Animation configuration for Select.Content component (popover presentation). Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default Keyframe animations (translateY/translateX, scale, opacity based on placement)
* `object`: Custom animation configuration with `entering` and/or `exiting` Keyframe animations
| prop | type | default | description |
| ---------- | ----------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `entering` | `EntryOrExitLayoutType` | - | Custom Keyframe animation for entering transition (default: Keyframe with translateY/translateX, scale, opacity based on placement, 200ms) |
| `exiting` | `EntryOrExitLayoutType` | - | Custom Keyframe animation for exiting transition (default: Keyframe mirroring entering animation, 150ms) |
### Select.Content (Bottom Sheet Presentation)
| prop | type | default | description |
| --------------------------- | ------------------ | ------- | ------------------------------------------------ |
| `children` | `ReactNode` | - | The bottom sheet content |
| `presentation` | `'bottom-sheet'` | - | Presentation mode for the select |
| `contentContainerClassName` | `string` | - | Additional CSS classes for the content container |
| `...BottomSheetProps` | `BottomSheetProps` | - | All @gorhom/bottom-sheet props are supported |
### Select.Content (Dialog Presentation)
| prop | type | default | description |
| -------------- | -------------------------------------------------------- | ------- | --------------------------------------------------- |
| `children` | `ReactNode` | - | The dialog content |
| `presentation` | `'dialog'` | - | Presentation mode for the select |
| `classNames` | `{ wrapper?: string; content?: string }` | - | Additional CSS classes for wrapper and content |
| `styles` | `Partial>` | - | Styles for different parts of the dialog content |
| `animation` | `SelectContentAnimation` | - | Animation configuration |
| `isSwipeable` | `boolean` | `true` | Whether the dialog content can be swiped to dismiss |
| `forceMount` | `boolean` | - | Whether to force mount the component in the DOM |
| `asChild` | `boolean` | `false` | Whether to render as a child element |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### `styles`
| prop | type | description |
| --------- | ----------- | -------------------------------- |
| `wrapper` | `ViewStyle` | Styles for the wrapper container |
| `content` | `ViewStyle` | Styles for the dialog content |
#### SelectContentAnimation
Animation configuration for Select.Content component (dialog presentation). Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default Keyframe animations (scale and opacity transitions)
* `object`: Custom animation configuration with `entering` and/or `exiting` Keyframe animations
| prop | type | default | description |
| ---------- | ----------------------- | ------- | -------------------------------------------------------------------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `entering` | `EntryOrExitLayoutType` | - | Custom Keyframe animation for entering transition (default: Keyframe with scale and opacity, 200ms) |
| `exiting` | `EntryOrExitLayoutType` | - | Custom Keyframe animation for exiting transition (default: Keyframe mirroring entering animation, 150ms) |
### Select.Close
Select.Close extends [CloseButton](./close-button) and automatically handles select dismissal when pressed.
### Select.ListLabel
| prop | type | default | description |
| -------------- | ----------- | ------- | -------------------------------------------------- |
| `children` | `ReactNode` | - | The label text content |
| `className` | `string` | - | Additional CSS classes for the list label |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
### Select.Item
| prop | type | default | description |
| ------------------- | ------------------------------------------------------------ | ------- | -------------------------------------------------------------------------- |
| `children` | `ReactNode \| ((props: SelectItemRenderProps) => ReactNode)` | - | Custom item content. Defaults to label and indicator, or a render function |
| `value` | `any` | - | The value associated with this item (required) |
| `label` | `string` | - | The label text for this item (required) |
| `isDisabled` | `boolean` | `false` | Whether this item is disabled |
| `className` | `string` | - | Additional CSS classes for the item |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported |
#### SelectItemRenderProps
When using a render function for `children`, the following props are provided:
| property | type | description |
| ------------ | --------- | --------------------------------------- |
| `isSelected` | `boolean` | Whether this item is currently selected |
| `value` | `string` | The value of the item |
| `isDisabled` | `boolean` | Whether the item is disabled |
### Select.ItemLabel
| prop | type | default | description |
| -------------- | ----------- | ------- | -------------------------------------------------- |
| `className` | `string` | - | Additional CSS classes for the item label |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
### Select.ItemDescription
| prop | type | default | description |
| -------------- | ----------- | ------- | -------------------------------------------------- |
| `children` | `ReactNode` | - | The description text content |
| `className` | `string` | - | Additional CSS classes for the item description |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
### Select.ItemIndicator
| prop | type | default | description |
| -------------- | ------------------------------ | ------- | -------------------------------------------------- |
| `children` | `ReactNode` | - | Custom indicator content. Defaults to check icon |
| `className` | `string` | - | Additional CSS classes for the item indicator |
| `iconProps` | `SelectItemIndicatorIconProps` | - | Check icon configuration |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### SelectItemIndicatorIconProps
| prop | type | default | description |
| ------- | -------- | ---------------------------------- | ----------------- |
| `size` | `number` | `16` | Size of the icon |
| `color` | `string` | theme accent-soft-foreground color | Color of the icon |
## Hooks
### useSelect
Hook to access the Select root context. Returns the select state and control functions.
```tsx
import { useSelect } from 'heroui-native';
const {
isOpen,
onOpenChange,
isDefaultOpen,
isDisabled,
presentation,
triggerPosition,
setTriggerPosition,
contentLayout,
setContentLayout,
nativeID,
value,
onValueChange,
} = useSelect();
```
#### Return Value
| property | type | description |
| -------------------- | -------------------------------------------------- | --------------------------------------------------------- |
| `isOpen` | `boolean` | Whether the select is currently open |
| `onOpenChange` | `(open: boolean) => void` | Callback to change the open state |
| `isDefaultOpen` | `boolean \| undefined` | Whether the select is open by default (uncontrolled mode) |
| `isDisabled` | `boolean \| undefined` | Whether the select is disabled |
| `presentation` | `'popover' \| 'bottom-sheet' \| 'dialog'` | Presentation mode for the select content |
| `triggerPosition` | `LayoutPosition \| null` | Position of the trigger element relative to viewport |
| `setTriggerPosition` | `(position: LayoutPosition \| null) => void` | Updates the trigger element's position |
| `contentLayout` | `LayoutRectangle \| null` | Layout measurements of the select content |
| `setContentLayout` | `(layout: LayoutRectangle \| null) => void` | Updates the content layout measurements |
| `nativeID` | `string` | Unique identifier for the select instance |
| `value` | `SelectOption \| SelectOption[]` | Currently selected option |
| `onValueChange` | `(option: SelectOption \| SelectOption[]) => void` | Callback fired when the selected value changes |
**Note:** This hook must be used within a `Select` component. It will throw an error if called outside of the select context.
### useSelectAnimation
Hook to access the Select animation state values within custom components or compound components.
```tsx
import { useSelectAnimation } from 'heroui-native';
const { selectState, progress, isDragging, isGestureReleaseAnimationRunning } =
useSelectAnimation();
```
#### Return Value
| property | type | description |
| ---------------------------------- | ---------------------- | ---------------------------------------------------------- |
| `progress` | `SharedValue` | Progress value for animations (0=idle, 1=open, 2=close) |
| `isDragging` | `SharedValue` | Whether the select content is currently being dragged |
| `isGestureReleaseAnimationRunning` | `SharedValue` | Whether the gesture release animation is currently running |
**Note:** This hook must be used within a `Select` component. It will throw an error if called outside of the select animation context.
#### SelectOption
| property | type | description |
| -------- | -------- | ---------------------------- |
| `value` | `string` | The value of the option |
| `label` | `string` | The label text of the option |
### useSelectItem
Hook to access the Select Item context. Returns the item's value and label.
```tsx
import { useSelectItem } from 'heroui-native';
const { itemValue, label } = useSelectItem();
```
#### Return Value
| property | type | description |
| ----------- | -------- | ---------------------------------- |
| `itemValue` | `string` | The value of the current item |
| `label` | `string` | The label text of the current item |
## Special Notes
### Element Inspector (iOS)
Select uses FullWindowOverlay on iOS. To enable the React Native element inspector during development, set `disableFullWindowOverlay={true}` on `Select.Portal`. Tradeoff: the select dropdown will not appear above native modals when disabled.
### Native Modal (iOS)
When a `Select` is opened inside a screen presented as a native modal (`presentation: 'modal' | 'formSheet' | 'pageSheet'`), the dropdown may render shifted upward. In the new architecture (Fabric), `react-native-screens` marks `RNSModalScreen` as a Fabric root, so the trigger's position is reported relative to the modal's origin while `FullWindowOverlay` (where the dropdown is mounted) is anchored to the iOS application window. Compensate by adding `safeAreaInsets.top` to `offset`:
```tsx
import { useSafeAreaInsets } from 'react-native-safe-area-context';
const insets = useSafeAreaInsets();
...
;
```
# TextArea
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/text-area
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(forms)/text-area.mdx
> A multiline text input component with styled border and background for collecting longer user input.
## Import
```tsx
import { TextArea } from 'heroui-native';
```
## Usage
### Basic Usage
TextArea can be used standalone or within a TextField component.
```tsx
import { TextArea } from 'heroui-native';
```
### Within TextField
TextArea works seamlessly with TextField for complete form structure.
```tsx
import { Description, Label, TextArea, TextField } from 'heroui-native';
Message
Please provide as much detail as possible.
```
### With Validation
Display error state when the text area is invalid.
```tsx
import { FieldError, Label, TextArea, TextField } from 'heroui-native';
Message
Please enter a valid message
```
### Disabled State
Disable the text area to prevent interaction.
```tsx
import { Label, TextArea, TextField } from 'heroui-native';
Disabled Field
```
### With Variant
Use different variants to style the text area based on context.
```tsx
import { Label, TextArea, TextField } from 'heroui-native';
Primary Variant
Secondary Variant
```
### Custom Styling
Customize the text area appearance using className.
```tsx
import { Label, TextArea, TextField } from 'heroui-native';
Custom Styled
```
## Example
```tsx
import { Description, FieldError, Label, TextArea, TextField } from 'heroui-native';
import { View } from 'react-native';
export default function TextAreaExample() {
return (
Primary Variant
Default variant with primary styling
Secondary Variant
Secondary variant for surfaces
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/text-area.tsx).
## API Reference
TextArea extends [Input](./input) component and inherits all its props. The only differences are default values: `multiline` defaults to `true` and `textAlignVertical` defaults to `'top'`.
# TextField
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/text-field
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(forms)/text-field.mdx
> A text input component with label, description, and error handling for collecting user input.
## Import
```tsx
import { TextField } from 'heroui-native';
```
## Anatomy
```tsx
...
...
...
```
* **TextField**: Root container that provides spacing and state management
* **Label**: Label with optional asterisk for required fields (from [Label](./label) component)
* **Input**: Input container with animated border and background (from [Input](./input) component)
* **Description**: Secondary descriptive helper text (from [Description](./description) component)
* **FieldError**: Validation error message display (from [FieldError](./field-error) component)
## Usage
### Basic Usage
TextField provides a complete form input structure with label and description.
```tsx
Email
We'll never share your email
```
### With Required Field
Mark fields as required to show an asterisk in the label.
```tsx
Username
```
### With Validation
Display error messages when the field is invalid.
```tsx
import { FieldError, Input, Label, TextField } from 'heroui-native';
Email
Please enter a valid email
;
```
### With Local Invalid State Override
Override the context's invalid state for individual components.
```tsx
import {
Description,
FieldError,
Input,
Label,
TextField,
} from 'heroui-native';
Email
This shows despite input being invalid
Email format is incorrect
;
```
### Multiline Input
Create text areas for longer content.
```tsx
Message
Maximum 500 characters
```
### Disabled State
Disable the entire field to prevent interaction.
```tsx
Disabled Field
```
### With Variant
Use different variants to style the input based on context.
```tsx
Primary Variant
Secondary Variant
```
### Custom Styling
Customize the input appearance using className.
```tsx
Custom Styled
```
## Example
```tsx
import { Ionicons } from '@expo/vector-icons';
import { Description, Input, Label, TextField } from 'heroui-native';
import { useState } from 'react';
import { Pressable, View } from 'react-native';
import { withUniwind } from 'uniwind';
const StyledIonicons = withUniwind(Ionicons);
export const TextInputContent = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
return (
Email
We'll never share your email with anyone else.
New password
setIsPasswordVisible(!isPasswordVisible)}
>
Password must be at least 6 characters
);
};
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/text-field.tsx).
## API Reference
### TextField
| prop | type | default | description |
| ------------ | ---------------------------- | ----------- | ----------------------------------------------------------------------------------------- |
| children | `React.ReactNode` | - | Content to render inside the text field |
| isDisabled | `boolean` | `false` | Whether the entire text field is disabled |
| isInvalid | `boolean` | `false` | Whether the text field is in an invalid state |
| isRequired | `boolean` | `false` | Whether the text field is required (shows asterisk) |
| className | `string` | - | Custom class name for the root element |
| animation | `"disable-all" \| undefined` | `undefined` | Animation configuration. Use `"disable-all"` to disable all animations including children |
| ...ViewProps | `ViewProps` | - | All standard React Native View props are supported |
> **Note**: For Label, Input, Description, and FieldError components, see their respective documentation:
>
> * [Label documentation](./label)
> * [Input documentation](./input)
> * [Description documentation](./description)
> * [FieldError documentation](./field-error)
>
> These components automatically consume form state from TextField via the form-item-state context.
## Hooks
### useTextField
Hook to access the TextField context values. Must be used within a `TextField` component.
```tsx
import { TextField, useTextField } from 'heroui-native';
function CustomComponent() {
const { isDisabled, isInvalid, isRequired } = useTextField();
// Use the context values...
}
```
#### Returns
| property | type | description |
| ---------- | --------- | --------------------------------------------- |
| isDisabled | `boolean` | Whether the entire text field is disabled |
| isInvalid | `boolean` | Whether the text field is in an invalid state |
| isRequired | `boolean` | Whether the text field is required |
# Card
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/card
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(layout)/card.mdx
> Displays a card container with flexible layout sections for structured content.
## Import
```tsx
import { Card } from 'heroui-native';
```
## Anatomy
```tsx
...
...
...
...
```
* **Card**: Main container that extends Surface component. Provides base card structure with configurable surface variants and handles overall layout.
* **Card.Header**: Header section for top-aligned content like icons or badges.
* **Card.Body**: Main content area with flex-1 that expands to fill all available space between Card.Header and Card.Footer.
* **Card.Title**: Title text with foreground color and medium font weight.
* **Card.Description**: Description text with muted color and smaller font size.
* **Card.Footer**: Footer section for bottom-aligned actions like buttons.
## Usage
### Basic Usage
The Card component creates a container with built-in sections for organized content.
```tsx
...
```
### With Title and Description
Combine title and description components for structured text content.
```tsx
...
...
```
### With Header and Footer
Add header and footer sections for icons, badges, or actions.
```tsx
...
...
...
```
### Variants
Control the card's background appearance using different variants.
```tsx
...
...
...
...
```
### Horizontal Layout
Create horizontal cards by using flex-row styling.
```tsx
```
### Background Image
Use an image as an absolute positioned background.
```tsx
...
```
## Example
```tsx
import { Button, Card } from 'heroui-native';
import { Ionicons } from '@expo/vector-icons';
import { View } from 'react-native';
export default function CardExample() {
return (
$450
Living room Sofa • Collection 2025
This sofa is perfect for modern tropical spaces, baroque inspired
spaces.
Buy now
Add to cart
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/card.tsx).
## API Reference
### Card
| prop | type | default | description |
| -------------- | --------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Content to be rendered inside the card |
| `variant` | `'default' \| 'secondary' \| 'tertiary' \| 'transparent'` | `'default'` | Visual variant of the card surface |
| `className` | `string` | - | Additional CSS classes to apply |
| `animation` | `"disable-all" \| undefined` | `undefined` | Animation configuration. Use `"disable-all"` to disable all animations including children |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### Card.Header
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside the header |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### Card.Body
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside the body |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### Card.Footer
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside the footer |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### Card.Title
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered as the title text |
| `className` | `string` | - | Additional CSS classes |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
### Card.Description
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered as the description text |
| `className` | `string` | - | Additional CSS classes |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
# Separator
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/separator
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(layout)/separator.mdx
> A simple line to separate content visually.
## Import
```tsx
import { Separator } from "heroui-native";
```
## Anatomy
```tsx
```
* **Separator**: A simple line component that separates content visually. Can be oriented horizontally or vertically, with customizable thickness and variant styles.
## Usage
### Basic Usage
The Separator component creates a visual separation between content sections.
```tsx
```
### Orientation
Control the direction of the separator with the `orientation` prop.
```tsx
Horizontal separator
Content below
Left
Right
```
### Variants
Choose between thin and thick variants for different visual emphasis.
```tsx
```
### Custom Thickness
Set a specific thickness value for precise control.
```tsx
```
## Example
```tsx
import { Separator, Surface } from 'heroui-native';
import { Text, View } from 'react-native';
export default function SeparatorExample() {
return (
HeroUI Native
A modern React Native component library.
Components
Themes
Examples
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/separator.tsx).
## API Reference
### Separator
| prop | type | default | description |
| -------------- | ---------------------------- | -------------- | -------------------------------------------------------------------------------------------- |
| `variant` | `'thin' \| 'thick'` | `'thin'` | Variant style of the separator |
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Orientation of the separator |
| `thickness` | `number` | `undefined` | Custom thickness in pixels. Controls height for horizontal or width for vertical orientation |
| `className` | `string` | `undefined` | Additional CSS classes to apply |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
# Surface
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/surface
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(layout)/surface.mdx
> Container component that provides elevation and background styling.
## Import
```tsx
import { Surface } from 'heroui-native';
```
## Anatomy
The Surface component is a container that provides elevation and background styling. It accepts children and can be customized with variants and styling props.
```tsx
...
```
* **Surface**: Main container component that provides consistent padding, background styling, and elevation through variants.
## Usage
### Basic Usage
The Surface component creates a container with consistent padding and styling.
```tsx
...
```
### Variants
Control the visual appearance with different surface levels.
```tsx
...
...
...
```
### Nested Surfaces
Create visual hierarchy by nesting surfaces with different variants.
```tsx
...
...
...
```
### Custom Styling
Apply custom styles using className or style props.
```tsx
...
...
```
### Disable All Animations
Disable all animations including children by using the `"disable-all"` value for the `animation` prop.
```tsx
{
/* Disable all animations including children */
}
No Animations ;
```
## Example
```tsx
import { Surface } from 'heroui-native';
import { Text, View } from 'react-native';
export default function SurfaceExample() {
return (
Surface Content
This is a default surface variant. It uses bg-surface styling.
Surface Content
This is a secondary surface variant. It uses bg-surface-secondary
styling.
Surface Content
This is a tertiary surface variant. It uses bg-surface-tertiary
styling.
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/surface.tsx).
## API Reference
### Surface
| prop | type | default | description |
| -------------- | --------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------- |
| `variant` | `'default' \| 'secondary' \| 'tertiary' \| 'transparent'` | `'default'` | Visual variant controlling background color and border |
| `children` | `React.ReactNode` | - | Content to be rendered inside the surface |
| `className` | `string` | - | Additional CSS classes to apply |
| `animation` | `"disable-all" \| undefined` | `undefined` | Animation configuration. Use `"disable-all"` to disable all animations including children |
| `asChild` | `boolean` | `false` | Whether to render as a child element |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
# Avatar
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/avatar
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(media)/avatar.mdx
> Displays a user avatar with support for images, text initials, or fallback icons.
## Import
```tsx
import { Avatar } from 'heroui-native';
```
## Anatomy
```tsx
```
* **Avatar**: Main container that manages avatar display state. Provides size and color context to child components. Supports animation configuration to control all child animations.
* **Avatar.Background**: Optional theme-aware background container rendered behind the avatar content. Mounted automatically for the `default` variant, and for the `soft` variant with `color="default"`, when the active theme registers default background content (e.g. `glass`). Replace or remove it via the `background` prop.
* **Avatar.Image**: Optional image component that displays the avatar image. Handles loading states and errors automatically with opacity-based fade-in animation.
* **Avatar.Fallback**: Optional fallback component shown when image fails to load or is unavailable. Displays a default person icon when no children are provided. Supports configurable entering animations with delay support.
## Usage
### Basic Usage
The Avatar component displays a default person icon when no image or text is provided.
```tsx
```
### With Image
Display an avatar image with automatic fallback handling.
```tsx
JD
```
### With Text Initials
Show text initials as the avatar content.
```tsx
AB
```
### With Custom Icon
Provide a custom icon as fallback content.
```tsx
```
### Sizes
Control the avatar size with the size prop.
```tsx
```
### Variants
Choose between different visual styles with the `variant` prop.
```tsx
DF
SF
```
### Colors
Apply different color variants to the avatar.
```tsx
DF
AC
SC
WR
DG
```
### Delayed Fallback
Show fallback after a delay to prevent flashing during image load.
```tsx
NA
```
### Custom Image Component
Use a custom image component with the asChild prop.
```tsx
import { Image } from 'expo-image';
EI
;
```
### Animation Control
Control animations at different levels of the Avatar component.
#### Disable All Animations
Disable all animations including children from the root component:
```tsx
JD
```
#### Custom Image Animation
Customize the image opacity animation:
```tsx
JD
```
#### Custom Fallback Animation
Customize the fallback entering animation:
```tsx
import { FadeInDown } from 'react-native-reanimated';
JD
;
```
#### Disable Individual Animations
Disable animations for specific components:
```tsx
JD
```
## Example
```tsx
import { Avatar } from 'heroui-native';
import { View } from 'react-native';
export default function AvatarExample() {
const users = [
{ id: 1, image: 'https://example.com/user1.jpg', name: 'John Doe' },
{ id: 2, image: 'https://example.com/user2.jpg', name: 'Jane Smith' },
{ id: 3, image: 'https://example.com/user3.jpg', name: 'Bob Johnson' },
];
return (
{users.map((user) => (
{user.name
.split(' ')
.map((n) => n[0])
.join('')}
))}
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/avatar.tsx).
## API Reference
### Avatar
| prop | type | default | description |
| -------------- | ------------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Avatar content (Image and/or Fallback components) |
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size of the avatar |
| `variant` | `'default' \| 'soft'` | `'default'` | Visual variant of the avatar |
| `color` | `'default' \| 'accent' \| 'success' \| 'warning' \| 'danger'` | `'accent'` | Color variant of the avatar |
| `className` | `string` | - | Additional CSS classes to apply |
| `animation` | `"disable-all"` \| `undefined` | `undefined` | Animation configuration. Use `"disable-all"` to disable all animations including children |
| `alt` | `string` | `'Avatar'` | Alternative text description for accessibility |
| `background` | `React.ReactNode` | - | Background layer behind the avatar content. `undefined` renders the theme-aware default for the `default` variant and the `soft` variant with `color="default"`; custom node replaces it; `null` removes it |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### Avatar.Background
Absolute-fill container rendered behind the avatar content. With no children, the active library theme decides the default content (e.g. a glass blur layer); pass children to host custom content with the same positioning and clipping.
| prop | type | default | description |
| -------------- | ----------------- | ------- | ---------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom content inside the background container |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard View props are supported |
### Avatar.Image
Props extend different base types depending on the `asChild` prop value:
* When `asChild={false}` (default): extends `AnimatedProps` from React Native Reanimated
* When `asChild={true}`: extends primitive image props for custom image components
**Note:** When using `asChild={true}` with custom image components, the `className` prop may not be applied in some cases depending on the custom component's implementation. Ensure your custom component properly handles style props.
| prop | type | default | description |
| ----------------------- | ---------------------------------------------- | ------- | ------------------------------------------------------------ |
| `source` | `ImageSourcePropType` | - | Image source (required when `asChild={false}`) |
| `asChild` | `boolean` | `false` | Whether to use a custom image component as child |
| `className` | `string` | - | Additional CSS classes to apply |
| `animation` | `AvatarImageAnimation` | - | Animation configuration |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `...AnimatedProps` | `AnimatedProps` or primitive props | - | Additional props based on `asChild` value |
#### AvatarImageAnimation
Animation configuration for avatar image component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ---------------------- | ----------------------- | --------------------------------------------------- | ----------------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `opacity.value` | `[number, number]` | `[0, 1]` | Opacity values \[initial, loaded] for image animation |
| `opacity.timingConfig` | `WithTimingConfig` | `{ duration: 200, easing: Easing.in(Easing.ease) }` | Animation timing configuration |
**Note:** Animation is automatically disabled when `asChild={true}`
### Avatar.Fallback
| prop | type | default | description |
| ----------------------- | ------------------------------------------------------------- | --------------------- | --------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Fallback content (text, icon, or custom element) |
| `delayMs` | `number` | `0` | Delay in milliseconds before showing the fallback (applied to entering animation) |
| `color` | `'default' \| 'accent' \| 'success' \| 'warning' \| 'danger'` | inherited from parent | Color variant of the fallback |
| `className` | `string` | - | Additional CSS classes for the container |
| `classNames` | `ElementSlots` | - | Additional CSS classes for different parts |
| `styles` | `{ container?: ViewStyle; text?: TextStyle }` | - | Styles for different parts of the avatar fallback |
| `textProps` | `TextProps` | - | Props to pass to Text component when children is a string |
| `iconProps` | `PersonIconProps` | - | Props to customize the default person icon |
| `animation` | `AvatarFallbackAnimation` | - | Animation configuration |
| `...Animated.ViewProps` | `Animated.ViewProps` | - | All Reanimated Animated.View props are supported |
**classNames prop:** `ElementSlots` provides type-safe CSS classes for different parts of the fallback component. Available slots: `container`, `text`.
#### `styles`
| prop | type | description |
| ----------- | ----------- | --------------------------- |
| `container` | `ViewStyle` | Styles for the container |
| `text` | `TextStyle` | Styles for the text content |
#### AvatarFallbackAnimation
Animation configuration for avatar fallback component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ---------------- | ----------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `entering.value` | `EntryOrExitLayoutType` | `FadeIn` `.duration(200)` `.easing(Easing.in(Easing.ease))` `.delay(0)` | Custom entering animation for fallback |
#### PersonIconProps
| prop | type | description |
| ------- | -------- | ------------------------------------- |
| `size` | `number` | Size of the icon in pixels (optional) |
| `color` | `string` | Color of the icon (optional) |
## Hooks
### useAvatar Hook
Hook to access Avatar primitive root context. Provides access to avatar status.
**Note:** The `status` property is particularly useful for adding a skeleton loader while the image is loading.
```tsx
import { Avatar, useAvatar, Skeleton } from 'heroui-native';
function AvatarWithSkeleton() {
return (
JD
);
}
function AvatarContent() {
const { status } = useAvatar();
if (status === 'loading') {
return ;
}
return null;
}
```
| property | type | description |
| ----------- | ---------------------------------------------------- | ----------------------------------------------------------- |
| `status` | `'loading' \| 'loaded' \| 'error'` | Current loading state of the avatar image. |
| `setStatus` | `(status: 'loading' \| 'loaded' \| 'error') => void` | Function to manually set the avatar status (advanced usage) |
**Status Values:**
* `'loading'`: Image is currently being loaded. Use this state to show a skeleton loader.
* `'loaded'`: Image has successfully loaded.
* `'error'`: Image failed to load or source is invalid. The fallback component is automatically shown in this state.
# Accordion
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/accordion
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(navigation)/accordion.mdx
> A collapsible content panel for organizing information in a compact space
## Import
```tsx
import { Accordion } from 'heroui-native';
```
## Anatomy
```tsx
...
...
...
```
* **Accordion**: Main container that manages the accordion state and behavior. Controls expansion/collapse of items, supports single or multiple selection modes, and provides variant styling (default or surface).
* **Accordion.Item**: Container for individual accordion items. Wraps the trigger and content, managing the expanded state for each item.
* **Accordion.Trigger**: Interactive element that toggles item expansion. Built on Header and Trigger primitives.
* **Accordion.Indicator**: Optional visual indicator showing expansion state. Defaults to an animated chevron icon that rotates based on item state.
* **Accordion.Content**: Container for expandable content. Animated with layout transitions for smooth expand/collapse effects.
## Usage
### Basic Usage
The Accordion component uses compound parts to create expandable content sections.
```tsx
...
...
```
### Single Selection Mode
Allow only one item to be expanded at a time.
```tsx
...
...
...
...
```
### Multiple Selection Mode
Allow multiple items to be expanded simultaneously.
```tsx
...
...
...
...
...
...
```
### Surface Variant
Apply a surface container style to the accordion.
```tsx
...
...
```
### Custom Indicator
Replace the default chevron indicator with custom content.
```tsx
...
...
```
### Without Separators
Hide the separators between accordion items.
```tsx
...
...
...
...
```
### Custom Styling
Apply custom styles using className, classNames, or styles props.
```tsx
...
...
```
### With PressableFeedback
Use `Accordion.Trigger` with `asChild` prop and wrap content with `PressableFeedback` to add custom press feedback animations.
```tsx
import { Accordion, PressableFeedback } from 'heroui-native';
import { View } from 'react-native';
Item Title
...
;
```
## Example
```tsx
import { Accordion, useThemeColor } from 'heroui-native';
import { Ionicons } from '@expo/vector-icons';
import { View, Text } from 'react-native';
export default function AccordionExample() {
const themeColorMuted = useThemeColor('muted');
const accordionData = [
{
id: '1',
title: 'How do I place an order?',
icon: ,
content:
'Lorem ipsum dolor sit amet consectetur. Netus nunc mauris risus consequat. Libero placerat dignissim consectetur nisl.',
},
{
id: '2',
title: 'What payment methods do you accept?',
icon: ,
content:
'Lorem ipsum dolor sit amet consectetur. Netus nunc mauris risus consequat. Libero placerat dignissim consectetur nisl.',
},
{
id: '3',
title: 'How much does shipping cost?',
icon: ,
content:
'Lorem ipsum dolor sit amet consectetur. Netus nunc mauris risus consequat. Libero placerat dignissim consectetur nisl.',
},
];
return (
{accordionData.map((item) => (
{item.icon}
{item.title}
{item.content}
))}
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/accordion.tsx).
## API Reference
### Accordion
| prop | type | default | description |
| ----------------------- | -------------------------------------------------- | ----------- | -------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside the accordion |
| `selectionMode` | `'single' \| 'multiple'` | - | Whether the accordion allows single or multiple expanded items |
| `variant` | `'default' \| 'surface'` | `'default'` | Visual variant of the accordion |
| `hideSeparator` | `boolean` | `false` | Whether to hide the separator between accordion items |
| `defaultValue` | `string \| string[] \| undefined` | - | Default expanded item(s) in uncontrolled mode |
| `value` | `string \| string[] \| undefined` | - | Controlled expanded item(s) |
| `isDisabled` | `boolean` | - | Whether all accordion items are disabled |
| `isCollapsible` | `boolean` | `true` | Whether expanded items can be collapsed |
| `animation` | `AccordionRootAnimation` | - | Animation configuration for accordion |
| `className` | `string` | - | Additional CSS classes for the container |
| `classNames` | `ElementSlots` | - | Additional CSS classes for the slots |
| `styles` | `Partial>` | - | Styles for different parts of the accordion root |
| `onValueChange` | `(value: string \| string[] \| undefined) => void` | - | Callback when expanded items change |
| `...Animated.ViewProps` | `Animated.ViewProps` | - | All Reanimated Animated.View props are supported |
#### `ElementSlots`
| prop | type | description |
| ----------- | -------- | ------------------------------------------------- |
| `container` | `string` | Custom class name for the accordion container |
| `separator` | `string` | Custom class name for the separator between items |
#### `styles`
| prop | type | description |
| ----------- | ----------- | -------------------------------------- |
| `container` | `ViewStyle` | Styles for the accordion container |
| `separator` | `ViewStyle` | Styles for the separator between items |
#### AccordionRootAnimation
Animation configuration for accordion root component. Can be:
* `false` or `"disabled"`: Disable only root animations
* `"disable-all"`: Disable all animations including children
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| -------------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
| `state` | `'disabled' \| 'disable-all' \| boolean` | - | Disable animations while customizing properties |
| `layout.value` | `LayoutTransition` | `LinearTransition` `.springify()` `.damping(140)` `.stiffness(1600)` `.mass(4)` | Custom layout animation for accordion transitions |
### Accordion.Item
| prop | type | default | description |
| ----------------------- | --------------------------------------------------------------------------- | ------- | -------------------------------------------------------------------------------- |
| `children` | `React.ReactNode \| ((props: AccordionItemRenderProps) => React.ReactNode)` | - | Children elements to be rendered inside the accordion item, or a render function |
| `value` | `string` | - | Unique value to identify this item |
| `isDisabled` | `boolean` | - | Whether this specific item is disabled |
| `className` | `string` | - | Additional CSS classes |
| `...Animated.ViewProps` | `Animated.ViewProps` | - | All Reanimated Animated.View props are supported |
#### AccordionItemRenderProps
| prop | type | description |
| ------------ | --------- | ------------------------------------------------ |
| `isExpanded` | `boolean` | Whether the accordion item is currently expanded |
| `value` | `string` | Unique value identifier for this accordion item |
### Accordion.Trigger
| prop | type | default | description |
| ------------------- | ----------------- | ------- | ------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside the trigger |
| `className` | `string` | - | Additional CSS classes |
| `isDisabled` | `boolean` | - | Whether the trigger is disabled |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported |
### Accordion.Indicator
| prop | type | default | description |
| ----------------------- | ----------------------------- | ------- | ---------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom indicator content, if not provided defaults to animated chevron |
| `className` | `string` | - | Additional CSS classes |
| `iconProps` | `AccordionIndicatorIconProps` | - | Icon configuration |
| `animation` | `AccordionIndicatorAnimation` | - | Animation configuration for indicator |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `...Animated.ViewProps` | `Animated.ViewProps` | - | All Reanimated Animated.View props are supported |
#### AccordionIndicatorIconProps
| prop | type | default | description |
| ------- | -------- | ------------ | ----------------- |
| `size` | `number` | `16` | Size of the icon |
| `color` | `string` | `foreground` | Color of the icon |
#### AccordionIndicatorAnimation
Animation configuration for accordion indicator component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ----------------------- | ----------------------- | -------------------------------------------- | ------------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `rotation.value` | `[number, number]` | `[0, -180]` | Rotation values \[collapsed, expanded] in degrees |
| `rotation.springConfig` | `WithSpringConfig` | `{ damping: 140, stiffness: 1000, mass: 4 }` | Spring animation configuration for rotation |
### Accordion.Content
| prop | type | default | description |
| -------------- | --------------------------- | ------- | --------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside the content |
| `className` | `string` | - | Additional CSS classes |
| `animation` | `AccordionContentAnimation` | - | Animation configuration for content |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### AccordionContentAnimation
Animation configuration for accordion content component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ---------------- | ----------------------- | ---------------------------------------------------------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `entering.value` | `EntryOrExitLayoutType` | `FadeIn` `.duration(200)` `.easing(Easing.out(Easing.ease))` | Custom entering animation for content |
| `exiting.value` | `EntryOrExitLayoutType` | `FadeOut` `.duration(200)` `.easing(Easing.in(Easing.ease))` | Custom exiting animation for content |
## Hooks
### useAccordion
Hook to access the accordion root context. Must be used within an `Accordion` component.
```tsx
import { useAccordion } from 'heroui-native';
const { value, onValueChange, selectionMode, isCollapsible, isDisabled } =
useAccordion();
```
#### Returns
| property | type | description |
| --------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| `selectionMode` | `'single' \| 'multiple' \| undefined` | Whether the accordion allows single or multiple expanded items |
| `value` | `(string \| undefined) \| string[]` | Currently expanded item(s) - string for single mode, array for multiple mode |
| `onValueChange` | `(value: string \| undefined) => void \| ((value: string[]) => void)` | Callback function to update expanded items |
| `isCollapsible` | `boolean` | Whether expanded items can be collapsed |
| `isDisabled` | `boolean \| undefined` | Whether all accordion items are disabled |
### useAccordionItem
Hook to access the accordion item context. Must be used within an `Accordion.Item` component.
```tsx
import { useAccordionItem } from 'heroui-native';
const { value, isExpanded, isDisabled, nativeID } = useAccordionItem();
```
#### Returns
| property | type | description |
| ------------ | ---------------------- | ---------------------------------------------------- |
| `value` | `string` | Unique value identifier for this accordion item |
| `isExpanded` | `boolean` | Whether the accordion item is currently expanded |
| `isDisabled` | `boolean \| undefined` | Whether this specific item is disabled |
| `nativeID` | `string` | Native ID used for accessibility and ARIA attributes |
## Special Notes
When using the Accordion component alongside other components in the same view, you should import and apply `AccordionLayoutTransition` to those components to ensure smooth and consistent layout animations across the entire screen.
```jsx
import { Accordion, AccordionLayoutTransition } from 'heroui-native';
import Animated from 'react-native-reanimated';
{/* Other content */}
{/* Accordion items */}
;
```
This ensures that when the accordion expands or collapses, all components on the screen animate with the same timing and easing, creating a cohesive user experience.
# ListGroup
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/list-group
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(navigation)/list-group.mdx
> A Surface-based container that groups related list items with consistent layout and spacing.
## Import
```tsx
import { ListGroup } from 'heroui-native';
```
## Anatomy
```tsx
...
...
...
```
* **ListGroup**: Surface-based root container that groups related list items. Supports all Surface variants (default, secondary, tertiary, transparent).
* **ListGroup.Item**: Pressable horizontal flex-row container for a single item, providing consistent spacing and alignment.
* **ListGroup.ItemPrefix**: Optional leading content slot for icons, avatars, or other visual elements.
* **ListGroup.ItemContent**: Flex-1 wrapper for title and description, occupying the remaining horizontal space.
* **ListGroup.ItemTitle**: Primary text label styled with foreground color and medium font weight.
* **ListGroup.ItemDescription**: Secondary text styled with muted color and smaller font size.
* **ListGroup.ItemSuffix**: Optional trailing content slot. Renders a chevron-right icon by default; accepts children to override the default icon.
## Usage
### Basic Usage
The ListGroup component uses compound parts to create grouped list items with title and description.
```tsx
Personal Info
Name, email, phone number
Payment Methods
Visa ending in 4829
```
### With Icons
Add leading icons using the `ListGroup.ItemPrefix` slot.
```tsx
Profile
Name, photo, bio
Security
Password, 2FA
```
### Title Only
Omit `ListGroup.ItemDescription` to display title-only items.
```tsx
Wi-Fi
Bluetooth
```
### Surface Variant
Apply a different visual variant to the root container.
```tsx
Wi-Fi
```
### Custom Suffix
Override the default chevron icon by passing children to `ListGroup.ItemSuffix`.
```tsx
Language
English
Notifications
7
```
### Custom Suffix Icon Props
Customise the default chevron icon size and color using `iconProps`.
```tsx
Storage
12.4 GB of 50 GB used
```
### With PressableFeedback
Wrap items with `PressableFeedback` to add scale and ripple press feedback animations. When using this pattern, pass `onPress` on `PressableFeedback` instead of `ListGroup.Item` and disable the item with `disabled` prop.
```tsx
import { ListGroup, PressableFeedback, Separator } from 'heroui-native';
{}}>
Appearance
Theme, font size, display
{}}>
Notifications
Alerts, sounds, badges
```
## Example
```tsx
import { Ionicons } from '@expo/vector-icons';
import { ListGroup, Separator, useThemeColor } from 'heroui-native';
import { View, Text } from 'react-native';
import { withUniwind } from 'uniwind';
const StyledIonicons = withUniwind(Ionicons);
export default function ListGroupExample() {
const mutedColor = useThemeColor('muted');
return (
Account
Personal Info
Name, email, phone number
Payment Methods
Visa ending in 4829
Preferences
Appearance
Theme, font size, display
Notifications
Alerts, sounds, badges
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/list-group.tsx).
## API Reference
### ListGroup
| prop | type | default | description |
| -------------- | --------------------------------------------------------- | ----------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside the group |
| `variant` | `'default' \| 'secondary' \| 'tertiary' \| 'transparent'` | `'default'` | Visual variant of the underlying Surface container |
| `className` | `string` | - | Additional CSS classes for the root container |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### ListGroup.Item
| prop | type | default | description |
| ------------------- | ----------------- | ------- | ------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside the item |
| `className` | `string` | - | Additional CSS classes for the item |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported |
### ListGroup.ItemPrefix
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Leading content such as icons or avatars |
| `className` | `string` | - | Additional CSS classes for the prefix |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### ListGroup.ItemContent
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Content area, typically title and description |
| `className` | `string` | - | Additional CSS classes for the content area |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### ListGroup.ItemTitle
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Title text or custom content |
| `className` | `string` | - | Additional CSS classes for the title |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### ListGroup.ItemDescription
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Description text or custom content |
| `className` | `string` | - | Additional CSS classes for the description |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### ListGroup.ItemSuffix
| prop | type | default | description |
| -------------- | -------------------- | ------- | -------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom trailing content; overrides the default chevron-right icon when provided |
| `className` | `string` | - | Additional CSS classes for the suffix |
| `iconProps` | `ListGroupIconProps` | - | Props to customise the default chevron-right icon. Only applies when no children |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### ListGroupIconProps
| prop | type | default | description |
| ------- | -------- | ------------------- | ---------------------------------- |
| `size` | `number` | `16` | Size of the chevron icon in pixels |
| `color` | `string` | theme `muted` color | Color of the chevron icon |
# Tabs
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/tabs
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(navigation)/tabs.mdx
> Organize content into tabbed views with animated transitions and indicators.
## Import
```tsx
import { Tabs } from 'heroui-native';
```
## Anatomy
```tsx
...
...
...
```
* **Tabs**: Main container that manages tab state and selection. Controls active tab, handles value changes, and provides context to child components.
* **Tabs.List**: Container for tab triggers. Groups triggers together with optional styling variants (primary or secondary).
* **Tabs.ListBackground**: Optional theme-aware background container rendered behind the list surface. Mounted automatically for the `primary` variant when the active theme registers default background content (e.g. `glass`). Replace or remove it via the `background` prop on `Tabs.List`.
* **Tabs.ScrollView**: Optional scrollable wrapper for tab triggers. Enables horizontal scrolling when tabs overflow with automatic centering of active tab.
* **Tabs.Trigger**: Interactive button for each tab. Handles press events to change active tab and measures its position for indicator animation.
* **Tabs.Label**: Text content for tab triggers. Displays the tab title with appropriate styling.
* **Tabs.Indicator**: Animated visual indicator for active tab. Smoothly transitions between tabs using spring or timing animations.
* **Tabs.Separator**: Visual separator between tabs. Shows when the current tab value is not in the `betweenValues` array, with animated opacity transitions.
* **Tabs.Content**: Container for tab panel content. Shows content when its value matches the active tab.
## Usage
### Basic Usage
The Tabs component uses compound parts to create navigable content sections.
```tsx
Tab 1
Tab 2
...
...
```
### Primary Variant
Default rounded primary style for tab triggers.
```tsx
Settings
Profile
...
...
```
### Secondary Variant
Underline style indicator for a more minimal appearance.
```tsx
Overview
Analytics
...
...
```
### Scrollable Tabs
Handle many tabs with horizontal scrolling.
```tsx
First Tab
Second Tab
Third Tab
Fourth Tab
Fifth Tab
...
...
...
...
...
```
### Disabled Tabs
Disable specific tabs to prevent interaction.
```tsx
Active
Disabled
Another
...
...
```
### With Icons
Combine icons with labels for enhanced visual context.
```tsx
Home
Search
...
...
```
### With Render Function
Use a render function on `Tabs.Trigger` to access state and customize content based on selection.
```tsx
{({ isSelected, value, isDisabled }) => (
Settings
)}
{({ isSelected }) => (
<>
Profile
>
)}
...
...
```
### With Separators
Add visual separators between tabs that show when the active tab is not between specified values.
```tsx
General
Notifications
Profile
...
...
...
```
## Example
```tsx
import {
Button,
Checkbox,
Description,
ControlField,
Label,
Tabs,
TextField,
} from 'heroui-native';
import { useState } from 'react';
import { View, Text } from 'react-native';
import Animated, {
FadeIn,
FadeOut,
LinearTransition,
} from 'react-native-reanimated';
const AnimatedContentContainer = ({
children,
}: {
children: React.ReactNode;
}) => (
{children}
);
export default function TabsExample() {
const [activeTab, setActiveTab] = useState('general');
const [showSidebar, setShowSidebar] = useState(true);
const [accountActivity, setAccountActivity] = useState(true);
const [name, setName] = useState('');
return (
General
Notifications
Profile
Show sidebar
Display the sidebar navigation panel
Account activity
Notifications about your account activity
Name
Update profile
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/tabs.tsx).
## API Reference
### Tabs
| prop | type | default | description |
| --------------- | ---------------------------- | ----------- | ----------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside tabs |
| `value` | `string` | - | Currently active tab value |
| `variant` | `'primary' \| 'secondary'` | `'primary'` | Visual variant of the tabs |
| `className` | `string` | - | Additional CSS classes for the container |
| `animation` | `"disable-all" \| undefined` | `undefined` | Animation configuration. Use `"disable-all"` to disable all animations including children |
| `onValueChange` | `(value: string) => void` | - | Callback when the active tab changes |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### Tabs.List
| prop | type | default | description |
| -------------- | ----------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside the list |
| `className` | `string` | - | Additional CSS classes |
| `background` | `React.ReactNode` | - | Background layer behind the list surface. `undefined` renders the theme-aware default for the `primary` variant; custom node replaces it; `null` removes it |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### Tabs.ListBackground
Absolute-fill container rendered behind the primary variant's list surface. With no children, the active library theme decides the default content (e.g. a glass blur layer); pass children to host custom content with the same positioning and clipping.
| prop | type | default | description |
| -------------- | ----------------- | ------- | ---------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom content inside the background container |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard View props are supported |
### Tabs.ScrollView
| prop | type | default | description |
| --------------------------- | ---------------------------------------- | ---------- | -------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside the scroll view |
| `scrollAlign` | `'start' \| 'center' \| 'end' \| 'none'` | `'center'` | Scroll alignment variant for the selected item |
| `className` | `string` | - | Additional CSS classes for the scroll view |
| `contentContainerClassName` | `string` | - | Additional CSS classes for the content container |
| `...ScrollViewProps` | `ScrollViewProps` | - | All standard React Native ScrollView props are supported |
### Tabs.Trigger
| prop | type | default | description |
| ------------------- | ------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------- |
| `children` | `React.ReactNode \| ((props: TabsTriggerRenderProps) => React.ReactNode)` | - | Children elements to be rendered inside the trigger, or a render function |
| `value` | `string` | - | The unique value identifying this tab |
| `isDisabled` | `boolean` | `false` | Whether the trigger is disabled |
| `className` | `string` | - | Additional CSS classes |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported |
#### TabsTriggerRenderProps
When using a render function for `children`, the following props are provided:
| property | type | description |
| ------------ | --------- | ------------------------------------------ |
| `isSelected` | `boolean` | Whether this trigger is currently selected |
| `value` | `string` | The value of the trigger |
| `isDisabled` | `boolean` | Whether the trigger is disabled |
### Tabs.Label
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Text content to be rendered as label |
| `className` | `string` | - | Additional CSS classes |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
### Tabs.Indicator
| prop | type | default | description |
| ----------------------- | ------------------------ | ------- | ------------------------------------------------------------ |
| `children` | `React.ReactNode` | - | Custom indicator content |
| `className` | `string` | - | Additional CSS classes |
| `animation` | `TabsIndicatorAnimation` | - | Animation configuration |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `...Animated.ViewProps` | `Animated.ViewProps` | - | All Reanimated Animated.View props are supported |
#### TabsIndicatorAnimation
Animation configuration for Tabs.Indicator component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ------------------- | -------------------------------------- | ---------------------------------------------------------------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `width.type` | `'spring' \| 'timing'` | `'spring'` | Type of animation to use |
| `width.config` | `WithSpringConfig \| WithTimingConfig` | `{ stiffness: 1200, damping: 120 }` (spring) or `{ duration: 200 }` (timing) | Reanimated animation configuration |
| `height.type` | `'spring' \| 'timing'` | `'spring'` | Type of animation to use |
| `height.config` | `WithSpringConfig \| WithTimingConfig` | `{ stiffness: 1200, damping: 120 }` (spring) or `{ duration: 200 }` (timing) | Reanimated animation configuration |
| `translateX.type` | `'spring' \| 'timing'` | `'spring'` | Type of animation to use |
| `translateX.config` | `WithSpringConfig \| WithTimingConfig` | `{ stiffness: 1200, damping: 120 }` (spring) or `{ duration: 200 }` (timing) | Reanimated animation configuration |
### Tabs.Separator
| prop | type | default | description |
| ----------------------- | ------------------------ | ------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `betweenValues` | `string[]` | - | Array of tab values between which the separator should be visible. The separator shows when the current tab value is NOT in this array |
| `isAlwaysVisible` | `boolean` | `false` | If true, opacity is always 1 regardless of the current tab value |
| `className` | `string` | - | Additional CSS classes |
| `animation` | `TabsSeparatorAnimation` | - | Animation configuration |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `children` | `React.ReactNode` | - | Custom separator content |
| `...Animated.ViewProps` | `Animated.ViewProps` | - | All Reanimated Animated.View props are supported |
**Note:** The following style properties are occupied by animations and cannot be set via className:
* `opacity` - Animated for separator visibility transitions (0 when current tab is in `betweenValues`, 1 when not)
To customize these properties, use the `animation` prop. To completely disable animated styles and use your own via className or style prop, set `isAnimatedStyleActive={false}`.
#### TabsSeparatorAnimation
Animation configuration for Tabs.Separator component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ---------------------- | ----------------------- | ------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `opacity.value` | `[number, number]` | `[0, 1]` | Opacity values \[hidden, visible] |
| `opacity.timingConfig` | `WithTimingConfig` | `{ duration: 200 }` | Animation timing configuration |
### Tabs.Content
| prop | type | default | description |
| -------------- | ----------------- | ------- | --------------------------------------------------- |
| `children` | `React.ReactNode` | - | Children elements to be rendered inside the content |
| `value` | `string` | - | The value of the tab this content belongs to |
| `className` | `string` | - | Additional CSS classes |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
## Hooks
### useTabs
Hook to access tabs root context values within custom components or compound components.
```tsx
import { useTabs } from 'heroui-native';
const CustomComponent = () => {
const { value, onValueChange, nativeID } = useTabs();
// ... your implementation
};
```
**Returns:** `UseTabsReturn`
| property | type | description |
| --------------- | ------------------------- | ------------------------------------------ |
| `value` | `string` | Currently active tab value |
| `onValueChange` | `(value: string) => void` | Callback function to change the active tab |
| `nativeID` | `string` | Unique identifier for the tabs instance |
**Note:** This hook must be used within a `Tabs` component. It will throw an error if called outside of the tabs context.
### useTabsMeasurements
Hook to access tab measurements context values for managing tab trigger positions and dimensions.
```tsx
import { useTabsMeasurements } from 'heroui-native';
const CustomIndicator = () => {
const { measurements, variant } = useTabsMeasurements();
// ... your implementation
};
```
**Returns:** `UseTabsMeasurementsReturn`
| property | type | description |
| ----------------- | ------------------------------------------------------- | ------------------------------------------------- |
| `measurements` | `Record` | Record of measurements for each tab trigger |
| `setMeasurements` | `(key: string, measurements: ItemMeasurements) => void` | Function to update measurements for a tab trigger |
| `variant` | `'primary' \| 'secondary'` | Visual variant of the tabs |
#### ItemMeasurements
| property | type | description |
| -------- | -------- | ----------------------------------- |
| `width` | `number` | Width of the tab trigger in pixels |
| `height` | `number` | Height of the tab trigger in pixels |
| `x` | `number` | X position of the tab trigger |
**Note:** This hook must be used within a `Tabs` component. It will throw an error if called outside of the tabs context.
### useTabsTrigger
Hook to access tab trigger context values within custom components or compound components.
```tsx
import { useTabsTrigger } from 'heroui-native';
const CustomLabel = () => {
const { value, isSelected, nativeID } = useTabsTrigger();
// ... your implementation
};
```
**Returns:** `UseTabsTriggerReturn`
| property | type | description |
| ------------ | --------- | ------------------------------------------ |
| `value` | `string` | The value of this trigger |
| `nativeID` | `string` | Unique identifier for this trigger |
| `isSelected` | `boolean` | Whether this trigger is currently selected |
**Note:** This hook must be used within a `Tabs.Trigger` component. It will throw an error if called outside of the trigger context.
# BottomSheet
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/bottom-sheet
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(overlays)/bottom-sheet.mdx
> Displays a bottom sheet that slides up from the bottom with animated transitions and swipe-to-dismiss gestures.
## Import
```tsx
import { BottomSheet } from 'heroui-native';
```
## Anatomy
```tsx
...
...
...
...
```
* **BottomSheet**: Root component that manages open state and provides context to child components.
* **BottomSheet.Trigger**: Pressable element that opens the bottom sheet when pressed.
* **BottomSheet.Portal**: Renders bottom sheet content in a portal with full window overlay.
* **BottomSheet.Overlay**: Background overlay that covers the screen, typically closes bottom sheet when pressed.
* **BottomSheet.Content**: Main bottom sheet container using @gorhom/bottom-sheet for rendering with gesture support.
* **BottomSheet.Close**: Close button for the bottom sheet. Can accept custom children or uses default close icon.
* **BottomSheet.Title**: Bottom sheet title text with semantic heading role and accessibility linking.
* **BottomSheet.Description**: Bottom sheet description text that provides additional context with accessibility linking.
## Usage
### Basic Bottom Sheet
Simple bottom sheet with title, description, and close button.
```tsx
Open Bottom Sheet
...
...
```
### Detached Bottom Sheet
Bottom sheet that appears detached from the bottom edge with custom spacing.
```tsx
...
...
```
### Scrollable with Snap Points
Bottom sheet with multiple snap points and scrollable content.
To make scrollable content work correctly inside `BottomSheet.Content`, follow these base principles:
* Use a scrollable from [`@gorhom/bottom-sheet`](https://gorhom.dev/react-native-bottom-sheet/components/bottomsheetscrollview) (e.g. `BottomSheetScrollView`, `BottomSheetFlatList`, `BottomSheetSectionList`, `BottomSheetVirtualizedList`). A plain `ScrollView`/`FlatList` from `react-native` will let the sheet intercept the scroll gesture.
* On `BottomSheet.Content`, disable over-drag and dynamic sizing so the sheet does not grow with its content or absorb the scroll: `enableOverDrag={false}` and `enableDynamicSizing={false}`.
* Give `BottomSheet.Content` a fixed height via `contentContainerClassName="h-full"` (or any other fixed height). The constraint must be on `BottomSheet.Content`, not on the scrollable child — the scrollable needs a bounded parent to scroll inside.
```tsx
import { BottomSheetScrollView } from '@gorhom/bottom-sheet';
...
...
;
```
See the full example with a sticky footer (`BottomSheetFooter`) in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/components/bottom-sheet/scrollable-with-snap-points.tsx).
### Blur Overlay
Use the built-in `blur` variant for an animated blur backdrop. iOS only, requires the optional `expo-blur` package; other platforms (or a missing package) fall back to the default solid backdrop. When the library theme is `glass`, the blur variant is used by default.
```tsx
...
...
```
### Custom Overlay
Replace the default overlay with custom content like blur effects.
```tsx
import { useBottomSheet, useBottomSheetAnimation } from 'heroui-native';
import { StyleSheet, Pressable } from 'react-native';
import { interpolate, useDerivedValue } from 'react-native-reanimated';
import { AnimatedBlurView } from './animated-blur-view';
import { useUniwind } from 'uniwind';
export const BottomSheetBlurOverlay = () => {
const { theme } = useUniwind();
const { onOpenChange } = useBottomSheet();
const { progress } = useBottomSheetAnimation();
const blurIntensity = useDerivedValue(() => {
return interpolate(progress.get(), [0, 1, 2], [0, 40, 0]);
});
return (
onOpenChange(false)}
>
);
};
```
```tsx
...
...
```
### With Keyboard-Aware Input
When rendering an `Input` or `InputOTP` inside `BottomSheet.Content`, use the `useBottomSheetAwareHandlers` hook to wire keyboard avoidance handlers. Pass the returned `onFocus` / `onBlur` to your input.
> **Note**: `useBottomSheetAwareHandlers` must be used inside a `BottomSheet`. Call it from a child component rendered inside `BottomSheet.Content` — outside of a `BottomSheet` context the returned handlers are no-ops.
For scrollable content, also configure `BottomSheet.Content` with `keyboardBehavior="extend"` (or `"interactive"`) and `keyboardShouldPersistTaps="handled"` on the scrollable so taps don't dismiss the keyboard before reaching their target.
```tsx
import { BottomSheet, Input, useBottomSheetAwareHandlers } from 'heroui-native';
const BottomSheetTextInput = () => {
const { onFocus, onBlur } = useBottomSheetAwareHandlers();
return ;
};
...
;
```
See full examples for [`Input`](https://github.com/heroui-inc/heroui-native/blob/main/example/src/components/bottom-sheet/with-text-input.tsx) and [`InputOTP`](https://github.com/heroui-inc/heroui-native/blob/main/example/src/components/bottom-sheet/with-otp-input.tsx) inside a bottom sheet.
## Example
```tsx
import { BottomSheet, Button } from 'heroui-native';
import { useState } from 'react';
import { View } from 'react-native';
import { withUniwind } from 'uniwind';
import Ionicons from '@expo/vector-icons/Ionicons';
const StyledIonicons = withUniwind(Ionicons);
export default function BottomSheetExample() {
const [isOpen, setIsOpen] = useState(false);
return (
Open Bottom Sheet
Keep yourself safe
Update your software to the latest version for better security and
performance.
setIsOpen(false)}>Update Now
setIsOpen(false)}>
Later
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/bottom-sheet.tsx).
## API Reference
### BottomSheet
| prop | type | default | description |
| --------------- | -------------------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Bottom sheet content and trigger elements |
| `isOpen` | `boolean` | - | Controlled open state of the bottom sheet |
| `isDefaultOpen` | `boolean` | `false` | Initial open state when uncontrolled |
| `animation` | `AnimationRootDisableAll` | - | Animation configuration |
| `onOpenChange` | `(value: boolean) => void` | - | Callback when open state changes |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### Animation Configuration
Animation configuration for bottom sheet root component. Can be:
* `"disable-all"`: Disable all animations including children
* `undefined`: Use default animations
### BottomSheet.Trigger
| prop | type | default | description |
| -------------------------- | ----------------------- | ------- | -------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Trigger element content |
| `asChild` | `boolean` | - | Render as child element without wrapper |
| `...TouchableOpacityProps` | `TouchableOpacityProps` | - | All standard React Native TouchableOpacity props are supported |
### BottomSheet.Portal
| prop | type | default | description |
| -------------------------------------------- | ---------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Portal content (overlay and bottom sheet) |
| `disableFullWindowOverlay` | `boolean` | `false` | When true on iOS, uses View instead of FullWindowOverlay. Enables element inspector; overlay won't appear above native modals |
| `unstable_accessibilityContainerViewIsModal` | `boolean` | `false` | Controls whether VoiceOver treats the overlay window as a modal container. When `true`, VoiceOver is restricted to elements inside the overlay. iOS only. Unstable: may change with react-native-screens updates |
| `className` | `string` | - | Additional CSS classes for portal container |
| `style` | `StyleProp` | - | Additional styles for portal container |
| `hostName` | `string` | - | Optional portal host name for specific container |
| `forceMount` | `boolean` | - | Force mount when closed for animation purposes |
### BottomSheet.Overlay
| prop | type | default | description |
| ----------------------- | ------------------------------------------------------ | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom overlay content |
| `className` | `string` | - | Additional CSS classes for overlay |
| `style` | `ViewStyle` | - | Additional styles for overlay container |
| `animation` | `Omit` | - | Animation configuration |
| `variant` | `'default' \| 'blur'` | `'default'` (`'blur'` when the library theme is `glass`) | Overlay variant. `'blur'` renders an animated blur backdrop (iOS only, requires `expo-blur`; falls back to `'default'` otherwise) |
| `blurViewProps` | `BlurViewProps` | - | Props forwarded to the BlurView rendered by the `'blur'` variant. `intensity` sets the maximum animated blur intensity (default: 75 dark / 50 light) |
| `isAnimatedStyleActive` | `boolean` | `true` (`false` for the `'blur'` variant) | Whether animated styles (react-native-reanimated) are active |
| `isCloseOnPress` | `boolean` | `true` | Whether pressing overlay closes bottom sheet |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported |
#### Animation Configuration
Animation configuration for bottom sheet overlay component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration (excluding `entering` and `exiting` properties)
| prop | type | default | description |
| --------------- | -------------------------- | ----------- | ----------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `opacity.value` | `[number, number, number]` | `[0, 1, 0]` | Opacity values \[idle, open, close] |
### BottomSheet.Content
| prop | type | default | description |
| --------------------------- | ---------------------------------------- | ------- | -------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Bottom sheet content |
| `className` | `string` | - | Additional CSS classes for bottom sheet container |
| `containerClassName` | `string` | - | Additional CSS classes for container |
| `contentContainerClassName` | `string` | - | Additional CSS classes for content container |
| `backgroundClassName` | `string` | - | Additional CSS classes for background |
| `handleClassName` | `string` | - | Additional CSS classes for handle |
| `handleIndicatorClassName` | `string` | - | Additional CSS classes for handle indicator |
| `contentContainerProps` | `Omit` | - | Props for the content container |
| `animation` | `AnimationDisabled` | - | Animation configuration |
| `...GorhomBottomSheetProps` | `Partial` | - | All [@gorhom/bottom-sheet props](https://gorhom.dev/react-native-bottom-sheet/props) are supported |
**Note**: You can use all components from [@gorhom/bottom-sheet](https://gorhom.dev/react-native-bottom-sheet/components/bottomsheetview) inside the content, such as `BottomSheetView`, `BottomSheetScrollView`, `BottomSheetFlatList`, etc.
### BottomSheet.Close
BottomSheet.Close extends [CloseButton](./close-button) and automatically handles bottom sheet dismissal when pressed.
### BottomSheet.Title
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Title content |
| `className` | `string` | - | Additional CSS classes for title |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
### BottomSheet.Description
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Description content |
| `className` | `string` | - | Additional CSS classes for description |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
## Hooks
### useBottomSheet
Hook to access bottom sheet primitive context.
```tsx
const { isOpen, onOpenChange } = useBottomSheet();
```
| property | type | description |
| -------------- | -------------------------- | ----------------------------- |
| `isOpen` | `boolean` | Current open state |
| `onOpenChange` | `(value: boolean) => void` | Function to change open state |
### useBottomSheetAnimation
Hook to access bottom sheet animation context for advanced customization.
```tsx
const { progress } = useBottomSheetAnimation();
```
| property | type | description |
| ---------- | --------------------- | -------------------------------------------- |
| `progress` | `SharedValue` | Animation progress (0=idle, 1=open, 2=close) |
### useBottomSheetAwareHandlers
Hook that returns `onFocus` and `onBlur` handlers for keyboard avoidance when an `Input` or `InputOTP` is rendered inside `BottomSheet.Content`. Must be used inside a `BottomSheet` — outside of a `BottomSheet` context, the returned handlers are no-ops.
```tsx
const { onFocus, onBlur } = useBottomSheetAwareHandlers();
```
| property | type | description |
| --------- | ------------------------- | ------------------------------------------------------------------------------------ |
| `onFocus` | `(e: FocusEvent) => void` | Focus handler that notifies the bottom sheet about the keyboard target |
| `onBlur` | `(e: BlurEvent) => void` | Blur handler that conditionally clears the keyboard target in the bottom sheet state |
## Special Notes
### Element Inspector (iOS)
BottomSheet uses FullWindowOverlay on iOS, which renders in a separate native window. This breaks the React Native element inspector. To enable the inspector during development, set `disableFullWindowOverlay={true}` on `BottomSheet.Portal`. Tradeoff: the bottom sheet will not appear above native modals when disabled.
### Handling Close Callbacks
It's recommended to use `BottomSheet`'s `onOpenChange` prop for handling close callbacks, as it reliably fires for all close scenarios (swiping down, pressing overlay, pressing close button, programmatic close, etc.).
```tsx
{
setIsOpen(value);
if (!value) {
// This callback runs whenever the bottom sheet closes
// regardless of how it was closed
yourCallbackOnClose();
}
}}
>
...
```
**Note**: `BottomSheet.Content`'s `onClose` prop (from @gorhom/bottom-sheet) has limitations and will only fire when the bottom sheet is closed by swiping down. It won't fire when closing via overlay press, close button, or programmatic close. For reliable close callbacks, always use `BottomSheet`'s `onOpenChange` prop instead.
# Dialog
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/dialog
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(overlays)/dialog.mdx
> Displays a modal overlay with animated transitions and gesture-based dismissal.
## Import
```tsx
import { Dialog } from 'heroui-native';
```
## Anatomy
```tsx
...
...
...
...
...
```
* **Dialog**: Root component that manages open state and provides context to child components.
* **Dialog.Trigger**: Pressable element that opens the dialog when pressed.
* **Dialog.Portal**: Renders dialog content in a portal with centered layout and animation control.
* **Dialog.Overlay**: Background overlay that appears behind the dialog content, typically closes dialog when pressed.
* **Dialog.Content**: Main dialog container with gesture support for drag-to-dismiss.
* **Dialog.Close**: Close button for the dialog. Can accept custom children or uses default close icon.
* **Dialog.Title**: Dialog title text with semantic heading role.
* **Dialog.Description**: Dialog description text that provides additional context.
## Usage
### Basic Dialog
Simple dialog with title, description, and close button.
```tsx
Open Dialog
...
...
```
### Scrollable Content
Handle long content with scroll views.
```tsx
...
...
...
```
### Blur Backdrop
Overlay with an animated blur backdrop. iOS only, requires the optional `expo-blur` package; other platforms (or a missing package) fall back to the default solid backdrop. When the library theme is `glass`, the blur variant is used by default.
```tsx
...
...
```
### Form Dialog
Dialog with text inputs and keyboard handling.
```tsx
...
...
...
Submit
```
## Example
```tsx
import { Button, Dialog } from 'heroui-native';
import { View } from 'react-native';
import { useState } from 'react';
export default function DialogExample() {
const [isOpen, setIsOpen] = useState(false);
return (
Open Dialog
Confirm Action
Are you sure you want to proceed with this action? This cannot be
undone.
setIsOpen(false)}>
Cancel
Confirm
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/dialog.tsx).
## API Reference
### Dialog
| prop | type | default | description |
| --------------- | -------------------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Dialog content and trigger elements |
| `isOpen` | `boolean` | - | Controlled open state of the dialog |
| `isDefaultOpen` | `boolean` | `false` | Initial open state when uncontrolled |
| `animation` | `AnimationRootDisableAll` | - | Animation configuration |
| `onOpenChange` | `(value: boolean) => void` | - | Callback when open state changes |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### AnimationRootDisableAll
Animation configuration for dialog root component. Can be:
* `false` or `"disabled"`: Disable only root animations
* `"disable-all"`: Disable all animations including children
* `true` or `undefined`: Use default animations
### Dialog.Trigger
| prop | type | default | description |
| -------------------------- | ----------------------- | ------- | -------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Trigger element content |
| `asChild` | `boolean` | - | Render as child element without wrapper |
| `...TouchableOpacityProps` | `TouchableOpacityProps` | - | All standard React Native TouchableOpacity props are supported |
### Dialog.Portal
| prop | type | default | description |
| -------------------------------------------- | ---------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Portal content (overlay and dialog) |
| `disableFullWindowOverlay` | `boolean` | `false` | When true on iOS, uses View instead of FullWindowOverlay. Enables element inspector; overlay won't appear above native modals |
| `unstable_accessibilityContainerViewIsModal` | `boolean` | `false` | Controls whether VoiceOver treats the overlay window as a modal container. When `true`, VoiceOver is restricted to elements inside the overlay. iOS only. Unstable: may change with react-native-screens updates |
| `className` | `string` | - | Additional CSS classes for portal container |
| `style` | `StyleProp` | - | Additional styles for portal container |
| `hostName` | `string` | - | Optional portal host name for specific container |
| `forceMount` | `boolean` | - | Force mount when closed for animation purposes |
### Dialog.Overlay
| prop | type | default | description |
| ----------------------- | ------------------------ | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom overlay content |
| `className` | `string` | - | Additional CSS classes for overlay |
| `style` | `ViewStyle` | - | Additional styles for overlay container |
| `animation` | `DialogOverlayAnimation` | - | Animation configuration |
| `variant` | `'default' \| 'blur'` | `'default'` (`'blur'` when the library theme is `glass`) | Overlay variant. `'blur'` renders an animated blur backdrop (iOS only, requires `expo-blur`; falls back to `'default'` otherwise) |
| `blurViewProps` | `BlurViewProps` | - | Props forwarded to the BlurView rendered by the `'blur'` variant. `intensity` sets the maximum animated blur intensity (default: 75 dark / 50 light) |
| `isAnimatedStyleActive` | `boolean` | `true` (`false` for the `'blur'` variant) | Whether animated styles (react-native-reanimated) are active |
| `isCloseOnPress` | `boolean` | `true` | Whether pressing overlay closes dialog |
| `forceMount` | `boolean` | - | Force mount when closed for animation purposes |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported |
#### DialogOverlayAnimation
Animation configuration for dialog overlay component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| --------------- | -------------------------- | ----------------------- | ----------------------------------------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `opacity.value` | `[number, number, number]` | `[0, 1, 0]` | Opacity values \[idle, open, close] (progress-based, for dialog presentation) |
| `entering` | `EntryOrExitLayoutType` | `FadeIn.duration(200)` | Custom entering animation (for popover presentation) |
| `exiting` | `EntryOrExitLayoutType` | `FadeOut.duration(150)` | Custom exiting animation (for popover presentation) |
### Dialog.Content
| prop | type | default | description |
| ----------------------- | ------------------------ | ------- | --------------------------------------------------- |
| `children` | `React.ReactNode` | - | Dialog content |
| `className` | `string` | - | Additional CSS classes for content container |
| `style` | `StyleProp` | - | Additional styles for content container |
| `animation` | `DialogContentAnimation` | - | Animation configuration |
| `isSwipeable` | `boolean` | `true` | Whether the dialog content can be swiped to dismiss |
| `forceMount` | `boolean` | - | Force mount when closed for animation purposes |
| `...Animated.ViewProps` | `Animated.ViewProps` | - | All Reanimated Animated.View props are supported |
#### DialogContentAnimation
Animation configuration for dialog content component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ---------- | ----------------------- | ------------------------------------------------------------------------------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `entering` | `EntryOrExitLayoutType` | Keyframe with `scale: 0.96→1` and `opacity: 0→1` (200ms, easing: `Easing.out(Easing.ease)`) | Custom entering animation |
| `exiting` | `EntryOrExitLayoutType` | Keyframe with `scale: 1→0.96` and `opacity: 1→0` (150ms, easing: `Easing.in(Easing.ease)`) | Custom exiting animation |
### Dialog.Close
Dialog.Close extends [CloseButton](./close-button) and automatically handles dialog dismissal when pressed.
### Dialog.Title
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Title content |
| `className` | `string` | - | Additional CSS classes for title |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
### Dialog.Description
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Description content |
| `className` | `string` | - | Additional CSS classes for description |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
## Hooks
### useDialog
Hook to access dialog primitive context.
```tsx
const { isOpen, onOpenChange } = useDialog();
```
| property | type | description |
| -------------- | -------------------------- | ----------------------------- |
| `isOpen` | `boolean` | Current open state |
| `onOpenChange` | `(value: boolean) => void` | Function to change open state |
### useDialogAnimation
Hook to access dialog animation context for advanced customization.
```tsx
const { progress, isDragging, isGestureReleaseAnimationRunning } =
useDialogAnimation();
```
| property | type | description |
| ---------------------------------- | ---------------------- | -------------------------------------------- |
| `progress` | `SharedValue` | Animation progress (0=idle, 1=open, 2=close) |
| `isDragging` | `SharedValue` | Whether dialog is being dragged |
| `isGestureReleaseAnimationRunning` | `SharedValue` | Whether gesture release animation is running |
## Special Notes
### Element Inspector (iOS)
Dialog uses FullWindowOverlay on iOS. To enable the React Native element inspector during development, set `disableFullWindowOverlay={true}` on `Dialog.Portal`. Tradeoff: the dialog will not appear above native modals when disabled.
# Popover
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/popover
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(overlays)/popover.mdx
> Displays a floating content panel anchored to a trigger element with placement and alignment options.
## Import
```tsx
import { Popover } from 'heroui-native';
```
## Anatomy
```tsx
...
...
...
```
* **Popover**: Main container that manages open/close state, positioning, and provides context to child components.
* **Popover.Trigger**: Clickable element that toggles popover visibility. Wraps any child element with press handlers.
* **Popover.Portal**: Renders popover content in a portal layer above other content. Ensures proper stacking and positioning.
* **Popover.Overlay**: Optional background overlay. Can be transparent or semi-transparent to capture outside clicks.
* **Popover.Content**: Container for popover content with positioning, styling, and collision detection. Supports both popover and bottom-sheet presentations.
* **Popover.Arrow**: Optional arrow element pointing to the trigger. Automatically positioned based on placement.
* **Popover.Close**: Close button for the popover. Can accept custom children or uses default close icon.
* **Popover.Title**: Optional title text with pre-styled typography.
* **Popover.Description**: Optional description text with muted styling.
## Usage
### Basic Usage
The Popover component uses compound parts to create floating content panels.
```tsx
...
...
```
### With Title and Description
Structure popover content with title and description for better information hierarchy.
```tsx
...
...
...
```
### With Arrow
Add an arrow pointing to the trigger element for better visual connection.
```tsx
...
...
```
> **Note:** When using ` `, you need to apply a border to `Popover.Content`, for instance using the `border border-border` class. This ensures the arrow visually connects properly with the content border.
### Width Control
Control the width of the popover content using the `width` prop.
```tsx
{
/* Fixed width in pixels */
}
...
...
;
{
/* Match trigger width */
}
...
...
;
{
/* Full width (100%) */
}
...
...
;
{
/* Auto-size to content (default) */
}
...
...
;
```
### Bottom Sheet Presentation
Use bottom sheet presentation for mobile-optimized interaction patterns.
> **Important:** The `presentation` prop on `Popover.Content` must match the `presentation` prop on `Popover.Root`. In development mode, a mismatch will throw an error.
```tsx
...
...
...
Close
```
### Placement Options
Control where the popover appears relative to the trigger element.
```tsx
...
...
```
### Alignment Options
Fine-tune content alignment along the placement axis.
```tsx
...
...
```
### Custom Animation
Configure custom animations for open and close transitions using the `animation` prop on `Popover.Root`.
```tsx
...
...
```
### Programmatic control
```tsx
// Open or close popover programmatically using ref
const popoverRef = useRef(null);
// Open programmatically
popoverRef.current?.open();
// Close programmatically
popoverRef.current?.close();
// Full example
Trigger
Content
popoverRef.current?.close()}>Close
;
```
## Example
```tsx
import { Ionicons } from '@expo/vector-icons';
import { Button, Popover, useThemeColor } from 'heroui-native';
import { Text, View } from 'react-native';
export default function PopoverExample() {
const themeColorMuted = useThemeColor('muted');
return (
Show Info
Information
This popover includes a title and description to provide more
structured information to users.
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/popover.tsx).
## API Reference
### Popover
| prop | type | default | description |
| --------------- | ----------------------------- | ----------- | ---------------------------------------------------------------------------------------------- |
| `children` | `ReactNode` | - | Children elements to be rendered inside the popover |
| `isOpen` | `boolean` | - | Whether the popover is open (controlled mode) |
| `isDefaultOpen` | `boolean` | - | The open state of the popover when initially rendered (uncontrolled mode) |
| `onOpenChange` | `(isOpen: boolean) => void` | - | Callback when the popover open state changes |
| `animation` | `AnimationRootDisableAll` | - | Animation configuration. Can be `false`, `"disabled"`, `"disable-all"`, `true`, or `undefined` |
| `presentation` | `'popover' \| 'bottom-sheet'` | `'popover'` | Presentation mode for the popover content |
| `asChild` | `boolean` | `false` | Whether to render as a child element |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### AnimationRootDisableAll
Animation configuration for popover root component. Can be:
* `false` or `"disabled"`: Disable only root animations
* `"disable-all"`: Disable all animations including children
* `true` or `undefined`: Use default animations
### Popover.Trigger
| prop | type | default | description |
| ------------------- | ---------------- | ------- | ------------------------------------------------------- |
| `children` | `ReactNode` | - | The trigger element content |
| `className` | `string` | - | Additional CSS classes for the trigger |
| `asChild` | `boolean` | `true` | Whether to render as a child element |
| `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported |
### Popover.Portal
| prop | type | default | description |
| -------------------------------------------- | ----------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `children` | `ReactNode` | - | The portal content (required) |
| `disableFullWindowOverlay` | `boolean` | `false` | When true on iOS, uses View instead of FullWindowOverlay. Enables element inspector; overlay won't appear above native modals |
| `unstable_accessibilityContainerViewIsModal` | `boolean` | `false` | Controls whether VoiceOver treats the overlay window as a modal container. When `true`, VoiceOver is restricted to elements inside the overlay. iOS only. Unstable: may change with react-native-screens updates |
| `hostName` | `string` | - | Optional name of the host element for the portal |
| `forceMount` | `boolean` | - | Whether to force mount the component in the DOM |
| `className` | `string` | - | Additional CSS classes for the portal container |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### Popover.Overlay
| prop | type | default | description |
| ----------------------- | ------------------------- | ------- | ------------------------------------------------------------ |
| `className` | `string` | - | Additional CSS classes for the overlay |
| `closeOnPress` | `boolean` | `true` | Whether to close the popover when overlay is pressed |
| `forceMount` | `boolean` | - | Whether to force mount the component in the DOM |
| `animation` | `PopoverOverlayAnimation` | - | Animation configuration |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `asChild` | `boolean` | `false` | Whether to render as a child element |
| `...Animated.ViewProps` | `Animated.ViewProps` | - | All Reanimated Animated.View props are supported |
#### PopoverOverlayAnimation
Animation configuration for popover overlay component. Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| --------------- | -------------------------- | --------------------------- | ----------------------------------------------------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `opacity.value` | `[number, number, number]` | `[0, 1, 0]` | Opacity values \[idle, open, close] - Takes effect for bottom-sheet/dialog presentation |
| `entering` | `EntryOrExitLayoutType` | FadeIn with duration 200ms | Custom Keyframe animation for entering transition - Takes effect for popover presentation |
| `exiting` | `EntryOrExitLayoutType` | FadeOut with duration 150ms | Custom Keyframe animation for exiting transition - Takes effect for popover presentation |
### Popover.Content (Popover Presentation)
| prop | type | default | description |
| ------------------------- | ------------------------------------------------ | --------------- | ------------------------------------------------------------------------------------------------------- |
| `children` | `ReactNode` | - | The popover content |
| `presentation` | `'popover'` | `'popover'` | Presentation mode - must match Popover.Root presentation prop. When not provided, defaults to 'popover' |
| `width` | `number \| 'trigger' \| 'content-fit' \| 'full'` | `'content-fit'` | Width sizing strategy for the content |
| `placement` | `'top' \| 'bottom' \| 'left' \| 'right'` | `'bottom'` | Placement of the popover relative to trigger |
| `align` | `'start' \| 'center' \| 'end'` | `'center'` | Alignment along the placement axis |
| `avoidCollisions` | `boolean` | `true` | Whether to flip placement when close to viewport edges |
| `offset` | `number` | `9` | Distance from trigger element in pixels |
| `alignOffset` | `number` | `0` | Offset along the alignment axis in pixels |
| `disablePositioningStyle` | `boolean` | `false` | Whether to disable automatic positioning styles |
| `forceMount` | `boolean` | - | Whether to force mount the component in the DOM |
| `insets` | `Insets` | - | Screen edge insets to respect when positioning |
| `className` | `string` | - | Additional CSS classes for the content container |
| `animation` | `PopupPopoverContentAnimation` | - | Animation configuration |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `asChild` | `boolean` | `false` | Whether to render as a child element |
| `...Animated.ViewProps` | `Animated.ViewProps` | - | All Reanimated Animated.View props are supported |
### Popover.Content (Bottom Sheet Presentation)
| prop | type | default | description |
| --------------------------- | ---------------------- | ------- | ---------------------------------------------------------------------------------------------- |
| `children` | `ReactNode` | - | The bottom sheet content |
| `presentation` | `'bottom-sheet'` | - | Presentation mode - must be 'bottom-sheet' and match Popover.Root presentation prop (required) |
| `contentContainerClassName` | `string` | - | Additional CSS classes for the content container |
| `contentContainerProps` | `BottomSheetViewProps` | - | Props for the content container |
| `enablePanDownToClose` | `boolean` | `true` | Whether pan down gesture closes the sheet |
| `backgroundStyle` | `ViewStyle` | - | Style for the bottom sheet background |
| `handleIndicatorStyle` | `ViewStyle` | - | Style for the bottom sheet handle indicator |
| `...BottomSheetProps` | `BottomSheetProps` | - | All @gorhom/bottom-sheet props are supported |
#### PopupPopoverContentAnimation
Animation configuration for popover content component (popover presentation). Can be:
* `false` or `"disabled"`: Disable all animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ---------- | ----------------------- | --------------------------------------------------------------- | ------------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `entering` | `EntryOrExitLayoutType` | Keyframe with translateY/translateX, scale, and opacity (200ms) | Custom Keyframe animation for entering transition |
| `exiting` | `EntryOrExitLayoutType` | Keyframe mirroring entering animation (150ms) | Custom Keyframe animation for exiting transition |
### Popover.Arrow
| prop | type | default | description |
| --------------------- | ---------------------------------------- | ------- | --------------------------------------------------------------------- |
| `className` | `string` | - | Additional CSS classes for the arrow |
| `height` | `number` | `12` | Height of the arrow in pixels |
| `width` | `number` | `20` | Width of the arrow in pixels |
| `fill` | `string` | - | Fill color of the arrow (defaults to content background) |
| `stroke` | `string` | - | Stroke (border) color of the arrow (defaults to content border color) |
| `strokeWidth` | `number` | `1` | Stroke width of the arrow border in pixels |
| `strokeBaselineInset` | `number` | `1` | Baseline inset in pixels for stroke alignment |
| `placement` | `'top' \| 'bottom' \| 'left' \| 'right'` | - | Placement of the popover (inherited from content) |
| `children` | `ReactNode` | - | Custom arrow content (replaces default SVG arrow) |
| `style` | `StyleProp` | - | Additional styles for the arrow container |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
### Popover.Close
Popover.Close extends [CloseButton](./close-button) and automatically handles popover dismissal when pressed.
### Popover.Title
| prop | type | default | description |
| -------------- | ----------- | ------- | -------------------------------------------------- |
| `children` | `ReactNode` | - | The title text content |
| `className` | `string` | - | Additional CSS classes for the title |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
### Popover.Description
| prop | type | default | description |
| -------------- | ----------- | ------- | -------------------------------------------------- |
| `children` | `ReactNode` | - | The description text content |
| `className` | `string` | - | Additional CSS classes for the description |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
## Hooks
### usePopover
Hook to access popover context values within custom components or compound components.
```tsx
import { usePopover } from 'heroui-native';
const CustomContent = () => {
const { isOpen, onOpenChange, triggerPosition } = usePopover();
// ... your implementation
};
```
**Returns:** `UsePopoverReturn`
| property | type | description |
| -------------------- | --------------------------------------------------- | ----------------------------------------------------------------- |
| `isOpen` | `boolean` | Whether the popover is currently open |
| `onOpenChange` | `(open: boolean) => void` | Callback function to change the popover open state |
| `isDefaultOpen` | `boolean \| undefined` | Whether the popover should be open by default (uncontrolled mode) |
| `isDisabled` | `boolean \| undefined` | Whether the popover is disabled |
| `triggerPosition` | `LayoutPosition \| null` | The position of the trigger element relative to the viewport |
| `setTriggerPosition` | `(triggerPosition: LayoutPosition \| null) => void` | Function to update the trigger element's position |
| `contentLayout` | `LayoutRectangle \| null` | The layout measurements of the popover content |
| `setContentLayout` | `(contentLayout: LayoutRectangle \| null) => void` | Function to update the content layout measurements |
| `nativeID` | `string` | Unique identifier for the popover instance |
**Note:** This hook must be used within a `Popover` component. It will throw an error if called outside of the popover context.
### usePopoverAnimation
Hook to access popover animation state values within custom components or compound components.
```tsx
import { usePopoverAnimation } from 'heroui-native';
const CustomContent = () => {
const { progress, isDragging } = usePopoverAnimation();
// ... your implementation
};
```
**Returns:** `UsePopoverAnimationReturn`
| property | type | description |
| ------------ | ---------------------- | ------------------------------------------------------------------ |
| `progress` | `SharedValue` | Progress value for the popover animation (0=idle, 1=open, 2=close) |
| `isDragging` | `SharedValue` | Dragging state shared value |
**Note:** This hook must be used within a `Popover` component. It will throw an error if called outside of the popover animation context.
## Special Notes
### Element Inspector (iOS)
Popover uses FullWindowOverlay on iOS. To enable the React Native element inspector during development, set `disableFullWindowOverlay={true}` on `Popover.Portal`. Tradeoff: the popover will not appear above native modals when disabled.
### Native Modal (iOS)
When a `Popover` is opened inside a screen presented as a native modal (`presentation: 'modal' | 'formSheet' | 'pageSheet'`), the popover content may render shifted upward. In the new architecture (Fabric), `react-native-screens` marks `RNSModalScreen` as a Fabric root, so the trigger's position is reported relative to the modal's origin while `FullWindowOverlay` (where the popover is mounted) is anchored to the iOS application window. Compensate by adding `safeAreaInsets.top` to `offset`:
```tsx
import { useSafeAreaInsets } from 'react-native-safe-area-context';
const insets = useSafeAreaInsets();
...
;
```
# Toast
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/toast
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(overlays)/toast.mdx
> Displays temporary notification messages that appear at the top or bottom of the screen.
## Import
```tsx
import { Toast, useToast } from 'heroui-native';
```
## Anatomy
```tsx
...
...
...
```
* **Toast**: Main container that displays notification messages. Handles positioning, animations, and swipe gestures.
* **Toast.Title**: Title text of the toast notification. Inherits variant styling from parent Toast context.
* **Toast.Description**: Descriptive text content displayed below the title.
* **Toast.Action**: Action button within the toast. Button variant is automatically determined based on toast variant but can be overridden.
* **Toast.Close**: Close button for dismissing the toast. Renders as an icon-only button that calls hide when pressed.
## Usage
### Usage Pattern 1: Simple String
Show a toast with a simple string message.
```tsx
const { toast } = useToast();
toast.show('This is a toast message');
```
### Usage Pattern 2: Config Object
Show a toast with label, description, variant, and action button using a config object.
```tsx
const { toast } = useToast();
toast.show({
variant: 'success',
label: 'You have upgraded your plan',
description: 'You can continue using HeroUI Chat',
icon: ,
actionLabel: 'Close',
onActionPress: ({ hide }) => hide(),
});
```
### Usage Pattern 3: Custom Component
Show a toast with a fully custom component for complete control over styling and layout.
```tsx
const { toast } = useToast();
toast.show({
component: (props) => (
Custom Toast
This is a custom toast component
),
});
```
**Note**: Toast items are memoized for performance. If you need to pass external state (like loading state) to a custom toast component, it will not update automatically. Use shared state techniques instead, such as React Context, state management libraries, or refs to ensure state updates propagate to the toast component.
### Disabling All Animations
Disable all animations including children by using `"disable-all"`. This cascades down to all child components (like Button in Toast.Action).
```tsx
const { toast } = useToast();
toast.show({
variant: 'success',
label: 'Operation completed',
description: 'All animations are disabled',
animation: 'disable-all',
});
```
Or with a custom component:
```tsx
const { toast } = useToast();
toast.show({
component: (props) => (
No animations
This toast has all animations disabled
Action
),
});
```
## Example
```tsx
import { Button, Toast, useToast, useThemeColor } from 'heroui-native';
import { View } from 'react-native';
export default function ToastExample() {
const { toast } = useToast();
const themeColorForeground = useThemeColor('foreground');
return (
toast.show({
variant: 'success',
label: 'You have upgraded your plan',
description: 'You can continue using HeroUI Chat',
actionLabel: 'Close',
onActionPress: ({ hide }) => hide(),
})
}
>
Show Success Toast
toast.show({
component: (props) => (
Custom Toast
This uses a custom component
props.hide()}>Undo
),
})
}
>
Show Custom Toast
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/toast.tsx).
## Global Configuration
Configure toast behavior globally using `HeroUINativeProvider` config prop. Global configs serve as defaults for all toasts unless overridden locally.
> **Note**: For complete provider configuration options, see the [Provider documentation](/docs/native/getting-started/handbook/provider#toast-configuration).
### Insets
Insets control the distance of toast sides from screen edges. Insets are added to safe area insets. To set all toasts to have a side distance of 20px from screen edges, configure insets:
```tsx
{children}
```
### Content Wrapper with KeyboardAvoidingView
Wrap toast content with KeyboardAvoidingView to ensure toasts adjust when the keyboard appears:
```tsx
import {
KeyboardAvoidingView,
KeyboardProvider,
} from 'react-native-keyboard-controller';
import { HeroUINativeProvider } from 'heroui-native';
import { useCallback } from 'react';
function AppContent() {
const contentWrapper = useCallback(
(children: React.ReactNode) => (
{children}
),
[]
);
return (
{children}
);
}
```
### Default Props
Set global defaults for variant, placement, animation, and swipe behavior:
```tsx
{children}
```
## API Reference
### Toast
| prop | type | default | description |
| ----------------------- | ------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------- |
| `variant` | `'default' \| 'accent' \| 'success' \| 'warning' \| 'danger'` | `'default'` | Visual variant of the toast |
| `placement` | `'top' \| 'bottom'` | `'top'` | Placement of the toast on screen |
| `isSwipeable` | `boolean` | `true` | Whether the toast can be swiped to dismiss and dragged with rubber effect |
| `animation` | `ToastRootAnimation` | - | Animation configuration |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `className` | `string` | - | Additional CSS class for the toast container |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### ToastRootAnimation
Animation configuration for Toast component. Can be:
* `false` or `"disabled"`: Disable only root animations
* `"disable-all"`: Disable all animations including children
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| `state` | `'disabled' \| 'disable-all' \| boolean` | - | Disable animations while customizing properties |
| `opacity.value` | `[number, number]` | `[1, 0]` | Opacity interpolation values for fade effect as toasts move beyond visible stack |
| `opacity.timingConfig` | `WithTimingConfig` | `{ duration: 300 }` | Animation timing configuration for opacity transitions |
| `translateY.value` | `[number, number]` | `[0, 10]` | Translate Y interpolation values for peek effect of stacked toasts |
| `translateY.timingConfig` | `WithTimingConfig` | `{ duration: 300 }` | Animation timing configuration for translateY transitions |
| `scale.value` | `[number, number]` | `[1, 0.97]` | Scale interpolation values for depth effect of stacked toasts |
| `scale.timingConfig` | `WithTimingConfig` | `{ duration: 300 }` | Animation timing configuration for scale transitions |
| `entering.top` | `EntryOrExitLayoutType` | `FadeInUp` `.springify()` `.withInitialValues({ opacity: 1, transform: [{ translateY: -100 }] })` `.mass(3)` | Custom entering animation for top placement |
| `entering.bottom` | `EntryOrExitLayoutType` | `FadeInDown` `.springify()` `.withInitialValues({ opacity: 1, transform: [{ translateY: 100 }] })` `.mass(3)` | Custom entering animation for bottom placement |
| `exiting.top` | `EntryOrExitLayoutType` | Keyframe animation with `translateY: -100, scale: 0.97, opacity: 0.5` | Custom exiting animation for top placement |
| `exiting.bottom` | `EntryOrExitLayoutType` | Keyframe animation with `translateY: 100, scale: 0.97, opacity: 0.5` | Custom exiting animation for bottom placement |
### Toast.Title
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Content to be rendered as title |
| `className` | `string` | - | Additional CSS classes |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
### Toast.Description
| prop | type | default | description |
| -------------- | ----------------- | ------- | -------------------------------------------------- |
| `children` | `React.ReactNode` | - | Content to be rendered as description |
| `className` | `string` | - | Additional CSS classes |
| `...TextProps` | `TextProps` | - | All standard React Native Text props are supported |
### Toast.Action
Toast.Action extends all props from [Button](button) component. Button variant is automatically determined based on toast variant but can be overridden.
| prop | type | default | description |
| ----------- | ---------------------- | ------- | ---------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Content to be rendered as action button label |
| `variant` | `ButtonVariant` | - | Button variant. If not provided, automatically determined from toast variant |
| `size` | `'sm' \| 'md' \| 'lg'` | `'sm'` | Size of the action button |
| `className` | `string` | - | Additional CSS classes |
For inherited props including `onPress`, `isDisabled`, and all Button props, see [Button API Reference](button#api-reference).
### Toast.Close
Toast.Close extends all props from [Button](button) component.
| prop | type | default | description |
| ----------- | ----------------------------------- | ------- | ---------------------------------------------- |
| `children` | `React.ReactNode` | - | Custom close icon. Defaults to CloseIcon |
| `iconProps` | `{ size?: number; color?: string }` | - | Props for the default close icon |
| `size` | `'sm' \| 'md' \| 'lg'` | `'sm'` | Size of the close button |
| `className` | `string` | - | Additional CSS classes |
| `onPress` | `(event: any) => void` | - | Custom press handler. Defaults to hiding toast |
For inherited props including `isDisabled` and all Button props, see [Button API Reference](button#api-reference).
### ToastProviderProps
Props for configuring toast behavior globally via `HeroUINativeProvider` config prop.
| prop | type | default | description |
| -------------------------------------------- | --------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `defaultProps` | `ToastGlobalConfig` | - | Global toast configuration used as defaults for all toasts |
| `disableFullWindowOverlay` | `boolean` | `false` | When true on iOS, uses View instead of FullWindowOverlay. Enables element inspector; toasts won't appear above native modals |
| `unstable_accessibilityContainerViewIsModal` | `boolean` | `false` | Controls whether VoiceOver treats the overlay window as a modal container. When `true`, VoiceOver is restricted to elements inside the overlay. iOS only. Unstable: may change with react-native-screens updates |
| `insets` | `ToastInsets` | - | Insets for spacing from screen edges (added to safe area insets) |
| `maxVisibleToasts` | `number` | `3` | Maximum number of visible toasts before opacity starts fading |
| `contentWrapper` | `(children: React.ReactNode) => React.ReactElement` | - | Custom wrapper function to wrap toast content |
| `children` | `React.ReactNode` | - | Children to render |
#### ToastGlobalConfig
Global toast configuration used as defaults for all toasts unless overridden locally.
| prop | type | description |
| ------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `variant` | `'default' \| 'accent' \| 'success' \| 'warning' \| 'danger'` | Visual variant of the toast |
| `placement` | `'top' \| 'bottom'` | Placement of the toast on screen |
| `isSwipeable` | `boolean` | Whether the toast can be swiped to dismiss and dragged with rubber effect |
| `animation` | `ToastRootAnimation` | Animation configuration for toast |
#### ToastInsets
Insets for spacing from screen edges. Values are added to safe area insets.
| prop | type | default | description |
| -------- | -------- | ------- | --------------------------------------------------------------------------------------------------------- |
| `top` | `number` | - | Inset from the top edge in pixels (added to safe area inset). Platform-specific: iOS = 0, Android = 12 |
| `bottom` | `number` | - | Inset from the bottom edge in pixels (added to safe area inset). Platform-specific: iOS = 6, Android = 12 |
| `left` | `number` | - | Inset from the left edge in pixels (added to safe area inset). Default: 12 |
| `right` | `number` | - | Inset from the right edge in pixels (added to safe area inset). Default: 12 |
## Hooks
### useToast
Hook to access toast functionality. Must be used within a `ToastProvider` (provided by `HeroUINativeProvider`).
| return value | type | description |
| ---------------- | -------------- | ---------------------------------------- |
| `toast` | `ToastManager` | Toast manager with show and hide methods |
| `isToastVisible` | `boolean` | Whether any toast is currently visible |
#### ToastManager
| method | type | description |
| ------ | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `show` | `(options: string \| ToastShowOptions) => string` | Show a toast. Returns the ID of the shown toast. Supports three usage patterns: simple string, config object, or custom component |
| `hide` | `(ids?: string \| string[] \| 'all') => void` | Hide one or more toasts. No argument hides the last toast, 'all' hides all toasts, single ID or array of IDs hides specific toast(s) |
#### ToastShowOptions
Options for showing a toast. Can be either a config object with default styling or a custom component.
**When using config object (without component):**
| prop | type | default | description |
| --------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `variant` | `'default' \| 'accent' \| 'success' \| 'warning' \| 'danger'` | - | Visual variant of the toast |
| `placement` | `'top' \| 'bottom'` | - | Placement of the toast on screen |
| `isSwipeable` | `boolean` | - | Whether the toast can be swiped to dismiss |
| `animation` | `ToastRootAnimation \| false \| "disabled" \| "disable-all"` | - | Animation configuration for toast |
| `duration` | `number \| 'persistent'` | `4000` | Duration in milliseconds before auto-hide. `0` auto-hides on the next tick; only `'persistent'` keeps the toast on screen indefinitely |
| `id` | `string` | - | Optional ID for the toast. If not provided, one will be generated |
| `label` | `string` | - | Label text for the toast |
| `description` | `string` | - | Description text for the toast |
| `actionLabel` | `string` | - | Action button label text |
| `onActionPress` | `(helpers: { show: (options: string \| ToastShowOptions) => string; hide: (ids?: string \| string[] \| 'all') => void }) => void` | - | Callback function called when the action button is pressed |
| `icon` | `React.ReactNode` | - | Icon element to display in the toast |
| `onShow` | `() => void` | - | Callback function called when the toast is shown |
| `onHide` | `() => void` | - | Callback function called when the toast is hidden |
**When using custom component:**
| prop | type | default | description |
| ----------- | ---------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | `string` | - | Optional ID for the toast. If not provided, one will be generated |
| `component` | `(props: ToastComponentProps) => React.ReactElement` | - | A function that receives toast props and returns a React element |
| `duration` | `number \| 'persistent'` | `4000` | Duration in milliseconds before auto-hide. `0` auto-hides on the next tick; only `'persistent'` keeps the toast on screen indefinitely |
| `onShow` | `() => void` | - | Callback function called when the toast is shown |
| `onHide` | `() => void` | - | Callback function called when the toast is hidden |
## Special Notes
### Element Inspector (iOS)
Toast uses FullWindowOverlay on iOS. To enable the React Native element inspector during development, set `disableFullWindowOverlay={true}` on `ToastProvider` (via `config.toast` when using HeroUINativeProvider). Tradeoff: toasts will not appear above native modals when disabled.
# Typography
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/text
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(typography)/text.mdx
> Primitive typography component for rendering styled text with semantic type variants.
## Import
```tsx
import { Typography } from 'heroui-native';
```
## Anatomy
```tsx
...
{/* Sub-components */}
...
...
...
```
* **Typography**: Root text element. Selects a typography preset via `type` and exposes orthogonal `align`, `color`, `weight`, and `truncate` props.
* **Typography.Heading**: Convenience wrapper restricted to heading types (`h1`–`h6`). Adds `accessibilityRole="header"` automatically.
* **Typography.Paragraph**: Convenience wrapper restricted to body types (`body`, `body-sm`, `body-xs`).
* **Typography.Code**: Chip-styled inline monospaced text. Uses a platform-appropriate monospace font family.
## Usage
### Basic Usage
The Typography component renders body text by default.
```tsx
Hello, world!
```
### Type Variants
Use the `type` prop to select a semantic typography preset.
```tsx
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Body text
Small body text
Extra-small body text
Code snippet
```
### Headings
Use `Typography.Heading` for heading text with automatic header accessibility role.
```tsx
Page Title
Section Title
Subsection Title
```
### Paragraphs
Use `Typography.Paragraph` for body text.
```tsx
This is a paragraph of body text with the default size.
This is smaller body text.
```
### Code
Use `Typography.Code` (or equivalently ``) for inline code snippets. Both render a chip-styled, monospaced inline element with a subtle background, rounded corners, and a `self-start` layout so it does not stretch in flex containers. The platform monospace `fontFamily` is applied at the `Typography` root, so the two forms are interchangeable.
```tsx
console.log('hello')
console.log('hello')
```
### Alignment
Use the `align` prop to control horizontal alignment. `start` and `end` are RTL-aware (they flip under right-to-left layouts).
```tsx
Start-aligned
Center-aligned
End-aligned
Justified text spreads across the line.
```
> **Note:** `text-justify` is iOS-only on React Native; Android falls back to left alignment.
### Color
Use the `color` prop to apply a semantic foreground color preset.
```tsx
Default foreground
Muted secondary text
```
For other theme colors, pass the corresponding utility through `className` (e.g. `className="text-accent"`, `className="text-danger"`).
### Weight
Use the `weight` prop to override the font weight implied by `type`. The override merges via `tailwind-merge`, so it always wins over the type variant's default weight.
```tsx
Bold H1
Medium body
Semibold body
```
If your app defines custom `--font-*` families, each weight resolves to the matching family instead of a numeric weight, so every weight you use needs its variable defined. See [Custom Fonts](/docs/native/getting-started/theming#custom-fonts).
### Truncation
Use the `truncate` boolean prop to limit the text to a single line with an ellipsis. It is mapped to React Native's `numberOfLines={1}`. An explicit `numberOfLines` prop, if provided, takes precedence.
```tsx
A long line of text that will be cut off with an ellipsis when it overflows
the container.
;
{
/* Multi-line truncation via the underlying RN prop */
}
Two-line truncation works through React Native's standard `numberOfLines`
prop.
;
```
## Example
```tsx
import { Typography } from 'heroui-native';
import { View } from 'react-native';
export default function TypographyExample() {
return (
Welcome
Getting Started
This is a body paragraph rendered with the Typography component.
Smaller supporting text for captions or footnotes.
npm install heroui-native
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/text.tsx).
## API Reference
### Typography
`Typography` extends all standard React Native `TextProps` with additional typography props.
| prop | type | default | description |
| -------------- | -------------------------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `type` | `'h1' \| 'h2' \| 'h3' \| 'h4' \| 'h5' \| 'h6' \| 'body' \| 'body-sm' \| 'body-xs' \| 'code'` | `'body'` | Semantic typography variant (size, default weight, line-height) |
| `align` | `'start' \| 'center' \| 'end' \| 'justify'` | `'start'` | Horizontal alignment. `start` and `end` are RTL-aware. `justify` is iOS-only. |
| `color` | `'default' \| 'muted'` | `'default'` | Semantic foreground color preset |
| `weight` | `'normal' \| 'medium' \| 'semibold' \| 'bold'` | - | Font weight override. When set, overrides the weight implied by `type`. |
| `truncate` | `boolean` | `false` | Truncates the text to a single line with an ellipsis (sets `numberOfLines={1}`). An explicit `numberOfLines` takes precedence. |
| `children` | `React.ReactNode` | - | Content to render |
| `className` | `string` | - | Additional CSS classes |
| `...TextProps` | `TextProps` | - | All standard React Native `Text` props are supported |
### Typography.Heading
Inherits all `Typography` root props (`align`, `color`, `weight`, `truncate`, `className`, and React Native `TextProps`). Sets `accessibilityRole="header"` automatically and narrows `type` to heading variants.
| prop | type | default | description |
| -------------- | ---------------------------------------------- | ------- | ---------------------------------------------------- |
| `type` | `'h1' \| 'h2' \| 'h3' \| 'h4' \| 'h5' \| 'h6'` | `'h1'` | Heading level |
| `children` | `React.ReactNode` | - | Content to render |
| `className` | `string` | - | Additional CSS classes |
| `...TextProps` | `TextProps` | - | All standard React Native `Text` props are supported |
### Typography.Paragraph
Inherits all `Typography` root props (`align`, `color`, `weight`, `truncate`, `className`, and React Native `TextProps`). Narrows `type` to body variants.
| prop | type | default | description |
| -------------- | ---------------------------------- | -------- | ---------------------------------------------------- |
| `type` | `'body' \| 'body-sm' \| 'body-xs'` | `'body'` | Paragraph text size |
| `children` | `React.ReactNode` | - | Content to render |
| `className` | `string` | - | Additional CSS classes |
| `...TextProps` | `TextProps` | - | All standard React Native `Text` props are supported |
### Typography.Code
Inherits all `Typography` root props (`align`, `color`, `weight`, `truncate`, `className`, `style`, and React Native `TextProps`). Thin wrapper that forces `type="code"`; the platform monospace `fontFamily` is merged in at the `Typography` root, so `` and `` render identically.
| prop | type | default | description |
| -------------- | ----------------- | ------- | ---------------------------------------------------- |
| `children` | `React.ReactNode` | - | Content to render |
| `className` | `string` | - | Additional CSS classes |
| `...TextProps` | `TextProps` | - | All standard React Native `Text` props are supported |
# PressableFeedback
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/pressable-feedback
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(utilities)/pressable-feedback.mdx
> Container component that provides visual feedback for press interactions with automatic scale animation.
## Import
```tsx
import { PressableFeedback } from 'heroui-native';
```
## Anatomy
```tsx
...
```
* **PressableFeedback**: Pressable container with built-in scale animation. Manages press state and container dimensions, providing them to child compound parts via context. Use `animation={false}` to disable the built-in scale when using `PressableFeedback.Scale` instead.
* **PressableFeedback.Scale**: Scale animation wrapper for applying scale to a specific child element. Use this instead of the root's built-in scale when you need control over which element scales or need to apply `className` / `style` to the scale wrapper.
* **PressableFeedback.Highlight**: Highlight overlay for iOS-style press feedback. Renders an absolute-positioned layer that fades in on press.
* **PressableFeedback.Ripple**: Ripple overlay for Android-style press feedback. Renders a radial gradient circle that expands from the touch point.
## Usage
### Basic
PressableFeedback provides press-down scale feedback out of the box. This is the recommended way to use it in most cases.
```tsx
...
```
### With Highlight
Add a highlight overlay for iOS-style feedback effect alongside the built-in scale.
```tsx
...
```
### With Ripple
Add a ripple overlay for Android-style feedback effect alongside the built-in scale.
```tsx
...
```
### Custom Scale Animation
Customize the built-in scale animation via the `animation.scale` prop. Accepts `value`, `timingConfig`, and `ignoreScaleCoefficient`.
```tsx
...
```
### Custom Highlight Animation
Configure highlight overlay opacity and background color.
```tsx
...
```
### Custom Ripple Animation
Configure ripple effect color, opacity, and duration.
```tsx
...
```
### Scale on a Specific Child (PressableFeedback.Scale)
When you need to apply the scale animation to a specific element inside the container rather than the root itself, disable the root's built-in scale with `animation={false}` and use the `PressableFeedback.Scale` compound part. This gives you full control over which element scales and lets you apply `className` / `style` directly to the scale wrapper.
```tsx
...
```
You can combine it with Highlight or Ripple inside the Scale wrapper:
```tsx
...
```
### Disable All Animations
Set `animation="disable-all"` on the root to cascade-disable all animations including the built-in scale and any child compound parts (Scale, Highlight, Ripple).
```tsx
...
```
You can also disable all animations while keeping a scale config (e.g. for toggling at runtime):
```tsx
...
```
## Example
```tsx
import { PressableFeedback, Card, Button } from 'heroui-native';
import { Image } from 'expo-image';
import { LinearGradient } from 'expo-linear-gradient';
import { StyleSheet, View, Text } from 'react-native';
export default function PressableFeedbackExample() {
return (
Neo
Home robot
Available soon
Get notified
Notify me
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/pressable-feedback.tsx).
## API Reference
### PressableFeedback
| prop | type | default | description |
| ----------------------- | -------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactNode` | - | Content to be wrapped with press feedback |
| `isDisabled` | `boolean` | `false` | Whether the pressable component is disabled |
| `className` | `string` | - | Additional CSS classes |
| `animation` | `PressableFeedbackRootAnimation` | - | Customize scale via `{ scale: ... }`, `false` to disable root scale, `'disable-all'` to cascade-disable all |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether the root's built-in animated styles are active |
| `asChild` | `boolean` | `false` | Whether to render as a child element |
| `...rest` | `AnimatedProps` | - | All Reanimated Animated Pressable props are supported |
#### PressableFeedbackRootAnimation
The root animation prop supports the standard `AnimationRoot` control flow:
* `true` or `undefined`: Use the default built-in scale animation
* `false` or `"disabled"`: Disable the root's built-in scale (use this when applying scale via `PressableFeedback.Scale` instead)
* `"disable-all"`: Cascade-disable all animations including the built-in scale and children (Scale, Highlight, Ripple)
* `object`: Custom configuration for the built-in scale
| prop | type | default | description |
| ------- | ---------------------------------------- | ------- | ------------------------------------------------------------------------------- |
| `scale` | `PressableFeedbackScaleAnimation` | - | Customize the built-in scale animation (value, timingConfig, etc.) |
| `state` | `'disabled' \| 'disable-all' \| boolean` | - | Control animation state while keeping configuration (e.g. for runtime toggling) |
### PressableFeedback.Scale
Use this compound part when you need to apply scale to a specific child element inside the container, instead of scaling the root itself. Set `animation={false}` on the root to disable its built-in scale when using this component.
| prop | type | default | description |
| ----------------------- | --------------------------------- | ------- | ------------------------------------------------------------ |
| `className` | `string` | - | Additional CSS classes |
| `animation` | `PressableFeedbackScaleAnimation` | - | Animation configuration for scale effect |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `style` | `ViewStyle` | - | Additional styles |
| `...AnimatedProps` | `AnimatedProps` | - | All Reanimated Animated View props are supported |
#### PressableFeedbackScaleAnimation
Animation configuration for scale effect. Can be:
* `false` or `"disabled"`: Disable scale animation
* `true` or `undefined`: Use default scale animation
* `object`: Custom scale configuration
| prop | type | default | description |
| ------------------------ | ----------------------- | ---------------------------------------------------- | -------------------------------------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `value` | `number` | `0.985` | Scale value when pressed (automatically adjusted based on container width) |
| `timingConfig` | `WithTimingConfig` | `{ duration: 300, easing: Easing.out(Easing.ease) }` | Animation timing configuration |
| `ignoreScaleCoefficient` | `boolean` | `false` | Ignore automatic scale coefficient and use the scale value directly |
### PressableFeedback.Highlight
| prop | type | default | description |
| ----------------------- | ------------------------------------- | ------- | ------------------------------------------------------------ |
| `className` | `string` | - | Additional CSS classes |
| `animation` | `PressableFeedbackHighlightAnimation` | - | Animation configuration for highlight overlay |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `style` | `ViewStyle` | - | Additional styles |
| `...AnimatedProps` | `AnimatedProps` | - | All Reanimated Animated View props are supported |
#### PressableFeedbackHighlightAnimation
Animation configuration for highlight overlay. Can be:
* `false` or `"disabled"`: Disable highlight animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ----------------------- | ----------------------- | ------------------- | ----------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `opacity.value` | `[number, number]` | `[0, 0.1]` | Opacity values \[unpressed, pressed] |
| `opacity.timingConfig` | `WithTimingConfig` | `{ duration: 200 }` | Animation timing configuration |
| `backgroundColor.value` | `string` | Theme-aware gray | Background color of highlight overlay |
### PressableFeedback.Ripple
| prop | type | default | description |
| ----------------------- | ----------------------------------------- | ------- | ------------------------------------------------------------ |
| `className` | `string` | - | Additional CSS classes for container slot |
| `classNames` | `ElementSlots` | - | Additional CSS classes for slots (container, ripple) |
| `styles` | `Partial>` | - | Styles for different parts of the ripple overlay |
| `animation` | `PressableFeedbackRippleAnimation` | - | Animation configuration for ripple overlay |
| `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active |
| `...ViewProps` | `Omit` | - | All View props except style are supported |
#### `styles`
| prop | type | description |
| ----------- | ----------- | ----------------------------- |
| `container` | `ViewStyle` | Styles for the container slot |
| `ripple` | `ViewStyle` | Styles for the ripple slot |
#### PressableFeedbackRippleAnimation
Animation configuration for ripple overlay. Can be:
* `false` or `"disabled"`: Disable ripple animations
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| ------------------------------------ | -------------------------- | ----------------------- | ---------------------------------------------------------------------------- |
| `state` | `'disabled' \| boolean` | - | Disable animations while customizing properties |
| `backgroundColor.value` | `string` | Computed based on theme | Background color of ripple effect |
| `progress.baseDuration` | `number` | `1000` | Base duration for ripple progress (automatically adjusted based on diagonal) |
| `progress.minBaseDuration` | `number` | `750` | Minimum base duration for the ripple progress animation |
| `progress.ignoreDurationCoefficient` | `boolean` | `false` | Ignore automatic duration coefficient and use base duration directly |
| `opacity.value` | `[number, number, number]` | `[0, 0.1, 0]` | Opacity values \[start, peak, end] for ripple animation |
| `opacity.timingConfig` | `WithTimingConfig` | `{ duration: 200 }` | Animation timing configuration |
| `scale.value` | `[number, number, number]` | `[0, 1, 1]` | Scale values \[start, peak, end] for ripple animation |
| `scale.timingConfig` | `WithTimingConfig` | `{ duration: 200 }` | Animation timing configuration |
#### `ElementSlots`
Additional CSS classes for ripple slots:
| slot | description |
| ----------- | ------------------------------------------------------------------------------------------------------------------- |
| `container` | Outer container slot (`absolute inset-0`) - styles can be fully customized |
| `ripple` | Inner ripple slot (`absolute top-0 left-0 rounded-full`) - has animated properties that cannot be set via className |
# ScrollShadow
**Category**: native
**URL**: https://heroui.com/en/docs/native/components/scroll-shadow
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/components/(utilities)/scroll-shadow.mdx
> Adds dynamic gradient shadows to scrollable content based on scroll position and overflow.
## Import
```tsx
import { ScrollShadow } from 'heroui-native';
```
## Anatomy
```tsx
...
```
* **ScrollShadow**: Main container that wraps scrollable components and adds dynamic gradient shadows at the edges based on scroll position and content overflow. Automatically detects scroll orientation (horizontal/vertical) and manages shadow visibility.
* **LinearGradientComponent**: Required prop that accepts a LinearGradient component from compatible libraries (expo-linear-gradient, react-native-linear-gradient, etc.) to render the gradient shadows.
## Usage
### Basic Usage
Wrap any scrollable component to automatically add edge shadows.
```tsx
...
```
### Horizontal Scrolling
The component auto-detects horizontal scrolling from the child's `horizontal` prop.
```tsx
```
### Custom Shadow Size
Control the gradient shadow height/width with the `size` prop.
```tsx
...
```
### Visibility Control
Specify which shadows to display using the `visibility` prop.
```tsx
...
...
...
```
### Custom Shadow Color
Override the default shadow color which uses the theme's background.
```tsx
...
```
### With Custom Scroll Handler
**Important:** ScrollShadow internally converts the child to a Reanimated animated component. If you need to use the `onScroll` prop, you must use `useAnimatedScrollHandler` from react-native-reanimated.
```tsx
import { LinearGradient } from 'expo-linear-gradient';
import Animated, { useAnimatedScrollHandler } from 'react-native-reanimated';
const scrollHandler = useAnimatedScrollHandler({
onScroll: (event) => {
console.log(event.contentOffset.y);
},
});
...
;
```
## Example
```tsx
import { ScrollShadow, Surface } from 'heroui-native';
import { LinearGradient } from 'expo-linear-gradient';
import { FlatList, ScrollView, Text, View } from 'react-native';
export default function ScrollShadowExample() {
const horizontalData = Array.from({ length: 10 }, (_, i) => ({
id: i,
title: `Card ${i + 1}`,
}));
return (
Horizontal List
(
{item.title}
)}
showsHorizontalScrollIndicator={false}
contentContainerClassName="p-5 gap-4"
/>
Vertical Content
Long Content
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
ad minim veniam, quis nostrud exercitation ullamco laboris.
Sed ut perspiciatis unde omnis iste natus error sit voluptatem
accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
quae ab illo inventore veritatis et quasi architecto beatae vitae.
);
}
```
You can find more examples in the [GitHub repository](https://github.com/heroui-inc/heroui-native/blob/main/example/src/app/\(home\)/components/scroll-shadow.tsx).
## API Reference
### ScrollShadow
| prop | type | default | description |
| ------------------------- | ---------------------------------------------------------------------- | ------------ | --------------------------------------------------------------------------------------------------------------- |
| `children` | `React.ReactElement` | - | The scrollable component to enhance with shadows. Must be a single React element (ScrollView, FlatList, etc.) |
| `LinearGradientComponent` | `ComponentType<` `LinearGradientProps>` | **required** | LinearGradient component from any compatible library (expo-linear-gradient, react-native-linear-gradient, etc.) |
| `size` | `number` | `50` | Size (height/width) of the gradient shadow in pixels |
| `orientation` | `'horizontal' \| 'vertical'` | auto-detect | Orientation of the scroll shadow. If not provided, will auto-detect from child's `horizontal` prop |
| `visibility` | `'auto' \| 'top' \| 'bottom' \| 'left' \| 'right' \| 'both' \| 'none'` | `'auto'` | Visibility mode for the shadows. 'auto' shows shadows based on scroll position and content overflow |
| `color` | `string` | theme color | Custom color for the gradient shadow. If not provided, uses the theme's background color |
| `isEnabled` | `boolean` | `true` | Whether the shadow effect is enabled |
| `animation` | `ScrollShadowRootAnimation` | - | Animation configuration |
| `className` | `string` | - | Additional CSS classes to apply to the container |
| `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported |
#### ScrollShadowRootAnimation
Animation configuration for ScrollShadow component. Can be:
* `false` or `"disabled"`: Disable only root animations
* `"disable-all"`: Disable all animations including children
* `true` or `undefined`: Use default animations
* `object`: Custom animation configuration
| prop | type | default | description |
| --------------- | ---------------------------------------- | -------- | ------------------------------------------------------------------------------------ |
| `state` | `'disabled' \| 'disable-all' \| boolean` | - | Disable animations while customizing properties |
| `opacity.value` | `[number, number]` | `[0, 1]` | `Opacity values [initial, active].` `For bottom/right shadow, this is reversed` |
### LinearGradientProps
The `LinearGradientComponent` prop expects a component that accepts these props:
| prop | type | description |
| ----------- | --------------------------------- | ------------------------------------------------------------------ |
| `colors` | `any` | Array of colors for the gradient |
| `locations` | `any` (optional) | Array of numbers defining the location of each gradient color stop |
| `start` | `any` (optional) | Start point of the gradient (e.g., `{ x: 0, y: 0 }`) |
| `end` | `any` (optional) | End point of the gradient (e.g., `{ x: 1, y: 0 }`) |
| `style` | `StyleProp` (optional) | Style to apply to the gradient view |
## Special Notes
**Important:** ScrollShadow internally converts the child to a Reanimated animated component. If you need to use the `onScroll` prop on your scrollable component, you must use `useAnimatedScrollHandler` from react-native-reanimated instead of the standard `onScroll` prop.
# Animation
**Category**: native
**URL**: https://heroui.com/en/docs/native/getting-started/animation
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/getting-started/(handbook)/animation.mdx
> Add smooth animations and transitions to HeroUI Native components
All animations in HeroUI Native are built with [react-native-reanimated](https://docs.swmansion.com/react-native-reanimated/) and gesture control is handled by [react-native-gesture-handler](https://docs.swmansion.com/react-native-gesture-handler/). It's worth familiarizing yourself with these libraries if you want more control over animations.
## The `animation` Prop
Every animated component in HeroUI Native exposes a single `animation` prop that controls all animations for that component. This prop allows you to modify animation values, timing configurations, layout animations, or completely disable animations.
**Approach**: If you're working with animations, first look for the `animation` prop on the component you're using.
## Modifying Animations
You can customize animations by passing an object to the `animation` prop. Each component exposes different animation properties that you can modify. The approach is simple: if you want to slightly change the animation behavior of already written animations in components, we provide all necessary values for modification. If you want to write your own animations without relying on our written ones, you must create your own custom components with animations.
### Example 1: Simple Value Modification
Modify animation values like scale, opacity, or colors:
```tsx
import {Switch} from 'heroui-native';
;
```
### Example 2: Timing Configuration
Customize animation timing and easing:
```tsx
import {Accordion} from 'heroui-native';
;
```
### Example 3: Layout Animations (Entering/Exiting)
Customize entering and exiting animations using Reanimated's layout animations:
```tsx
import {Accordion} from 'heroui-native';
import {FadeInRight, FadeInLeft, ZoomIn} from 'react-native-reanimated';
import {Easing} from 'react-native-reanimated';
Content here
;
```
### Example 4: State Prop for Granular Control
The `state` prop allows you to disable animations while still customizing animation properties. This is useful when you want to fine-tune component behavior without enabling animations:
```tsx
import {Switch} from 'heroui-native';
```
The `state` prop accepts:
* `'disabled'`: Disable animations while allowing property customization
* `'disable-all'`: Disable all animations including children (only available at root level)
* `boolean`: Simple enable/disable control (`true` enables, `false` disables)
This provides more granular control over animation behavior, allowing you to customize properties without enabling animations.
## Disabling Animations
You can disable animations at different levels using the `animation` prop.
### Disable Options
* `animation={false}` or `animation="disabled"`: Disable animations for the specific component only
* `animation="disable-all"`: Disable all animations including children (only available at root level)
* `animation={true}` or `animation={undefined}`: Use default animations
### Component-Level Disabling
Disable animations for a specific component:
```tsx
```
### Root-Level Disabling (`disable-all`)
The `"disable-all"` option is only available at the root level of compound components. When used, it disables all animations including children, even if those children are not part of the compound component structure:
```tsx
// Disables all animations including Button components inside Card
$450
Living room Sofa
Buy now
Add to cart
```
**Important**: `"disable-all"` cascades down to all child components, including standalone components like `Button`, `Spinner`, etc., not just compound component parts.
## Global Animation Configuration
You can disable all HeroUI Native animations globally using the `HeroUINativeProvider`:
```tsx
import {HeroUINativeProvider} from 'heroui-native';
;
```
This will disable all animations across your entire application, regardless of individual component `animation` prop settings.
## Accessibility
Reduce motion is handled automatically under the hood. When a user enables "Reduce Motion" in their device accessibility settings, all animations are automatically disabled globally. This is handled by the `GlobalAnimationSettingsProvider` which checks `useReducedMotion()` from react-native-reanimated.
You don't need to do anything - the library respects the user's accessibility preferences automatically.
## Animation State Management
We keep disabled state of animations under control internally to ensure they look nice without unpredictable lags or jumps. When animations are disabled, components immediately jump to their final state rather than animating, preventing visual glitches or intermediate states.
## Children Render Function
Many components support a render function pattern for children, which is particularly handy when working with state like `isSelected`:
```tsx
import {Switch} from 'heroui-native';
{({isSelected, isDisabled}) => (
{isSelected ? : }
)}
;
```
This pattern allows you to conditionally render content based on component state, making it easy to create dynamic UIs that respond to selection, disabled states, and other component properties.
## Next Steps
* Learn about [Styling](/docs/native/getting-started/styling) approaches
* View [Theming](/docs/native/getting-started/theming) documentation
* Explore [Colors](/docs/native/getting-started/colors) documentation
# Colors
**Category**: native
**URL**: https://heroui.com/en/docs/native/getting-started/colors
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/getting-started/(handbook)/colors.mdx
> Color palette and theming system for HeroUI Native
import {ColorSectionSideBySide, ColorSectionStacked, ColorSectionFormField, ColorSectionPrimitive} from "@/components/color-section";
HeroUI Native's color system is built around semantic intent, not visual abundance. Instead of exposing large raw palettes, the system defines a small, meaningful set of color roles that cover the majority of interface needs.
Most colors in the system are derived automatically from a limited number of base values. This allows HeroUI to maintain consistent contrast, hierarchy, and theming behavior while keeping the system easy to reason about and modify.
Colors should communicate purpose and state first. Visual variation comes from scale, emphasis, and context.
## Accent
The accent color represents the primary brand or product identity. It is used to draw attention to key actions, highlights, and moments of emphasis.
Accent should be used intentionally and sparingly. Overuse reduces its impact and can harm visual hierarchy. In most cases, components derive multiple accent-related values (hover, subtle backgrounds, focus states) automatically from the base accent color.
## Default (neutrals)
Default colors form the neutral backbone of the system. They are used for most non-emphasized UI elements.
## Success
Success colors communicate positive outcomes, confirmations, and completed states. They are typically used in feedback components, status indicators, and validation states.
## Warning
Warning colors indicate caution, risk, or actions that require attention but are not destructive. They are commonly used for alerts, messages, and transitional states where the user should pause or review information.
## Danger
Danger colors represent destructive, irreversible, or critical actions and states. They should be immediately recognizable and used consistently for errors, destructive buttons, and critical alerts.
## Foreground
Foreground colors are used for primary content such as text and icons. These colors are optimized for readability and accessibility and adapt automatically to background and surface contexts. Foreground colors should never be hard-coded at the component level.
## Background
Background colors define the base canvas of the interface. They establish overall contrast and mood while staying visually quiet.
## Surface
Surface colors sit on top of backgrounds and are used for containers such as cards, panels, modals, and dropdown. Surfaces help create visual separation and hierarchy through elevation, contrast, and layering rather than strong color shifts.
## Form field
Form field colors are specialized tokens used for inputs, controls, and interactive fields. They account for multiple states such as default, focus, and hover. Isolating them ensures form elements have a distinct visual language from buttons and the rest of the UI.
## Separator
Separator colors are used for dividers, outlines, and subtle boundaries. They exist to structure content and guide the eye without adding noise. Separator colors should remain low contrast and unobtrusive.
## Other
Other colors serve specific utility roles across the interface. They exist to structure content and guide the eye without adding noise.
## Primitive
Primitive colors are mode agnostic values used as foundations for semantic color tokens. They do not change between light and dark themes.
## How to Use Colors
**In your components:**
```tsx
import { View, Text } from 'react-native';
Content
Click me
;
```
**In CSS files:**
```css title="global.css"
/* Direct CSS variables */
.container {
flex: 1;
background-color: var(--accent);
width: 50px;
height: 50px;
border-radius: var(--radius);
}
```
## Default Theme
The complete theme definition can be found in ([variables.css](https://github.com/heroui-inc/heroui-native/blob/main/src/styles/variables.css)). This theme automatically switches between light and dark modes through [Uniwind's theming system](https://docs.uniwind.dev/theming/basics), which supports system preferences and programmatic theme switching.
```css
@theme {
/* Primitive Colors (Do not change between light and dark) */
--white: oklch(100% 0 0);
--black: oklch(0% 0 0);
--snow: oklch(0.9911 0 0);
--eclipse: oklch(0.2103 0.0059 285.89);
/* Border */
--border-width: 1px;
--field-border-width: 0px;
/* Base radius */
--radius: 0.5rem;
--field-radius: calc(var(--radius) * 1.5);
/* Opacity */
--opacity-disabled: 0.5;
}
@layer theme {
:root {
@variant light {
/* Base Colors */
--background: oklch(0.9702 0 0);
--foreground: var(--eclipse);
/* Surface */
--surface: var(--white);
--surface-foreground: var(--foreground);
--surface-secondary: oklch(0.9524 0.0013 286.37);
--surface-secondary-foreground: var(--foreground);
--surface-tertiary: oklch(0.9373 0.0013 286.37);
--surface-tertiary-foreground: var(--foreground);
/* Overlay */
--overlay: var(--white);
--overlay-foreground: var(--foreground);
--backdrop: oklch(0% 0 0 / 20%);
--muted: oklch(0.5517 0.0138 285.94);
--default: oklch(94% 0.001 286.375);
--default-foreground: var(--eclipse);
--accent: oklch(0.6204 0.195 253.83);
--accent-foreground: var(--snow);
/* Form Fields */
--field-background: var(--white);
--field-foreground: oklch(0.2103 0.0059 285.89);
--field-placeholder: var(--muted);
--field-border: transparent;
/* Status Colors */
--success: oklch(0.7329 0.1935 150.81);
--success-foreground: var(--eclipse);
--warning: oklch(0.7819 0.1585 72.33);
--warning-foreground: var(--eclipse);
--danger: oklch(0.6532 0.2328 25.74);
--danger-foreground: var(--snow);
/* Component Colors */
--segment: var(--white);
--segment-foreground: var(--eclipse);
/* Misc Colors */
--border: oklch(90% 0.004 286.32);
--separator: oklch(74% 0.004 286.32);
--focus: var(--accent);
--link: var(--foreground);
}
@variant dark {
/* Base Colors */
--background: oklch(12% 0.005 285.823);
--foreground: var(--snow);
/* Surface */
--surface: oklch(0.2103 0.0059 285.89);
--surface-foreground: var(--foreground);
--surface-secondary: oklch(0.257 0.0037 286.14);
--surface-secondary-foreground: var(--foreground);
--surface-tertiary: oklch(0.2721 0.0024 247.91);
--surface-tertiary-foreground: var(--foreground);
/* Overlay */
--overlay: oklch(0.2103 0.0059 285.89);
--overlay-foreground: var(--foreground);
--backdrop: oklch(0% 0 0 / 20%);
--muted: oklch(70.5% 0.015 286.067);
--default: oklch(27.4% 0.006 286.033);
--default-foreground: var(--snow);
--accent: oklch(0.6204 0.195 253.83);
--accent-foreground: var(--snow);
/* Form Fields */
--field-background: oklch(0.2103 0.0059 285.89);
--field-foreground: var(--foreground);
--field-placeholder: var(--muted);
--field-border: transparent;
/* Status Colors */
--success: oklch(0.7329 0.1935 150.81);
--success-foreground: var(--eclipse);
--warning: oklch(0.8203 0.1388 76.34);
--warning-foreground: var(--eclipse);
--danger: oklch(0.594 0.1967 24.63);
--danger-foreground: var(--snow);
/* Component Colors */
--segment: oklch(0.3964 0.01 285.93);
--segment-foreground: var(--foreground);
/* Misc Colors */
--border: oklch(28% 0.006 286.033);
--separator: oklch(40% 0.006 286.033);
--focus: var(--accent);
--link: var(--foreground);
}
}
}
```
## Customizing Colors
**Override existing colors:**
```css
@layer theme {
@variant light {
/* Override default colors */
--accent: oklch(0.65 0.25 270); /* Custom indigo accent */
--success: oklch(0.65 0.15 155);
}
@variant dark {
/* Override dark theme colors */
--accent: oklch(0.65 0.25 270);
--success: oklch(0.75 0.12 155);
}
}
```
**Tip:** Convert colors at [oklch.com](https://oklch.com)
**Add your own colors:**
```css
@layer theme {
@variant light {
--info: oklch(0.6 0.15 210);
--info-foreground: oklch(0.98 0 0);
}
@variant dark {
--info: oklch(0.7 0.12 210);
--info-foreground: oklch(0.15 0 0);
}
}
@theme inline {
--color-info: var(--info);
--color-info-foreground: var(--info-foreground);
}
```
Now you can use it:
```tsx
import { View, Text } from 'react-native';
Info message
;
```
> **Note**: To learn more about theme variables and how they work in Tailwind CSS v4, see the [Tailwind CSS Theme documentation](https://tailwindcss.com/docs/theme).
## useThemeColor Hook
The `useThemeColor` hook has been enhanced to support multiple colors selection, making it more flexible for complex theming scenarios.
**Multiple Colors Selection:**
You can now select multiple colors at once, which is useful when you need to work with related color values together:
```tsx
import { useThemeColor } from 'heroui-native';
// Select multiple colors at once
const [accent, accentForeground, success, danger] = useThemeColor([
'accent',
'accentForeground',
'success',
'danger',
]);
// Use the selected colors
Accent Text
;
```
This enhancement improves performance when working with multiple color values and makes it easier to manage complex theming scenarios where multiple colors need to be selected and applied together.
# Composition
**Category**: native
**URL**: https://heroui.com/en/docs/native/getting-started/composition
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/getting-started/(handbook)/composition.mdx
> Build flexible UI with component composition patterns
HeroUI Native uses composition patterns to create flexible, customizable components. Change the rendered element, compose components together, and maintain full control over markup.
## Compound Components
HeroUI Native components use a compound component pattern with dot notation—components export sub-components as properties (e.g., `Button.Label`, `Dialog.Trigger`, `Accordion.Item`) that work together to form complete UI elements.
```tsx
import { Button, Dialog } from 'heroui-native';
function DialogExample() {
return (
Open Dialog
Dialog Title
Dialog description
);
}
```
## The asChild Prop
The `asChild` prop lets you change what element a component renders. When `asChild` is true, HeroUI Native clones the child element and merges props instead of rendering its default element.
```tsx
import { Button, Dialog } from 'heroui-native';
function DialogExample() {
return (
{/* With asChild: Button becomes the trigger directly, no wrapper element */}
Open Dialog
{/* Dialog.Close can also use asChild */}
Cancel
Dialog Title
Dialog description
);
}
```
## Custom Components
Create your own components by composing HeroUI Native primitives:
```tsx
import { Button, Card, Popover } from 'heroui-native';
import { View } from 'react-native';
// Product card component
function ProductCard({ title, description, price, onBuy, ...props }) {
return (
{price}
{title}
{description}
Buy now
);
}
// Popover button component
function PopoverButton({ children, popoverContent, ...props }) {
return (
{children}
{popoverContent}
);
}
// Usage
console.log('Buy')}
/>
Information
Additional details here
}>
Show Info
```
## Custom Variants
Create custom variants using `tailwind-variants` to extend component styling. Note that text color classes must be applied to `Button.Label`, not the parent `Button`:
```tsx
import { Button } from 'heroui-native';
import type { ButtonRootProps } from 'heroui-native';
import { tv, type VariantProps } from 'tailwind-variants';
const customButtonVariants = tv({
base: 'font-semibold rounded-lg',
variants: {
intent: {
primary: 'bg-blue-500',
secondary: 'bg-gray-200',
danger: 'bg-red-500',
},
},
defaultVariants: {
intent: 'primary',
},
});
const customLabelVariants = tv({
base: '',
variants: {
intent: {
primary: 'text-white',
secondary: 'text-gray-800',
danger: 'text-white',
},
},
defaultVariants: {
intent: 'primary',
},
});
type CustomButtonVariants = VariantProps;
interface CustomButtonProps
extends Omit,
CustomButtonVariants {
className?: string;
labelClassName?: string;
}
export function CustomButton({
intent,
className,
labelClassName,
children,
...props
}: CustomButtonProps) {
return (
{children}
);
}
```
## Next Steps
* Learn about [Styling](/docs/native/getting-started/styling) system
* Explore [Theming](/docs/native/getting-started/theming) documentation
* Explore [Animation](/docs/native/getting-started/animation) options
# Portal
**Category**: native
**URL**: https://heroui.com/en/docs/native/getting-started/portal
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/getting-started/(handbook)/portal.mdx
Portals let you render its children into a different part of your app. This is particularly useful for components that need to render above other content, such as modals, overlays, and popups.
## Default Setup
By default, the `PortalHost` is included in the `HeroUINativeProvider`, so there is no need to add it manually. The provider automatically sets up the portal system for all components that use portals.
## Advanced Use Cases
For advanced use cases, you can import `Portal` and `PortalHost` directly from `heroui-native` to create custom portal implementations:
```tsx
import { Portal, PortalHost } from "heroui-native";
import { View, Text } from "react-native";
function AppLayout() {
return (
Header Content
Main Content Area
{/* Portal host positioned at the top of the screen */}
);
}
function CustomNotification() {
return (
This notification appears at the top via Portal
);
}
```
In this example, the `CustomNotification` component uses a `Portal` to render its content at the location of the `PortalHost`, which is positioned at the top of the screen. This allows the notification to appear above all other content regardless of where it's defined in the component tree.
## State Management Considerations
State changes in parent components can cause unexpected issues with components rendered inside portals. For example, when a text input is placed directly inside a portal and the parent component re-renders, it can reset the input's auto-suggestions or cause other UI disruptions.
To avoid this, keep the state of interactive components (like text inputs) inside the portal by creating a separate component for the portal content. This isolates the state from parent re-renders.
### Example Pattern
```tsx
// ❌ Problematic: State in parent causes re-renders that affect portal content
function ParentComponent() {
const [dialogOpen, setDialogOpen] = useState(false);
const [inputValue, setInputValue] = useState(""); // State in parent
return (
Open Dialog
);
}
// ✅ Correct: State managed inside separate component within portal
function ParentComponent() {
const [dialogOpen, setDialogOpen] = useState(false);
return (
Open Dialog
setDialogOpen(false)}
// Form state isolated from parent
/>
);
}
function DialogFormContent({ onClose }: { onClose: () => void }) {
const [inputValue, setInputValue] = useState(""); // State inside portal
const [error, setError] = useState("");
return (
{error}
Close
);
}
```
In the correct pattern, the `DialogFormContent` component manages its own state independently of the parent component. This ensures that parent re-renders (such as when `dialogOpen` changes) don't affect the input's internal state, preserving auto-suggestions and other input behaviors.
## API Reference
### PortalHost
By default, children of all Portal components will be rendered as its own children.
| Prop | Type | Note |
| ---- | -------- | --------------------------------------------------- |
| name | `string` | Provide when it is used as a custom host (optional) |
### Portal
| Prop | Type | Note |
| -------- | ----------------- | ------------------------------------------------------------------------------------- |
| name\* | `string` | Unique value otherwise the portal with the same name will replace the original portal |
| hostName | `string` | Provide when its children are to be rendered in a custom host (optional) |
| children | `React.ReactNode` | The content to render in the portal |
\* Required prop
## Related
* [Quick Start](/docs/native/getting-started/quick-start) - Basic setup guide
* View [Provider](/docs/native/getting-started/provider) documentation
# Provider
**Category**: native
**URL**: https://heroui.com/en/docs/native/getting-started/provider
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/getting-started/(handbook)/provider.mdx
> Configure HeroUI Native provider with text, text input, animation, toast, and layout direction settings
The `HeroUINativeProvider` is the root provider component that configures and initializes HeroUI Native in your React Native application. It provides global configuration and portal management for your application.
## Overview
The provider serves as the main entry point for HeroUI Native, wrapping your application with essential contexts and configurations:
* **Safe Area Insets**: Automatically handles safe area insets updates via `SafeAreaListener` and syncs them with Uniwind for use in Tailwind classes (e.g., `pb-safe-offset-3`)
* **Text Configuration**: Global text component settings for consistency across all HeroUI components
* **Text Input Configuration**: Global text input settings for consistency across all HeroUI input components
* **Animation Configuration**: Global animation control to disable all animations across the application
* **Toast Configuration**: Global toast system configuration including insets, default props, and wrapper components
* **Layout Direction**: Global right-to-left flag used by component logic that runs in JavaScript instead of styles
* **Portal Management**: Handles overlays, modals, and other components that render on top of the app hierarchy
## Basic Setup
Wrap your application root with the provider:
```tsx
import { HeroUINativeProvider } from 'heroui-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
export default function App() {
return (
{/* Your app content */}
);
}
```
## Configuration Options
The provider accepts a `config` prop with the following options:
### Text Component Configuration
Global settings for all Text components within HeroUI Native. These props are carefully selected to include only those that make sense to configure globally across all Text components in the application:
```tsx
import { HeroUINativeProvider } from 'heroui-native';
import type { HeroUINativeConfig } from 'heroui-native';
const config: HeroUINativeConfig = {
textProps: {
// Disable font scaling for accessibility
allowFontScaling: false,
// Auto-adjust font size to fit container
adjustsFontSizeToFit: false,
// Maximum font size multiplier when scaling
maxFontSizeMultiplier: 1.5,
// Minimum font scale (iOS only, 0.01-1.0)
minimumFontScale: 0.5,
},
};
export default function App() {
return (
{/* Your app content */}
);
}
```
### Text Input Component Configuration
Global settings for all TextInput-based components within HeroUI Native (e.g. Input, TextArea, SearchField, InputGroup, InputOTP). These props are carefully selected to include only those that make sense to configure globally across all inputs in the application:
```tsx
import { HeroUINativeProvider } from 'heroui-native';
import type { HeroUINativeConfig } from 'heroui-native';
const config: HeroUINativeConfig = {
textInputProps: {
// Respect Text Size accessibility settings
allowFontScaling: false,
// Maximum font size multiplier when allowFontScaling is enabled
maxFontSizeMultiplier: 1.5,
},
};
export default function App() {
return (
{/* Your app content */}
);
}
```
**Note**: These props are applied as defaults. Any prop passed directly to an individual input component overrides the corresponding global value.
### Animation Configuration
Global animation configuration for the entire application:
```tsx
const config: HeroUINativeConfig = {
// Disable all animations across the application (cascades to all children)
animation: 'disable-all',
};
```
**Note**: When set to `'disable-all'`, all animations across the application will be disabled. This is useful for accessibility or performance optimization.
### Developer Information Configuration
Control developer-facing informational messages displayed in the console:
```tsx
const config: HeroUINativeConfig = {
devInfo: {
// Disable styling principles information message
stylingPrinciples: false,
},
};
```
**Note**: By default, informational messages are enabled. Set `stylingPrinciples: false` to disable the styling principles message that appears in the console during development.
### Toast Configuration
Configure the global toast system including insets, default props, and wrapper components. You can also disable the toast provider entirely:
**Option 1: Disable Toast Provider**
```tsx
const config: HeroUINativeConfig = {
// Disable toast provider entirely
toast: false,
// or
toast: 'disabled',
};
```
**Note**: When toast is disabled (`false` or `'disabled'`), the `ToastProvider` will not be rendered, and toast functionality will not be available in your application.
**Option 2: Configure Toast Provider**
```tsx
import { KeyboardAvoidingView } from 'react-native';
const config: HeroUINativeConfig = {
toast: {
// Global toast configuration (used as defaults for all toasts)
defaultProps: {
variant: 'default',
placement: 'top',
isSwipeable: true,
animation: true,
},
// Insets for spacing from screen edges (added to safe area insets)
insets: {
top: 0, // Default: iOS = 0, Android = 12
bottom: 6, // Default: iOS = 6, Android = 12
left: 12, // Default: 12
right: 12, // Default: 12
},
// Maximum number of visible toasts before opacity starts fading
maxVisibleToasts: 3,
// Custom wrapper function to wrap the toast content
contentWrapper: (children) => (
{children}
),
},
};
```
### Layout Direction Configuration
Tell HeroUI Native components which layout direction they render in:
```tsx
import { I18nManager } from 'react-native';
const config: HeroUINativeConfig = {
isRTL: I18nManager.isRTL,
};
```
Components mirror themselves with Yoga logical properties (`start`/`end`), so most of the UI flips on its own. This flag only covers logic that runs in JavaScript, such as `Slider` gesture deltas and popover `start`/`end` alignment.
**Note**: `isRTL` defaults to `I18nManager.isRTL`. Set it only when your app renders in a direction that differs from the global RTL state.
To override the direction for a subtree, wrap it with `LayoutDirectionScope`, together with Uniwind's `LayoutDirection` for the `rtl:` variants and a `direction` style for Yoga layout:
```tsx
{children}
```
**Note**: Portalled content renders at the app root and escapes the scope, so render a `PortalHost` with a custom `name` inside it and pass the matching `hostName` to the overlay. In your own components, read the effective direction with the `useIsRTL` hook.
## Complete Example
Here's a comprehensive example showing all configuration options:
```tsx
import { HeroUINativeProvider } from 'heroui-native';
import type { HeroUINativeConfig } from 'heroui-native';
import { I18nManager } from 'react-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
const config: HeroUINativeConfig = {
// Global text configuration
textProps: {
minimumFontScale: 0.5,
maxFontSizeMultiplier: 1.5,
allowFontScaling: true,
adjustsFontSizeToFit: false,
},
// Global text input configuration
textInputProps: {
allowFontScaling: true,
maxFontSizeMultiplier: 1.5,
},
// Global animation configuration
animation: 'disable-all', // Optional: disable all animations
// Developer information messages configuration
devInfo: {
stylingPrinciples: true, // Optional: disable styling principles message
},
// Global layout direction (defaults to I18nManager.isRTL)
isRTL: I18nManager.isRTL,
// Global toast configuration
// Option 1: Configure toast with custom settings
toast: {
defaultProps: {
variant: 'default',
placement: 'top',
},
insets: {
top: 0,
bottom: 6,
left: 12,
right: 12,
},
maxVisibleToasts: 3,
},
// Option 2: Disable toast entirely
// toast: false,
// or
// toast: 'disabled',
};
export default function App() {
return (
);
}
```
## Integration with Expo Router
When using Expo Router, wrap your root layout:
```tsx
// app/_layout.tsx
import { HeroUINativeProvider } from 'heroui-native';
import type { HeroUINativeConfig } from 'heroui-native';
import { Stack } from 'expo-router';
const config: HeroUINativeConfig = {
textProps: {
minimumFontScale: 0.5,
maxFontSizeMultiplier: 1.5,
},
};
export default function RootLayout() {
return (
);
}
```
## Architecture
### Provider Hierarchy
The `HeroUINativeProvider` internally composes multiple providers:
```
HeroUINativeProvider
├── SafeAreaListener (handles safe area insets updates)
│ └── LayoutDirectionProvider (layout direction configuration)
│ └── GlobalAnimationSettingsProvider (animation configuration)
│ └── TextComponentProvider (text configuration)
│ └── TextInputComponentProvider (text input configuration)
│ └── ToastProvider (toast configuration, conditionally rendered)
│ └── Your App
│ └── PortalHost (for overlays)
```
**Note**: The `ToastProvider` is conditionally rendered based on the `toast` configuration. If `toast` is set to `false` or `'disabled'`, the `ToastProvider` will not be rendered, and the app content and `PortalHost` will be rendered directly under `TextInputComponentProvider`.
### Safe Area Insets Handling
The provider automatically wraps your application with [`SafeAreaListener`](https://appandflow.github.io/react-native-safe-area-context/api/safe-area-listener) from `react-native-safe-area-context`. This component listens to safe area insets and frame changes without triggering re-renders, and automatically updates Uniwind with the latest insets via the `onChange` callback.
## Raw Provider
`HeroUINativeProviderRaw` is a lightweight variant of `HeroUINativeProvider` designed for bundle optimization. It excludes `ToastProvider` and `PortalHost`, giving you a bare minimum starting point where you only install and add what you actually need. Its `HeroUINativeConfigRaw` config accepts the same options as `HeroUINativeConfig` except `toast`, so `textProps`, `textInputProps`, `animation`, `devInfo`, and `isRTL` all behave identically.
### When to Use
Use `HeroUINativeProviderRaw` when you want full control over which dependencies are included in your bundle. With the raw provider imported from `heroui-native/provider-raw`, the following dependencies are optional and only required if you use the corresponding components:
* **react-native-screens** -- required for overlay components (Popover, Dialog)
* **@gorhom/bottom-sheet** -- required for BottomSheet component
* **react-native-svg** -- required for components that use icons (Accordion, Alert, Checkbox, etc.)
### Setup
```tsx
import {
HeroUINativeProviderRaw,
type HeroUINativeConfigRaw,
} from 'heroui-native/provider-raw';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
const config: HeroUINativeConfigRaw = {
textProps: {
maxFontSizeMultiplier: 1.5,
},
};
export default function App() {
return (
{/* Your app content */}
);
}
```
### Adding Toast and Portal Manually
If you need toast or portal functionality with the raw provider, add them yourself:
```tsx
import { HeroUINativeProviderRaw } from 'heroui-native/provider-raw';
import { PortalHost } from 'heroui-native/portal';
import { ToastProvider } from 'heroui-native/toast';
export default function App() {
return (
{/* Your app content */}
);
}
```
### Provider Hierarchy
```
HeroUINativeProviderRaw
├── SafeAreaListener (handles safe area insets updates)
│ └── LayoutDirectionProvider (layout direction configuration)
│ └── GlobalAnimationSettingsProvider (animation configuration)
│ └── TextComponentProvider (text configuration)
│ └── TextInputComponentProvider (text input configuration)
│ └── Your App
```
## Best Practices
### 1. Single Provider Instance
Always use a single `HeroUINativeProvider` at the root of your app. Don't nest multiple providers:
```tsx
// ❌ Bad
{/* Don't do this */}
// ✅ Good
```
### 2. Configuration Object
Define your configuration outside the component to prevent recreating on each render:
```tsx
// ❌ Bad
function App() {
return (
{/* ... */}
);
}
// ✅ Good
const config: HeroUINativeConfig = {
textProps: {
maxFontSizeMultiplier: 1.5,
},
};
function App() {
return (
{/* ... */}
);
}
```
### 3. Text Configuration
Consider accessibility when configuring text props:
```tsx
const config: HeroUINativeConfig = {
textProps: {
// Allow font scaling for accessibility
allowFontScaling: true,
// But limit maximum scale
maxFontSizeMultiplier: 1.5,
},
};
```
## TypeScript Support
The provider is fully typed. Import types for better IDE support:
```tsx
import { HeroUINativeProvider, type HeroUINativeConfig } from 'heroui-native';
const config: HeroUINativeConfig = {
// Full type safety and autocomplete
textProps: {
allowFontScaling: true,
maxFontSizeMultiplier: 1.5,
},
textInputProps: {
allowFontScaling: true,
maxFontSizeMultiplier: 1.5,
},
animation: 'disable-all', // Optional: disable all animations
devInfo: {
stylingPrinciples: true, // Optional: disable styling principles message
},
isRTL: false, // Optional: layout direction, defaults to I18nManager.isRTL
// Toast configuration options:
// - false or 'disabled': Disable toast provider
// - ToastProviderProps object: Configure toast settings
toast: {
defaultProps: {
variant: 'default',
placement: 'top',
},
insets: {
top: 0,
bottom: 6,
left: 12,
right: 12,
},
},
};
```
## Related
* [Quick Start](/docs/native/getting-started/quick-start) - Basic setup guide
* [Theming](/docs/native/getting-started/theming) - Customize colors and themes
* [Styling](/docs/native/getting-started/styling) - Style components with Tailwind
# Styling
**Category**: native
**URL**: https://heroui.com/en/docs/native/getting-started/styling
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/getting-started/(handbook)/styling.mdx
> Style HeroUI Native components with Tailwind or StyleSheet API
HeroUI Native components provide flexible styling options: Tailwind CSS utilities, StyleSheet API, and render props for dynamic styling.
## Styling Principles
HeroUI Native is built with `className` as the go-to styling solution. You can use Tailwind CSS classes via the `className` prop on all components.
**StyleSheet precedence:** The `style` prop (StyleSheet API) can be used and has precedence over `className` when both are provided. This allows you to override Tailwind classes when needed.
**Animated styles:** Some style properties are animated using `react-native-reanimated` and, like StyleSheet styles, they have precedence over `className`. To identify which styles are animated and cannot be used via `className`:
* **Hover over `className` in your IDE** - The TypeScript definitions will show which properties are available
* **Check component documentation** - Each component page includes a link to the component's style source at the top, which contains notes about animated properties
**Customizing animated styles:** If styles are occupied by animation, you can modify them via the `animation` prop on components that support it.
## Basic Styling
**Using className:** All HeroUI Native components accept `className` props:
```tsx
import { Button } from 'heroui-native';
Custom Button
;
```
**Using style:** Components also accept inline styles via the `style` prop:
```tsx
import { Button } from 'heroui-native';
Styled Button
;
```
## Render Props
Use a render function to access component state and customize content dynamically:
```tsx
import { RadioGroup, Label, cn } from 'heroui-native';
{({ isSelected, isInvalid, isDisabled }) => (
<>
Option 1
{isSelected && }
>
)}
;
```
## Creating Wrapper Components
Create reusable custom components using [tailwind-variants](https://tailwind-variants.org/)—a Tailwind CSS first-class variant API:
```tsx
import { Button } from 'heroui-native';
import type { ButtonRootProps } from 'heroui-native';
import { tv, type VariantProps } from 'tailwind-variants';
const customButtonVariants = tv({
base: 'font-semibold rounded-lg',
variants: {
intent: {
primary: 'bg-blue-500',
secondary: 'bg-gray-200',
danger: 'bg-red-500',
},
},
defaultVariants: {
intent: 'primary',
},
});
const customLabelVariants = tv({
base: '',
variants: {
intent: {
primary: 'text-white',
secondary: 'text-gray-800',
danger: 'text-white',
},
},
defaultVariants: {
intent: 'primary',
},
});
type CustomButtonVariants = VariantProps;
interface CustomButtonProps
extends Omit,
CustomButtonVariants {
className?: string;
labelClassName?: string;
}
export function CustomButton({
intent,
className,
labelClassName,
children,
...props
}: CustomButtonProps) {
return (
{children}
);
}
```
## Using Component classNames
Each HeroUI Native component exports a `classNames` object that contains the same styling functions used internally by the component. This is particularly useful when you want to style your own custom components to match the appearance of HeroUI Native components.
For example, you can style a custom `Link` component to look like a `Button`:
```tsx
import { buttonClassNames, cn } from 'heroui-native';
import { Pressable, Text } from 'react-native';
interface LinkProps {
href: string;
variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
size?: 'sm' | 'md' | 'lg';
children: React.ReactNode;
className?: string;
}
export function Link({
href,
variant = 'primary',
size = 'md',
children,
className,
}: LinkProps) {
return (
{
// Handle navigation
}}
>
{children}
);
}
```
**Available classNames exports:**
Each component exports its `classNames` object. For example:
* `buttonClassNames` - Contains `root` and `label` functions
* `cardClassNames` - Contains `root`, `header`, `body`, `footer`, `label`, and `description` functions
* `chipClassNames` - Contains `root` and `label` functions
* And many more...
**Usage pattern:**
```tsx
import { buttonClassNames } from 'heroui-native';
// Use with variant and size options
const rootClasses = buttonClassNames.root({
variant: 'primary',
size: 'md',
className: 'custom-class', // Optional: merge with your own classes
});
const labelClasses = buttonClassNames.label({
variant: 'primary',
size: 'md',
});
```
The `classNames` functions accept the same variant props as the components themselves, allowing you to maintain visual consistency across your custom components and HeroUI Native components.
## Responsive Design
HeroUI Native supports Tailwind's responsive breakpoint system via [Uniwind](https://docs.uniwind.dev/breakpoints). Use breakpoint prefixes like `sm:`, `md:`, `lg:`, and `xl:` to apply styles conditionally based on screen width.
**Mobile-first approach:** Start with mobile styles (no prefix), then use breakpoints to enhance for larger screens.
### Responsive Typography and Spacing
```tsx
import { Button } from 'heroui-native';
import { View, Text } from 'react-native';
Responsive Heading
Responsive Button
;
```
### Responsive Layouts
```tsx
import { View, Text } from 'react-native';
{/* Mobile: 1 column, Tablet: 2 columns, Desktop: 3 columns */}
Item 1
;
```
**Default breakpoints:**
* `sm`: 640px
* `md`: 768px
* `lg`: 1024px
* `xl`: 1280px
* `2xl`: 1536px
For custom breakpoints and more details, see the [Uniwind breakpoints documentation](https://docs.uniwind.dev/breakpoints).
## Utilities
HeroUI Native provides utility functions to assist with styling components.
### cn Utility
The `cn` utility function merges Tailwind CSS classes with proper conflict resolution. It's particularly useful when combining conditional classes or merging classes from props:
````tsx
import { cn } from 'heroui-native';
import { View } from 'react-native';
function MyComponent({ className, isActive }) {
return (
);
}
```;
The `cn` utility is powered by `tailwind-variants` and includes:
- Automatic Tailwind class merging (`twMerge: true`)
- Custom opacity class group support
- Proper conflict resolution (later classes override earlier ones)
**Example with conflicts:**
```tsx
// 'bg-accent' overrides 'bg-background'
cn('bg-background p-4', 'bg-accent');
// Result: 'p-4 bg-accent'
````
### useThemeColor Hook
Retrieves theme color values from CSS variables. Supports both single color and multiple colors for efficient batch retrieval.
**Single color usage:**
````tsx
import { useThemeColor } from 'heroui-native';
function MyComponent() {
const accentColor = useThemeColor('accent');
const dangerColor = useThemeColor('danger');
return (
Error message
);
}
```;
**Multiple colors usage (more efficient):**
```tsx
import { useThemeColor } from 'heroui-native';
function MyComponent() {
const [accentColor, backgroundColor, dangerColor] = useThemeColor([
'accent',
'background',
'danger',
]);
return (
Error message
);
}
```;
**Type signatures:**
```tsx
// Single color
useThemeColor(themeColor: ThemeColor): string
// Multiple colors (with type inference for tuples)
useThemeColor(
themeColor: T
): CreateStringTuple
// Multiple colors (array)
useThemeColor(themeColor: ThemeColor[]): string[]
````
Available theme colors include: `background`, `foreground`, `surface`, `accent`, `default`, `success`, `warning`, `danger`, and all their variants (hover, soft, foreground, etc.), plus semantic colors like `muted`, `border`, `separator`, `field`, `overlay`, and more.
## Next Steps
* Learn about [Animation](/docs/native/getting-started/animation) techniques
* Explore [Theming](/docs/native/getting-started/theming) system
* Explore [Colors](/docs/native/getting-started/colors) documentation
# Theming
**Category**: native
**URL**: https://heroui.com/en/docs/native/getting-started/theming
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/getting-started/(handbook)/theming.mdx
> Customize HeroUI Native's design system with CSS variables and global styles
HeroUI Native uses CSS variables for theming. Customize everything from colors to component styles using standard CSS.
## How It Works
HeroUI Native's theming system is built on top of [Tailwind CSS v4](https://tailwindcss.com/docs/theme)'s theme via [Uniwind](https://uniwind.dev/). When you import `heroui-native/styles`, it uses Tailwind's built-in color palettes, maps them to semantic variables, automatically switches between light and dark themes, and uses CSS layers and the `@theme` directive for organization.
**Naming pattern:**
* Colors without a suffix are backgrounds (e.g., `--accent`)
* Colors with `-foreground` are for text on that background (e.g., `--accent-foreground`)
## Quick Start
**Apply colors in your components:**
```tsx
import { View, Text } from 'react-native';
Your app content
;
```
**Switch themes:**
HeroUI Native automatically supports dark mode through [Uniwind](https://docs.uniwind.dev/theming/basics). The theme switches between light and dark variants based on system preferences or manual selection:
```tsx
import { Uniwind, useUniwind } from 'uniwind';
import { Button } from 'heroui-native';
function ThemeToggle() {
const { theme } = useUniwind();
return (
Uniwind.setTheme(theme === 'light' ? 'dark' : 'light')}
>
Toggle {theme === 'light' ? 'Dark' : 'Light'} Mode
);
}
```
**Override colors:**
```css
/* global.css */
@layer theme {
@variant light {
/* Override any color variable */
--accent: oklch(0.65 0.25 270); /* Custom indigo accent */
--success: oklch(0.65 0.15 155);
}
@variant dark {
--accent: oklch(0.65 0.25 270);
--success: oklch(0.75 0.12 155);
}
}
```
> **Note**: See [Colors](/docs/native/getting-started/colors) for the complete color palette and visual reference.
**Create your own theme:**
Create multiple themes using Uniwind's variant system. For complete custom theme documentation, see the [Uniwind Custom Themes Guide](https://docs.uniwind.dev/theming/custom-themes).
**Important:** All themes must define the same variables. See the [Default Theme](/docs/native/getting-started/colors#default-theme) section for a complete list of all required variables.
```css
/* global.css */
@layer theme {
:root {
@variant ocean-light {
/* Base Colors */
--background: oklch(0.95 0.02 230);
--foreground: oklch(0.25 0.04 230);
/* Surface: Used for non-overlay components (cards, accordions, disclosure groups) */
--surface: oklch(0.98 0.01 230);
--surface-foreground: oklch(0.3 0.045 230);
--surface-secondary: oklch(0.96 0.012 230);
--surface-secondary-foreground: oklch(0.3 0.045 230);
--surface-tertiary: oklch(0.94 0.015 230);
--surface-tertiary-foreground: oklch(0.3 0.045 230);
/* Overlay: Used for floating/overlay components (dialogs, popovers, modals, menus) */
--overlay: oklch(0.998 0.003 230);
--overlay-foreground: oklch(0.3 0.045 230);
--backdrop: oklch(0% 0 0 / 20%);
--muted: oklch(0.55 0.035 230);
--default: oklch(0.94 0.018 230);
--default-foreground: oklch(0.4 0.05 230);
/* Accent */
--accent: oklch(0.6 0.2 230);
--accent-foreground: oklch(0.98 0.005 230);
/* Form Field Defaults - Colors */
--field-background: oklch(0.98 0.01 230);
--field-foreground: oklch(0.25 0.04 230);
--field-placeholder: var(--muted);
--field-border: transparent;
/* Status Colors */
--success: oklch(0.72 0.14 165);
--success-foreground: oklch(0.25 0.08 165);
--warning: oklch(0.78 0.12 85);
--warning-foreground: oklch(0.3 0.08 85);
--danger: oklch(0.68 0.18 15);
--danger-foreground: oklch(0.98 0.005 15);
/* Component Colors */
--segment: oklch(0.98 0.01 230);
--segment-foreground: oklch(0.25 0.04 230);
/* Misc Colors */
--border: oklch(0 0 0 / 0%);
--separator: oklch(0.91 0.015 230);
--focus: var(--accent);
--link: oklch(0.62 0.17 230);
/* Shadows */
--surface-shadow:
0 2px 4px 0 rgba(0, 0, 0, 0.04), 0 1px 2px 0 rgba(0, 0, 0, 0.06),
0 0 1px 0 rgba(0, 0, 0, 0.06);
--overlay-shadow:
0 2px 8px 0 rgba(0, 0, 0, 0.02), 0 -6px 12px 0 rgba(0, 0, 0, 0.01),
0 14px 28px 0 rgba(0, 0, 0, 0.03);
--field-shadow:
0 2px 4px 0 rgba(0, 0, 0, 0.04), 0 1px 2px 0 rgba(0, 0, 0, 0.06),
0 0 1px 0 rgba(0, 0, 0, 0.06);
}
@variant ocean-dark {
/* Base Colors */
--background: oklch(0.15 0.04 230);
--foreground: oklch(0.94 0.01 230);
/* Surface: Used for non-overlay components (cards, accordions, disclosure groups) */
--surface: oklch(0.2 0.048 230);
--surface-foreground: oklch(0.9 0.015 230);
--surface-secondary: oklch(0.24 0.046 230);
--surface-secondary-foreground: oklch(0.9 0.015 230);
--surface-tertiary: oklch(0.27 0.044 230);
--surface-tertiary-foreground: oklch(0.9 0.015 230);
/* Overlay: Used for floating/overlay components (dialogs, popovers, modals, menus) */
--overlay: oklch(0.23 0.045 230);
--overlay-foreground: oklch(0.9 0.015 230);
--backdrop: oklch(0% 0 0 / 20%);
--muted: oklch(0.5 0.04 230);
--default: oklch(0.25 0.05 230);
--default-foreground: oklch(0.88 0.018 230);
/* Accent */
--accent: oklch(0.72 0.21 230);
--accent-foreground: oklch(0.15 0.04 230);
/* Form Field Defaults - Colors */
--field-background: var(--default);
--field-foreground: var(--foreground);
--field-placeholder: var(--muted);
--field-border: transparent;
/* Status Colors */
--success: oklch(0.68 0.16 165);
--success-foreground: oklch(0.95 0.008 165);
--warning: oklch(0.75 0.14 90);
--warning-foreground: oklch(0.2 0.04 90);
--danger: oklch(0.65 0.2 20);
--danger-foreground: oklch(0.95 0.008 20);
/* Component Colors */
--segment: oklch(0.22 0.046 230);
--segment-foreground: oklch(0.9 0.015 230);
/* Misc Colors */
--border: oklch(0 0 0 / 0%);
--separator: oklch(0.28 0.045 230);
--focus: var(--accent);
--link: oklch(0.75 0.18 230);
/* Shadows */
--surface-shadow: 0 0 0 0 transparent inset; /* No shadow on dark mode */
--overlay-shadow: 0 0 1px 0 rgba(255, 255, 255, 0.3) inset;
--field-shadow: 0 0 0 0 transparent inset; /* Transparent shadow to allow ring utilities to work */
}
}
}
```
**Important:** When adding custom themes, you must register them in your Metro config:
```js
// metro.config.js
const { withUniwindConfig } = require('uniwind/metro');
const {
wrapWithReanimatedMetroConfig,
} = require('react-native-reanimated/metro-config');
const config = {
// ... your existing config
};
module.exports = withUniwindConfig(wrapWithReanimatedMetroConfig(config), {
cssEntryFile: './global.css',
dtsFile: './src/uniwind.d.ts',
extraThemes: ['ocean-light', 'ocean-dark'],
});
```
Apply themes in your app:
```tsx
import { Uniwind } from 'uniwind';
import { Button } from 'heroui-native';
function App() {
return (
Uniwind.setTheme('ocean-light')}>
Ocean Theme
);
}
```
## Adding Custom Colors
Add your own semantic colors to the theme:
```css
@layer theme {
@variant light {
--info: oklch(0.6 0.15 210);
--info-foreground: oklch(0.98 0 0);
}
@variant dark {
--info: oklch(0.7 0.12 210);
--info-foreground: oklch(0.15 0 0);
}
}
/* Make the color available to Tailwind */
@theme inline {
--color-info: var(--info);
--color-info-foreground: var(--info-foreground);
}
```
Now use it in your components:
```tsx
import { View, Text } from 'react-native';
Info message
;
```
## Custom Fonts
To use a custom font family in your app, you need to load the fonts and then override the font CSS variables.
### 1. Load Fonts in Your App
First, load your custom fonts (using Expo's `useFonts` hook for example):
```tsx
import { useFonts } from 'expo-font';
import { HeroUINativeProvider } from 'heroui-native';
import {
YourFont_400Regular,
YourFont_500Medium,
YourFont_600SemiBold,
} from '@expo-google-fonts/your-font';
export default function App() {
const [fontsLoaded] = useFonts({
YourFont_400Regular,
YourFont_500Medium,
YourFont_600SemiBold,
});
if (!fontsLoaded) {
return null; // Or return a loading screen
}
return {/* Your app content */} ;
}
```
### 2. Configure Font CSS Variables
After loading the fonts, override the font CSS variables in your `global.css` file:
```css
@theme {
--font-normal: 'YourFont-400Regular';
--font-medium: 'YourFont-500Medium';
--font-semibold: 'YourFont-600SemiBold';
--font-bold: 'YourFont-700Bold';
}
```
**Note:** The font names in CSS variables should match the PostScript names of your loaded fonts. Check your font package documentation or use the font names exactly as they appear in your `useFonts` hook.
All HeroUI Native components automatically use these font variables, ensuring consistent typography throughout your app.
### How Font Weights Resolve
Components request weights through the `font-normal`, `font-medium`, `font-semibold` and `font-bold` utilities, which resolve differently depending on whether you define the variables above:
* **Custom fonts defined** — a weight selects the matching family, so `--font-semibold` must point at a face that is already semibold. No numeric `font-weight` is applied, because pairing one with a single-weight face makes iOS pick the heaviest face in the family.
* **No custom fonts** — the same weight applies a numeric `font-weight` to the system font.
**Define all four variables if you define any of them.** The two modes are resolved per weight, so a weight with no variable falls back to a numeric weight on the platform font while the others keep your custom family. Besides mixing typefaces, that combination can make iOS render text with the heaviest face of your family, because pairing a numeric weight with a single-weight face is exactly the case iOS resolves incorrectly.
## Variables Reference
HeroUI defines three types of variables:
1. **Base Variables** — Non-changing values like `--white`, `--black`
2. **Theme Variables** — Colors that change between light/dark themes
3. **Calculated Variables** — Automatically generated hover (pressed) states and size variants
For a complete reference, see: [Colors Documentation](/docs/native/getting-started/colors), [Default Theme Variables](https://github.com/heroui-inc/heroui-native/blob/main/src/styles/variables.css), [Shared Theme Utilities](https://github.com/heroui-inc/heroui-native/blob/main/src/styles/theme.css)
**Calculated variables (Tailwind):**
We use Tailwind's `@theme` directive to automatically create calculated variables for hover (pressed) states and radius variants. These are defined in [theme.css](https://github.com/heroui-inc/heroui-native/blob/main/src/styles/theme.css):
```css
@theme inline static {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-surface: var(--surface);
--color-surface-foreground: var(--surface-foreground);
--color-surface-hover: color-mix(in oklab, var(--surface) 92%, var(--surface-foreground) 8%);
--color-surface-secondary: var(--surface-secondary);
--color-surface-secondary-foreground: var(--surface-secondary-foreground);
--color-surface-tertiary: var(--surface-tertiary);
--color-surface-tertiary-foreground: var(--surface-tertiary-foreground);
--color-overlay: var(--overlay);
--color-overlay-foreground: var(--overlay-foreground);
--color-backdrop: var(--backdrop);
--color-muted: var(--muted);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-segment: var(--segment);
--color-segment-foreground: var(--segment-foreground);
--color-border: var(--border);
--color-separator: var(--separator);
--color-focus: var(--focus);
--color-link: var(--link);
--color-default: var(--default);
--color-default-foreground: var(--default-foreground);
--color-success: var(--success);
--color-success-foreground: var(--success-foreground);
--color-warning: var(--warning);
--color-warning-foreground: var(--warning-foreground);
--color-danger: var(--danger);
--color-danger-foreground: var(--danger-foreground);
/* Form Field Tokens */
--color-field: var(--field-background, var(--default));
--color-field-foreground: var(--field-foreground, var(--foreground));
--color-field-placeholder: var(--field-placeholder, var(--muted));
--color-field-border: var(--field-border, var(--border));
--radius-field: var(--field-radius, var(--radius-xl));
--border-width-field-width: var(--field-border-width, var(--border-width));
--shadow-surface: var(--surface-shadow);
--shadow-overlay: var(--overlay-shadow);
--shadow-field: var(--field-shadow);
/* Calculated Variables */
/* Colors */
/* --- background shades --- */
--color-background-secondary: color-mix(in oklab, var(--background) 96%, var(--foreground) 4%);
--color-background-tertiary: color-mix(in oklab, var(--background) 92%, var(--foreground) 8%);
--color-background-inverse: var(--foreground);
/* ------------------------- */
--color-default-hover: color-mix(in oklab, var(--default) 96%, var(--default-foreground) 4%);
--color-accent-hover: color-mix(in oklab, var(--accent) 90%, var(--accent-foreground) 10%);
--color-success-hover: color-mix(in oklab, var(--success) 90%, var(--success-foreground) 10%);
--color-warning-hover: color-mix(in oklab, var(--warning) 90%, var(--warning-foreground) 10%);
--color-danger-hover: color-mix(in oklab, var(--danger) 90%, var(--danger-foreground) 10%);
/* Form Field Colors */
--color-field-hover: color-mix(in oklab, var(--field-background, var(--default)) 90%, var(--field-foreground, var(--foreground)) 2%);
--color-field-focus: var(--field-background, var(--default));
--color-field-border-hover: color-mix(in oklab, var(--field-border, var(--border)) 88%, var(--field-foreground, var(--foreground)) 10%);
--color-field-border-focus: color-mix(in oklab, var(--field-border, var(--border)) 74%, var(--field-foreground, var(--foreground)) 22%);
/* Soft Colors */
--color-accent-soft: color-mix(in oklab, var(--accent) 15%, transparent);
--color-accent-soft-foreground: var(--accent);
--color-accent-soft-hover: color-mix(in oklab, var(--accent) 20%, transparent);
--color-danger-soft: color-mix(in oklab, var(--danger) 15%, transparent);
--color-danger-soft-foreground: var(--danger);
--color-danger-soft-hover: color-mix(in oklab, var(--danger) 20%, transparent);
--color-warning-soft: color-mix(in oklab, var(--warning) 15%, transparent);
--color-warning-soft-foreground: var(--warning);
--color-warning-soft-hover: color-mix(in oklab, var(--warning) 20%, transparent);
--color-success-soft: color-mix(in oklab, var(--success) 15%, transparent);
--color-success-soft-foreground: var(--success);
--color-success-soft-hover: color-mix(in oklab, var(--success) 20%, transparent);
/* Separator Colors - Levels */
--color-separator-secondary: color-mix(in oklab, var(--surface) 85%, var(--surface-foreground) 15%);
--color-separator-tertiary: color-mix(in oklab, var(--surface) 81%, var(--surface-foreground) 19%);
/* Border Colors - Levels (progressive contrast: default → secondary → tertiary) */
/* Light mode: lighter → darker | Dark mode: darker → lighter */
--color-border-secondary: color-mix(in oklab, var(--surface) 78%, var(--surface-foreground) 22%);
--color-border-tertiary: color-mix(in oklab, var(--surface) 66%, var(--surface-foreground) 34%);
/* Radius and default sizes - defaults can change by just changing the --radius */
--radius-xs: calc(var(--radius) * 0.25); /* 0.125rem (2px) */
--radius-sm: calc(var(--radius) * 0.5); /* 0.25rem (4px) */
--radius-md: calc(var(--radius) * 0.75); /* 0.375rem (6px) */
--radius-lg: calc(var(--radius) * 1); /* 0.5rem (8px) */
--radius-xl: calc(var(--radius) * 1.5); /* 0.75rem (12px) */
--radius-2xl: calc(var(--radius) * 2); /* 1rem (16px) */
--radius-3xl: calc(var(--radius) * 3); /* 1.5rem (24px) */
--radius-4xl: calc(var(--radius) * 4); /* 2rem (32px) */
}
```
> **Field border utilities:** Use `border-field-width` for the field border width and `border-field-border` for the field border color. Pair them together (`border-field-width border-field-border`) when you need both. The `border-field` class remains a border-color utility from `--color-field` only; do not use it for width. If you previously used `border-field` for width, migrate to `border-field-width`. Customize the width via the `--field-border-width` primitive.
Form controls now rely on the `--field-*` variables and their calculated hover/focus variants. Update them in your theme to restyle inputs, checkboxes, radios, and OTP slots without impacting surfaces like buttons or cards.
## Vibrant Palette
By default, HeroUI Native uses accessible soft foreground colors that mix the semantic color with the foreground for better contrast on soft backgrounds. If you prefer more saturated, vibrant soft foreground colors, import the optional `heroui-native/styles/vibrant` stylesheet alongside the base styles:
```css
/* global.css */
@import "heroui-native/styles";
@import "heroui-native/styles/vibrant"; /* [!code highlight] */
```
This switches all `*-soft-foreground` variables (accent, success, warning, danger) to use 92% of the semantic color with only 8% foreground mixed in — closer to the raw color but with a slight contrast boost. Components such as [Alert](/docs/native/components/alert), [Avatar](/docs/native/components/avatar), [Button](/docs/native/components/button), [Chip](/docs/native/components/chip), and [Toast](/docs/native/components/toast) automatically pick up the new soft foreground colors on their soft variants — no component prop changes are required.
| Mode | Accessible (default) | Vibrant |
| --------------- | -------------------------------------------- | ------------------------------------- |
| Soft foreground | `color-mix(color 70-80%, foreground 30-40%)` | `color-mix(color 92%, foreground 8%)` |
The vibrant palette prioritizes visual saturation over contrast. It may not meet WCAG accessibility guidelines for some color combinations, especially with lighter accent colors.
The optional vibrant palette is available starting from [v1.0.4](/docs/native/releases/v1-0-4).
## Resources
* [Colors Documentation](/docs/native/getting-started/colors)
* [Styling Guide](/docs/native/getting-started/styling)
* [Tailwind CSS v4 Theming](https://tailwindcss.com/docs/theme)
* [OKLCH Color Tool](https://oklch.com)
# Design Principles
**Category**: native
**URL**: https://heroui.com/en/docs/native/getting-started/design-principles
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/getting-started/(overview)/design-principles.mdx
> Core principles that guide HeroUI v3's design and development
HeroUI Native follows 9 core principles that prioritize clarity, accessibility, customization, and developer experience.
## Core Principles
### 1. Semantic Intent Over Visual Style
Use semantic naming (primary, secondary, tertiary) instead of visual descriptions (solid, flat, bordered). Inspired by [Uber's Base design system](https://base.uber.com/6d2425e9f/p/756216-button), variants follow a clear hierarchy:
```tsx
// ✅ Semantic variants communicate hierarchy
Save
Edit
Cancel
```
| Variant | Purpose | Usage |
| ------------- | --------------------------------- | ---------------- |
| **Primary** | Main action to move forward | 1 per context |
| **Secondary** | Alternative actions | Multiple allowed |
| **Tertiary** | Dismissive actions (cancel, skip) | Sparingly |
| **Danger** | Destructive actions | When needed |
### 2. Accessibility as Foundation
Accessibility follows mobile development best practices with proper touch accessibility, focus management, and screen reader support built into every component. All components include proper accessibility labels and semantic structure for VoiceOver (iOS) and TalkBack (Android).
```tsx
import { Tabs } from 'heroui-native';
Profile
Security
Content
Content
```
### 3. Composition Over Configuration
Compound components let you rearrange, customize, or omit parts as needed. Use dot notation to compose components exactly as you need them.
```tsx
// Compose parts to build exactly what you need
import { Accordion } from 'heroui-native';
Question Text
Answer content
```
### 4. Progressive Disclosure
Start simple, add complexity only when needed. Components work with minimal props and scale up as requirements grow.
```tsx
import { Button, Spinner } from 'heroui-native';
import { Feather } from '@expo/vector-icons';
// Level 1: Minimal
Click me
// Level 2: Enhanced
Submit
// Level 3: Advanced
{isLoading ? (
<>
Loading...
>
) : (
Submit
)}
```
### 5. Predictable Behavior
Consistent patterns across all components: sizes (`sm`, `md`, `lg`), variants, and className support. Same API, same behavior.
```tsx
import { Button, Chip, Avatar } from 'heroui-native';
// All components follow the same patterns
Click me
Success
JD
```
### 6. Type Safety First
Full TypeScript support with IntelliSense, auto-completion, and compile-time error detection. Extend types for custom components.
```tsx
import type { ButtonRootProps } from 'heroui-native';
// Type-safe props and event handlers
{ // Properly typed press handler
console.log('Button pressed');
}}
>
Click me
// Extend types for custom components
interface CustomButtonProps extends Omit {
intent: 'save' | 'cancel' | 'delete';
}
```
### 7. Developer Experience Excellence
Clear APIs, descriptive errors, IntelliSense and AI-friendly markdown docs.
### 8. Complete Customization
Beautiful defaults out-of-the-box. Transform the entire look with CSS variables through [Uniwind's theming system](https://docs.uniwind.dev/theming/basics). Every slot is customizable.
```css
/* Custom colors using Uniwind's theme layer */
@layer theme {
@variant light {
--accent: oklch(0.65 0.25 270); /* Custom indigo accent */
--background: oklch(0.98 0 0); /* Custom background */
}
@variant dark {
--accent: oklch(0.65 0.25 270);
--background: oklch(0.15 0 0);
}
}
/* Radius customization */
@theme {
--radius: 0.75rem; /* Increase for rounder components */
}
```
### 9. Open and Extensible
Wrap, extend, and customize components to match your needs. Create custom wrappers or apply custom styles using className.
```tsx
import { Button } from 'heroui-native';
import type { ButtonRootProps } from 'heroui-native';
// Custom wrapper component
interface CTAButtonProps extends Omit {
intent?: 'primary-cta' | 'secondary-cta' | 'minimal';
}
const CTAButton = ({
intent = 'primary-cta',
children,
...props
}: CTAButtonProps) => {
const variantMap = {
'primary-cta': 'primary',
'secondary-cta': 'secondary',
'minimal': 'ghost'
} as const;
return (
{children}
);
};
// Usage
Get Started
Learn More
```
**Extend with Tailwind Variants:**
```tsx
import { Button } from 'heroui-native';
import { tv } from 'tailwind-variants';
// Extend button styles with custom variants
const myButtonVariants = tv({
base: 'px-4 py-2 rounded-lg',
variants: {
variant: {
'primary-cta': 'bg-accent px-8 py-4 shadow-lg',
'secondary-cta': 'border-2 border-accent px-6 py-3',
}
},
defaultVariants: {
variant: 'primary-cta',
}
});
// Label variants for text colors (must be applied to Button.Label)
const myLabelVariants = tv({
base: '',
variants: {
variant: {
'primary-cta': 'text-accent-foreground',
'secondary-cta': 'text-accent',
}
},
defaultVariants: {
variant: 'primary-cta',
}
});
// Use the custom variants
function CustomButton({ variant, className, labelClassName, children, ...props }) {
return (
{children}
);
}
// Usage
Get Started
Learn More
```
# Quick Start
**Category**: native
**URL**: https://heroui.com/en/docs/native/getting-started/quick-start
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/getting-started/(overview)/quick-start.mdx
> Get up and running with HeroUI Native
Choose the path that fits your project:
* **Option 1** — Scaffold a new, preconfigured project with our CLI. Zero setup.
* **Option 2** — Add HeroUI Native to an existing React Native or Expo project.
## Option 1: Create a New Project
The fastest way to start. The CLI scaffolds an Expo project with HeroUI Native, all required peer dependencies, Uniwind / Tailwind CSS, global styles, and the `HeroUINativeProvider` already wired up — so you can jump straight to building.
```bash
npx create-heroui-native-app@latest
```
```bash
pnpm create heroui-native-app@latest
```
```bash
yarn create heroui-native-app
```
```bash
bun create heroui-native-app@latest
```
Follow the interactive prompts, then start the dev server:
```bash
cd my-app
npm run start
```
You're ready to build. Skip ahead to [Use Your First Component](#use-your-first-component) or [browse components](/docs/native/components).
The scaffold includes Expo with TypeScript, Uniwind + Tailwind CSS preconfigured, `global.css` with the required imports, and the app entry already wrapped in `GestureHandlerRootView` and `HeroUINativeProvider`.
## Option 2: Add to an Existing Project
If you already have a React Native or Expo app, follow these steps to install and configure HeroUI Native manually.
**Prefer to let your AI assistant do it?** Install the [HeroUI Native MCP Server](/docs/native/getting-started/mcp-server) in your editor, then paste the prompt into your AI assistant — it will analyze your project and handle the entire setup for you.
### 1. Install HeroUI Native
```bash
npm install heroui-native
```
```bash
pnpm add heroui-native
```
```bash
yarn add heroui-native
```
```bash
bun add heroui-native
```
### 2. Install Mandatory Peer Dependencies
```bash
npm install react-native-reanimated@^4.1.1 react-native-gesture-handler@^2.28.0 react-native-worklets@^0.5.1 react-native-safe-area-context@^5.6.0 react-native-svg@^15.12.1 tailwind-variants@^3.2.2 tailwind-merge@^3.4.0
```
```bash
pnpm add react-native-reanimated@^4.1.1 react-native-gesture-handler@^2.28.0 react-native-worklets@^0.5.1 react-native-safe-area-context@^5.6.0 react-native-svg@^15.12.1 tailwind-variants@^3.2.2 tailwind-merge@^3.4.0
```
```bash
yarn add react-native-reanimated@^4.1.1 react-native-gesture-handler@^2.28.0 react-native-worklets@^0.5.1 react-native-safe-area-context@^5.6.0 react-native-svg@^15.12.1 tailwind-variants@^3.2.2 tailwind-merge@^3.4.0
```
```bash
bun add react-native-reanimated@^4.1.1 react-native-gesture-handler@^2.28.0 react-native-worklets@^0.5.1 react-native-safe-area-context@^5.6.0 react-native-svg@^15.12.1 tailwind-variants@^3.2.2 tailwind-merge@^3.4.0
```
It's recommended to use the exact versions specified above to avoid compatibility issues. Version mismatches may cause unexpected bugs.
### 3. Optional Dependencies
These packages are only needed if you use specific components or features:
| Package | Version | Required for |
| ---------------------- | --------- | ----------------------------------------------------------------------- |
| `react-native-screens` | `^4.16.0` | BottomSheet, Dialog, Menu, Popover, Select, Toast |
| `@gorhom/bottom-sheet` | `^5.2.9` | BottomSheet, Menu / Popover / Select when `presentation="bottom-sheet"` |
### 4. Set Up Uniwind
Follow the [Uniwind installation guide](https://docs.uniwind.dev/quickstart) to set up Tailwind CSS for React Native.
If you're migrating from NativeWind, see the [migration guide](https://docs.uniwind.dev/migration-from-nativewind).
### 5. Configure global.css
Inside your `global.css` file add the following imports:
```css
@import 'tailwindcss';
@import 'uniwind';
@import 'heroui-native/styles';
/* Path to the heroui-native lib inside node_modules relative to global.css */
/* Examples:
* - If global.css is at project root: ./node_modules/heroui-native/lib
* - If global.css is in app/: ../node_modules/heroui-native/lib
* - If global.css is in src/styles/: ../../node_modules/heroui-native/lib
*/
/* Not required starting from heroui-native 1.0.8 — the library registers its own source */
@source './node_modules/heroui-native/lib';
```
### 6. Wrap Your App with Provider
Wrap your application with `HeroUINativeProvider`. You must wrap it with `GestureHandlerRootView`:
```tsx
import { HeroUINativeProvider } from 'heroui-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
export default function App() {
return (
{/* Your app content */}
);
}
```
> **Note**: For advanced configuration options including text props, animation settings, and toast configuration, see the [Provider documentation](/docs/native/getting-started/provider).
## Use Your First Component
```tsx
import { Button } from 'heroui-native';
import { View } from 'react-native';
export default function MyComponent() {
return (
console.log('Pressed!')}>Get Started
);
}
```
## Reduce Bundle Size with Granular Exports
If you want to reduce bundle size and import only the components you need, our library provides granular exports for each component:
```tsx
// Granular imports - use when you need only a few components
import { HeroUINativeProvider } from "heroui-native/provider";
import { Button } from "heroui-native/button";
import { Card } from "heroui-native/card";
// General import - imports the whole library, use when you're using many components
import { Button, Card } from "heroui-native";
```
Granular imports are ideal when you only need a few components, as they help keep your bundle size smaller. General imports from `heroui-native` will include the entire library, which is convenient when you're using many components throughout your app.
**Available granular exports:**
* `heroui-native/provider` - Provider component
* `heroui-native/provider-raw` - Lightweight provider (keeps bare minimum to start)
* `heroui-native/[component-name]` - Individual components
* `heroui-native/portal` - Portal utilities
* `heroui-native/toast` - Toast provider and utilities
* `heroui-native/utils` - Utility functions
* `heroui-native/hooks` - Custom hooks
**Important**: To keep the bundle size under control, you must follow the pattern with granular imports consistently. Even one general import from `heroui-native` will break this optimization strategy.
> **Tip**: For even more control over your bundle, consider using [`HeroUINativeProviderRaw`](/docs/native/getting-started/provider#raw-provider) — a lightweight provider that excludes `ToastProvider` and `PortalHost`.
## What's Next?
* [HeroUI Native Provider](/docs/native/getting-started/provider)
* [Styling Guide](/docs/native/getting-started/styling)
* [Theming Documentation](/docs/native/getting-started/theming)
## Running on Web (Expo)
HeroUI Native is currently not recommended for web use. We are focusing on mobile platforms (iOS and Android) at this time. For web development, please use [HeroUI React](/docs/react/getting-started/quick-start) instead.
# Agent Skills
**Category**: native
**URL**: https://heroui.com/en/docs/native/getting-started/agent-skills
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/getting-started/(ui-for-agents)/agent-skills.mdx
> Enable AI assistants to build mobile UIs with HeroUI Native components
HeroUI Native Skills give your AI assistant comprehensive knowledge of HeroUI Native components, patterns, and best practices for React Native development.
### Installation
```bash
curl -fsSL https://heroui.com/install | bash -s heroui-native
```
Or using the skills package:
```bash
npx skills add heroui-inc/heroui
```
Support Claude Code, Cursor, OpenCode and more.
### Usage
Skills are **automatically discovered** by your AI assistant, or call it directly using `/heroui-native` command.
Simply ask your AI assistant to:
* Build mobile components using HeroUI Native
* Create screens with HeroUI Native components
* Customize themes and styles
* Access component documentation
For more complex use cases, use the [MCP Server](/docs/native/getting-started/mcp-server) which provides real-time access to component documentation and source code.
### What's Included
* HeroUI Native installation guide
* All HeroUI Native components with props, examples, and usage patterns
* Theming and styling guidelines with Uniwind
* Design principles and composition patterns
### Structure
```
skills/heroui-native/
├── SKILL.md # Main skill documentation
├── LICENSE.txt # Apache License 2.0
└── scripts/ # Utility scripts
├── list_components.mjs
├── get_component_docs.mjs
├── get_theme.mjs
└── get_docs.mjs
```
### Related Documentation
* [Agent Skills Specification](https://agentskills.io/home) - Learn about the Agent Skills format
* [Claude Agent Skills](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview) - Claude's Skills documentation
* [Cursor Skills](https://cursor.com/docs/context/skills) - Using Skills in Cursor
* [OpenCode Skills](https://opencode.ai/docs/skills) - Using Skills in OpenCode
# AGENTS.md
**Category**: native
**URL**: https://heroui.com/en/docs/native/getting-started/agents-md
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/getting-started/(ui-for-agents)/agents-md.mdx
> Download HeroUI Native documentation for AI coding agents
Download HeroUI Native documentation directly into your project for AI assistants to reference.
**Note:** The `agents-md` command is specifically for HeroUI React v3 and HeroUI Native. Other CLI commands (like `add`, `init`, `upgrade`, etc.) are for HeroUI v2 (for now).
### Usage
```bash
npx heroui-cli@latest agents-md --native
```
Or specify output file:
```bash
npx heroui-cli@latest agents-md --native --output AGENTS.md
```
### What It Does
* Downloads latest HeroUI Native docs to `.heroui-docs/native/`
* Generates an index in `AGENTS.md` or `CLAUDE.md`
* Adds `.heroui-docs/` to `.gitignore` automatically
### Options
* `--native` - Download Native docs only
* `--output ` - Target file(s) (e.g., `AGENTS.md` or `AGENTS.md CLAUDE.md`)
* `--ssh` - Use SSH for git clone
### Requirements
* Tailwind CSS >= v4 (via Uniwind)
### Related Documentation
* [AGENTS.md](https://agents.md/) - Learn about the AGENTS.md format for coding agents
* [CLAUDE.md](https://code.claude.com/docs/en/best-practices#write-an-effective-claude-md) - Claude equivalent of AGENTS.md
* [AGENTS.md vs Skills](https://vercel.com/blog/agents-md-outperforms-skills-in-our-agent-evals) - AGENTS.md performance
# LLMs.txt
**Category**: native
**URL**: https://heroui.com/en/docs/native/getting-started/llms-txt
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/getting-started/(ui-for-agents)/llms-txt.mdx
> Enable AI assistants like Claude, Cursor, and Windsurf to understand HeroUI Native
We provide [LLMs.txt](https://llmstxt.org/) files to make HeroUI Native documentation accessible to AI coding assistants.
## Available Files
**Core documentation:**
* [/native/llms.txt](/native/llms.txt) — Quick reference index for Native documentation
* [/native/llms-full.txt](/native/llms-full.txt) — Complete HeroUI Native documentation
**For limited context windows:**
* [/native/llms-components.txt](/native/llms-components.txt) — Component documentation only
* [/native/llms-patterns.txt](/native/llms-patterns.txt) — Common patterns and recipes
**All platforms:**
* [/llms.txt](/llms.txt) — Quick reference index (React + Native)
* [/llms-full.txt](/llms-full.txt) — Complete documentation (React + Native)
* [/llms-components.txt](/llms-components.txt) — All component documentation
* [/llms-patterns.txt](/llms-patterns.txt) — All patterns and recipes
## Integration
**Claude Code:** Tell Claude to reference the documentation:
```
Use HeroUI Native documentation from https://heroui.com/native/llms.txt
```
Or add to your project's `.claude` file for automatic loading.
**Cursor:** Use the `@Docs` feature:
```
@Docs https://heroui.com/native/llms-full.txt
```
[Learn more](https://docs.cursor.com/context/@-symbols/@-docs)
**Windsurf:** Add to your `.windsurfrules` file:
```
#docs https://heroui.com/native/llms-full.txt
```
[Learn more](https://docs.codeium.com/windsurf/memories#memories-and-rules)
**Other AI tools:** Most AI assistants can reference documentation by URL. Simply provide:
```
https://heroui.com/native/llms.txt
```
**For component-specific documentation:**
```
https://heroui.com/native/llms-components.txt
```
**For patterns and best practices:**
```
https://heroui.com/native/llms-patterns.txt
```
## Contributing
Found an issue with AI-generated code? Help us improve our LLMs.txt files on [GitHub](https://github.com/heroui-inc/heroui).
# MCP Server
**Category**: native
**URL**: https://heroui.com/en/docs/native/getting-started/mcp-server
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/native/getting-started/(ui-for-agents)/mcp-server.mdx
> Access HeroUI Native documentation directly in your AI assistant
The HeroUI MCP Server gives AI assistants direct access to HeroUI Native component documentation, making it easier to build with HeroUI in AI-powered development environments.
The MCP server currently supports **heroui-native** and [stdio transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#stdio). Published at `@heroui/native-mcp` on npm. View the source code on [GitHub](https://github.com/heroui-inc/heroui-mcp).
As we add more components to HeroUI Native, they'll be available in the MCP server too.
## Quick Setup
**Cursor:**
Or manually add to **Cursor Settings** → **Tools** → **MCP Servers**:
```json title=".cursor/mcp.json"
{
"mcpServers": {
"heroui-native": {
"command": "npx",
"args": ["-y", "@heroui/native-mcp@latest"]
}
}
}
```
Alternatively, add the following to your `~/.cursor/mcp.json` file. To learn more, see the [Cursor documentation](https://cursor.com/docs/context/mcp).
**Claude Code:** Run this command in your terminal:
```bash
claude mcp add heroui-native -- npx -y @heroui/native-mcp@latest
```
Or manually add to your project's `.mcp.json` file:
```json title=".mcp.json"
{
"mcpServers": {
"heroui-native": {
"command": "npx",
"args": ["-y", "@heroui/native-mcp@latest"]
}
}
}
```
After adding the configuration, restart Claude Code and run `/mcp` to see the HeroUI MCP server in the list. If you see **Connected**, you're ready to use it.
See the [Claude Code MCP documentation](https://docs.claude.com/en/docs/claude-code/mcp) for more details.
**Windsurf:** Add the HeroUI server to your project's `.windsurf/mcp.json` configuration file:
```json title=".windsurf/mcp.json"
{
"mcpServers": {
"heroui-native": {
"command": "npx",
"args": ["-y", "@heroui/native-mcp@latest"]
}
}
}
```
After adding the configuration, restart Windsurf to activate the MCP server.
See the [Windsurf MCP documentation](https://docs.windsurf.com/windsurf/cascade/mcp) for more details.
**Zed:** Add the HeroUI server to your `settings.json` configuration file. Open settings via Command Palette (`zed: open settings`) or use `Cmd-,` (Mac) / `Ctrl-,` (Linux):
```json title="settings.json"
{
"context_servers": {
"heroui-native": {
"command": "npx",
"args": ["-y", "@heroui/native-mcp@latest"],
"env": {}
}
}
}
```
After adding the configuration, restart Zed and open the Agent Panel settings view. Check that the indicator dot next to the heroui-native server is green with "Server is active" tooltip.
See the [Zed MCP documentation](https://zed.dev/docs/ai/mcp) for more details.
**VS Code:** To configure MCP in VS Code with GitHub Copilot, add the HeroUI server to your project's `.vscode/mcp.json` configuration file:
```json title=".vscode/mcp.json"
{
"servers": {
"heroui-native": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@heroui/native-mcp@latest"]
}
}
}
```
After adding the configuration, open `.vscode/mcp.json` and click **Start** next to the heroui-native server.
See the [VS Code MCP documentation](https://code.visualstudio.com/docs/copilot/customization/mcp-servers) for more details.
**Codex:** Add the HeroUI server to your `~/.codex/config.toml` (or a project-scoped `.codex/config.toml`):
```toml title="config.toml"
[mcp_servers.heroui-native]
command = "npx"
args = ["-y", "@heroui/native-mcp@latest"]
```
After adding the configuration, restart Codex and run `/mcp` in the TUI to verify the server is active.
See the [Codex MCP documentation](https://developers.openai.com/codex/mcp) for more details.
**OpenCode:** Add the HeroUI server to your project's `opencode.json` configuration file:
```json title="opencode.json"
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"heroui-native": {
"type": "local",
"command": ["npx", "-y", "@heroui/native-mcp@latest"]
}
}
}
```
After adding the configuration, restart OpenCode to activate the MCP server.
See the [OpenCode MCP documentation](https://open-code.ai/docs/en/mcp-servers) for more details.
## Usage
Once configured, ask your AI assistant questions like:
* "Help me install HeroUI Native in my Expo app"
* "Show me all HeroUI Native components"
* "What props does the Button component have?"
* "Give me an example of using the Card component"
* "What are the theme variables for dark mode?"
### Automatic Updates
The MCP server can help you upgrade to the latest HeroUI Native version:
```bash
"Hey Cursor, update HeroUI Native to the latest version"
```
Your AI assistant will automatically:
* Compare your current version with the latest release
* Review the changelog for breaking changes
* Apply the necessary code updates to your project
This works for any version upgrade, whether you're updating to the latest stable or pre-release version.
## Available Tools
The MCP server provides these tools to AI assistants:
| Tool | Description |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `list_components` | List all available HeroUI Native components |
| `get_component_docs` | Get complete component documentation including anatomy, props, examples, and usage patterns for one or more components |
| `get_theme_variables` | Access theme variables for colors, typography, spacing with light/dark mode support |
| `get_docs` | Browse the full HeroUI Native documentation including guides and principles (use path `/docs/native/getting-started/quick-start` for installation instructions) |
## Troubleshooting
**Requirements:** Node.js 22 or higher. The package will be automatically downloaded when using `npx`.
**Need help?** [GitHub Issues](https://github.com/heroui-inc/heroui-mcp/issues) | [Discord Community](https://discord.gg/heroui)
## Links
* [npm Package](https://www.npmjs.com/package/@heroui/native-mcp)
* [GitHub Repository](https://github.com/heroui-inc/heroui-mcp)
* [Contributing Guide](https://github.com/heroui-inc/heroui-mcp/blob/main/CONTRIBUTING.md)
# 所有组件(React)
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/index.mdx
> 浏览库中所有可用组件的完整列表,更多组件正在路上。
## 按钮
## 集合
## 颜色
## 控件
## 数据展示
## 日期与时间
## 反馈
## 表单
## 布局
## 媒体
## 导航
## 浮层
## 选择器
## 排版
## 工具
# 介绍
**Category**: react
**URL**: https://heroui.com/cn/docs/react/getting-started
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/getting-started/index.mdx
> 一个开源 UI 组件库,用于构建美观且易于访问的用户界面。
HeroUI 是一个基于 [Tailwind CSS v4](https://tailwindcss.com/) 和 [React Aria Components](https://react-spectrum.adobe.com/react-aria/index.html) 构建的 React 组件库。每个组件都带有流畅的动画、精致的细节和内置的无障碍支持——开箱即用,完全可定制。
## 为什么选择 HeroUI?
**默认美观** — 开箱即用,外观专业,无需额外样式配置。
**无障碍** — 基于 [React Aria Components](https://react-spectrum.adobe.com/react-aria/components.html) 构建,内置焦点管理、键盘导航和屏幕阅读器支持。
**灵活** — 每个组件都由可定制的部件组成。按需修改,其余保持不动。
**开发者友好** — 完整的类型化 API、可预期的模式以及出色的自动补全。
**持续维护** — 我们负责处理更新、错误修复和新功能。你只需更新依赖包。
**轻量级** — 支持 Tree Shaking,只把你实际使用的部分打包到应用中。
**面向未来** — 为 [React 19](https://react.dev/blog/2024/12/05/react-19) 和 [Tailwind v4](https://tailwindcss.com/blog/tailwindcss-v4) 而构建,专为 AI 辅助开发而设计。
## 一个精心打造的组件库,而非复制粘贴
复制粘贴的代码能用,直到它出问题为止。你将不得不维护那些不再演进的过时依赖。
HeroUI 则不同,它是与你共同演进的组件库:
* 自动更新和修复
* 无需额外工作即可获得新功能
* 组件与 React、Tailwind 和浏览器保持同步
* 深度定制,而非浅层主题调整
* 面向代码生成的 AI 友好 API
## HeroUI 生态系统
* **🌐 HeroUI v3**(Web) — 你正在浏览的就是这里!基于 Tailwind CSS v4 的 React 组件
* **📱 [HeroUI Native](https://link.heroui.com/native)**(移动端) — 为 React Native 提供精美组件
* **🤖 [HeroUI Chat](https://heroui.chat?ref=heroui-v3)**(文本生成应用) — 用自然语言创建应用
* **🧠 面向 LLM 的 UI** — 全新平台与 MCP 即将推出
**为什么选择 React Aria?** 我们选择 React Aria 是为了大规模实现无障碍能力。从 HeroUI v2 起我们就在使用它,v3 也保留了熟悉的 API 约定,例如 `isDisabled` 和 `onPress`。感谢 [Devon Govett](https://x.com/devongovett) 以及 Adobe 团队。
## 常见问题
**HeroUI 免费吗?**
是的,基于 Apache License 2.0 完全免费且开源。
**可以用于生产环境吗?**
可以。HeroUI v3 已经稳定,可放心用于生产环境。
**我可以定制组件吗?**
当然可以!你可以使用 Tailwind 工具类、CSS 变量、[BEM](https://getbem.com/) 修饰符,或以不同的方式组合组件。每一个插槽都可以定制。
**它支持 TypeScript 吗?**
完全类型化,提供出色的 IDE 支持和自动补全。
**无障碍能力如何?**
基于 React Aria Components 构建,符合 WCAG 标准。内置键盘导航、焦点管理和屏幕阅读器支持。
**可以在不使用 React 的情况下使用样式吗?**
可以,CSS 可以应用于纯 HTML。请查看我们的 [Tailwind Play 示例](https://play.tailwindcss.com/vMYXzKPyUx)。
**有 Figma 文件吗?**
有!欢迎访问我们的设计系统:[HeroUI Figma Kit V3](https://www.figma.com/community/file/1546526812159103429)。
## 参与其中
加入社区、分享反馈或参与贡献:
* [GitHub Discussions](https://github.com/heroui-inc/heroui/discussions)
* [Discord](https://discord.gg/9b6yyZKmH4)
* [X/Twitter](https://x.com/hero_ui)
* [贡献指南](https://github.com/heroui-inc/heroui/blob/main/CONTRIBUTING.md)
HeroUI 基于 [Apache License 2.0](https://github.com/heroui-inc/heroui/blob/main/LICENSE) 协议发布。
# 迁移(面向 AI 助手)
**Category**: react
**URL**: https://heroui.com/cn/docs/react/migration/agent-index
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/migration/agent-index.mdx
> 供 AI 助手协助将 HeroUI v2 迁移到 v3 时使用的入口
面向 AI 助手:在协助将 HeroUI v2 → v3 进行迁移时,请将本文档作为入口。
## 入口
请选择一种迁移策略:
* **完整迁移**(迁移过程中项目将无法正常运行)→ 阅读 `(workflows)/agent-guide-full.mdx`。
* **渐进式迁移**(v2 与 v3 并存)→ 阅读 `(workflows)/agent-guide-incremental.mdx`。
## 本套文档中的参考资料
* **通用指南:** `hooks.mdx`、`styling.mdx`。
* 上述工作流程指南已经内嵌了「主要变更」、「关键 API 变更」、组件参考表以及「新增组件」等内容。
* **各组件指南:** `(components)/.mdx`(例如 `(components)/button.mdx`、`(components)/select.mdx`)。请通过工作流程指南中的组件参考表来定位对应的文件。
# Hooks
**Category**: react
**URL**: https://heroui.com/cn/docs/react/migration/hooks
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/migration/hooks.mdx
> HeroUI Hooks 从 v2 到 v3 的迁移指南
完整的 API 参考请参阅 [v3 组件文档](/docs/components-list)。本指南重点介绍如何从 HeroUI v2 迁移 Hooks。
## 概述
HeroUI v3 移除了 v2 中存在的大多数组件 Hooks,转而使用复合组件,并新增了一个用于管理浮层状态的 Hook。本指南涵盖:
* 组件 Hooks 的移除(`useSwitch`、`useInput`、`useCheckbox` 等)
* `useDisclosure` → `useOverlayState` 的迁移
* 迁移策略与示例
## 组件 Hooks 的移除
HeroUI v2 提供了一系列组件 Hooks(例如 `useSwitch`、`useInput`、`useCheckbox` 等),它们返回一组 prop getter(`getBaseProps`、`getWrapperProps`、`getThumbProps` 等),让用户在无法直接修改内部子组件的情况下也能自定义组件结构。HeroUI v3 通过复合组件解决了这个问题,从而无需再依赖这些 Hooks。
### 为什么 v2 中存在这些 Hooks
在 v2 中,组件具有固定的内部结构。为了自定义这些结构,用户需要使用提供 prop getter 的 Hooks。例如,`useSwitch` 返回 `getBaseProps()`、`getWrapperProps()`、`getThumbProps()` 等,用户可以将其展开到自定义元素上,从而构建自己的 Switch 结构。
### v3 的解决方案:复合组件
v3 采用了复合组件模式,让你可以直接访问组件的各个部分。你不再需要使用带有 prop getter 的 Hooks,而是可以直接通过 `Switch.Control`、`Switch.Thumb`、`Checkbox.Control`、`Checkbox.Indicator` 等子组件进行组合。
### 迁移策略
1. **识别 Hook 用法**:在你的代码库中搜索来自 `@heroui/react` 的导入,找出包含 Hook 名称(`useSwitch`、`useInput`、`useCheckbox`、`useRadio` 等)的引用。
2. **替换为复合组件**:使用复合组件模式,替代带有 prop getter 的 Hooks。
3. **保留原有结构**:迁移时,尽量保持与原 Hook 实现一致的组件结构。例如:
* 如果你之前用 `useSwitch` 创建了一个 **不带** thumb 的 Switch,那么在 v3 中也不要添加 `Switch.Thumb`
* 如果你之前用 `useCheckbox` 创建了一个 **不带** indicator 的 Checkbox,那么在 v3 中也不要添加 `Checkbox.Indicator`
* 只引入原本基于 Hook 的实现中实际用到的子组件
4. **参考各组件指南**:查看各个组件的迁移指南,获取具体示例。
### 主要差异
* **v2**:Hooks 提供 prop getter,用于自定义固定的组件结构
* **v3**:复合组件允许直接组合组件的各个部分
### 保留结构示例
**v2:不带 thumb 的 Switch**
```tsx
import { useSwitch } from "@heroui/react";
function CustomSwitch() {
const { getBaseProps } = useSwitch();
return (
{/* No thumb element */}
);
}
```
**v3:等效结构**
```tsx
import { Switch } from "@heroui/react";
function CustomSwitch() {
return (
{/* No Switch.Thumb - preserving the original structure */}
);
}
```
有关具体组件的详细迁移示例,请参阅各个组件的迁移指南。
## useDisclosure → useOverlayState
v2 中的 `useDisclosure` 钩子在 v3 中已替换为 `useOverlayState`。该钩子用于管理 Modal、Popover 等浮层组件的打开/关闭状态。
### v2:useDisclosure
**API:**
```tsx
const {isOpen, onOpen, onClose, onOpenChange, isControlled, getButtonProps, getDisclosureProps} = useDisclosure({
isOpen?: boolean;
defaultOpen?: boolean;
onClose?(): void;
onOpen?(): void;
onChange?(isOpen: boolean | undefined): void;
id?: string;
});
```
**示例:**
```tsx
import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Button, useDisclosure } from "@heroui/react";
export default function App() {
const {isOpen, onOpen, onOpenChange} = useDisclosure();
return (
<>
Open Modal
Title
Content
Close
>
);
}
```
### v3:useOverlayState
**API:**
```tsx
const state = useOverlayState({
isOpen?: boolean;
defaultOpen?: boolean;
onOpenChange?: (isOpen: boolean) => void;
});
// Returns:
// {
// isOpen: boolean;
// open(): void;
// close(): void;
// toggle(): void;
// setOpen(isOpen: boolean): void;
// }
```
**示例:**
```tsx
import { Modal, Button, useOverlayState } from "@heroui/react";
export default function App() {
const state = useOverlayState();
return (
Open Modal
{({close}) => (
<>
Title
Content
Close
>
)}
);
}
```
### 迁移指南
#### 基本迁移
**v2:**
```tsx
const {isOpen, onOpen, onClose, onOpenChange} = useDisclosure();
```
**v3:**
```tsx
const state = useOverlayState();
// Use state.open(), state.close(), state.toggle(), state.setOpen(boolean)
```
#### 受控状态
**v2:**
```tsx
const {isOpen, onOpenChange} = useDisclosure({
isOpen: controlledIsOpen,
onChange: (isOpen) => setControlledIsOpen(isOpen)
});
```
**v3:**
```tsx
const state = useOverlayState({
isOpen: controlledIsOpen,
onOpenChange: setControlledIsOpen
});
```
#### 非受控状态
**v2:**
```tsx
const {isOpen, onOpen, onClose} = useDisclosure({
defaultOpen: false
});
```
**v3:**
```tsx
const state = useOverlayState({
defaultOpen: false
});
// Use state.open(), state.close(), state.toggle()
```
### API 差异
| v2(useDisclosure) | v3(useOverlayState) | 说明 |
| ---------------------- | ------------------- | ----------- |
| `isOpen` | `isOpen` | 相同 |
| `onOpen()` | `open()` | 方法重命名 |
| `onClose()` | `close()` | 方法重命名 |
| `onOpenChange()` | `toggle()` | 新增的切换方法 |
| `onOpenChange`(prop) | `setOpen(boolean)` | API 不同 |
| `isControlled` | - | 已移除(由内部处理) |
| `getButtonProps()` | - | 已移除(改用复合组件) |
| `getDisclosureProps()` | - | 已移除(改用复合组件) |
### useOverlayState 的优势
* **更简洁的 API**:使用专用方法(`open()`、`close()`、`toggle()`),而非回调
* **更简单的状态管理**:在受控与非受控两种模式下都能无缝工作
* **更完善的 TypeScript 支持**:改进了类型推断和自动补全
* **与 React Aria 保持一致**:与 React Aria Components 的模式相符
### 替代方案:useState
对于简单的场景,你也可以直接使用 React 的 `useState`:
```tsx
import { useState } from "react";
import { Modal, Button } from "@heroui/react";
export default function App() {
const [isOpen, setIsOpen] = useState(false);
return (
setIsOpen(true)}>Open
{/* content */}
);
}
```
不过,`useOverlayState` 为常见操作提供了更简洁的 API 和专用方法。
## 已移除的 Hooks
v2 中的以下 Hooks 在 v3 中已被移除:
* **useDraggable**:已移除
* **useClipboard**:已移除
* **usePagination**:已移除
* **useToast**:已移除
## 总结
* **组件 Hooks**(`useSwitch`、`useInput` 等)→ 改用 **复合组件**
* **useDisclosure** → 改用 **useOverlayState** 来管理浮层状态
* **useOverlayState** 提供了更简洁的 API,包含 `open()`、`close()`、`toggle()` 与 `setOpen()` 方法
* **已移除的 Hooks**:`useDraggable`、`useClipboard`、`usePagination`、`useToast` 不再可用
* 对于简单的场景可以直接使用 `useState`,但 `useOverlayState` 在使用体验上更佳
有关具体组件的 Hooks 迁移示例,请参阅各个组件的迁移指南。
# 迁移
**Category**: react
**URL**: https://heroui.com/cn/docs/react/migration
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/migration/index.mdx
> 将 HeroUI v2 应用迁移到 v3 的完整指南
## 面向 AI 助手
以下是 AI 助手获取迁移文档的三种方式。***我们推荐使用 HeroUI Migration MCP 服务器***,并充分利用其 prompt 与工具,不过其它方式也都能为 agent 提供完整的文档。
| 对比项 | MCP Server | Agent Skills | AGENTS.md |
| -------- | ------------------------------------------------ | ---------------------------------------------------- | ---------------------------------------------- |
| **数据来源** | 远程端点 | 远程端点 | 本地文件 |
| **访问方式** | MCP 工具 | 脚本文件 | 读取本地文件 |
| **配置方式** | MCP 配置 | 安装命令 | `heroui-cli` 命令 |
| **更新** | 实时 | 实时 | 手动 |
| **离线** | ❌ | ❌ | ✅ |
| **工具** | MCP 工具 + prompt | 脚本 | ❌ |
| **指南** | [MCP Server →](/docs/react/migration/mcp-server) | [Agent Skills →](/docs/react/migration/agent-skills) | [AGENTS.md →](/docs/react/migration/agents-md) |
## 主要变化
* **依赖项**:将 React 升级到 v19+、HeroUI 包升级到 v3、Tailwind CSS 升级到 v4,并移除 Framer Motion
* **无需 Provider**:v3 不再需要 `HeroUIProvider`
* **组件 API 更新**:许多组件改用 React Aria Components 模式
* **复合组件**:全新的复合组件模式带来了更好的定制能力。详情请参阅各组件的迁移指南。
* **已移除的 Hooks**:v2 中的组件 Hooks(如 `useSwitch`、`useInput`)已被移除——请改用复合组件。`useDisclosure` 已被替换为 `useOverlayState`。详情请参阅 [Hooks 迁移指南](/docs/react/migration/hooks)。
* **配置变更**:从 Tailwind 配置中移除 `heroui()` 插件,更新 CSS 导入,并删除 `hero.ts` 文件
* **条目标识**:集合类组件(Dropdown、ListBox、Select、Accordion 等)在 v3 中改用 `id` 和 `textValue`;列表本身仍需保留 React 的 `key`。
### 条目标识与无障碍(key、id、textValue)
在 v2 中,集合类组件(Dropdown、ListBox、Select、Accordion 等)使用 **React 的 `key`** 作为条目标识。同一个值既驱动 React 的列表协调,又承担组件的选中/展开状态。在使用 React Aria Components 的 v3 中,这两种职责被拆分开:
* **`id`** — v3 在每个条目上使用显式的 **`id`** 属性来表示选中状态、焦点以及回调(例如 `selectedKeys`、`expandedKeys`、`onSelectionChange`)。请使用与你在 v2 中给 `key` 设置的相同(或等效)的值,这样状态和回调仍能正确指向对应的条目。
* **`textValue`** — 当条目的可见内容不是纯文本时(例如使用了 `Label`、图标或 `Description`),v3 需要在条目上提供 **`textValue`**。它用于屏幕阅读器播报和键入快速定位(type-ahead)。
* **`key`** — **继续在列表项上使用 React 的 `key`**。它仍然是 React 列表协调所必需的,且与 `id` 相互独立。
迁移时:为 v3 的 API 添加 `id`(必要时再加上 `textValue`),同时保留供 React 使用的 `key`。
## 迁移策略
如果不做特殊设置,HeroUI v2 与 v3 不能在同一个项目中共存。你可以选择以下两种迁移方式:
### 一次性完整迁移
**适用场景:** 能够集中投入时间、一次性完成迁移的项目。
**工作方式:**
* 先迁移所有组件代码(此阶段项目将无法正常运行)
* 将依赖项切换到 v3
* 完成样式迁移
**优点:**
* 配置更简单——无需复杂的共存配置
* 切换更干净——同一时间只有一个版本处于激活状态
* 由 Migration MCP 的 prompt 提供支持
**缺点:**
* 项目在迁移期间无法正常运行
* 必须在切换依赖之前完成所有组件的迁移
**开始迁移:** [完整迁移指南](/docs/react/migration/full-migration)
### 渐进式迁移
**适用场景:** 需要在迁移过程中保持可用的项目、希望分阶段逐步迁移的团队,以及按功能逐个迁移的大型代码库。
**工作方式:**
* 通过 pnpm 别名或组件包来设置共存
* 在保持项目可用的前提下,逐个迁移组件
* 完成迁移后再移除 v2 依赖项
**优点:**
* 项目在迁移期间始终可用
* 可以分阶段、按需逐步推进
* 可以将 v3 组件与 v2 并存测试
**缺点:**
* 初始配置更为复杂
* 可能出现样式冲突
* 需要同时管理两个版本
**开始迁移:** [渐进式迁移指南](/docs/react/migration/incremental-migration)
## 组件迁移参考
可以通过下表快速查找每个组件的迁移指南。点击「迁移指南」列中的链接,即可跳转到对应的详细迁移说明。
**组件开发状态**:标有 🔄 进行中或 📋 计划中的组件仍在开发中。可以查看[路线图](https://herouiv3.featurebase.app/roadmap)了解任务状态。这些组件的迁移指南将在开发完成后提供。
| v2 组件 | v3 组件 | 状态 | 迁移指南 |
| ---------------- | -------------------------- | ------ | ------------------------------------------------------------------------ |
| Accordion | Accordion | ✅ 可用 | [查看指南 →](/docs/react/migration/accordion) |
| Alert | Alert | ✅ 可用 | [查看指南 →](/docs/react/migration/alert) |
| Autocomplete | ComboBox | ✅ 已重命名 | [查看指南 →](/docs/react/migration/autocomplete) |
| Avatar | Avatar | ✅ 可用 | [查看指南 →](/docs/react/migration/avatar) |
| Badge | Badge | ✅ 可用 | [查看指南 →](/docs/react/migration/badge) |
| Breadcrumbs | Breadcrumbs | ✅ 可用 | [查看指南 →](/docs/react/migration/breadcrumbs) |
| Button | Button | ✅ 可用 | [查看指南 →](/docs/react/migration/button) |
| ButtonGroup | ButtonGroup | ✅ 可用 | [查看指南 →](/docs/react/migration/button-group) |
| Calendar | Calendar | ✅ 可用 | [查看指南 →](/docs/react/migration/calendar) |
| Card | Card | ✅ 可用 | [查看指南 →](/docs/react/migration/card) |
| Checkbox | Checkbox | ✅ 可用 | [查看指南 →](/docs/react/migration/checkbox) |
| CheckboxGroup | CheckboxGroup | ✅ 可用 | [查看指南 →](/docs/react/migration/checkbox-group) |
| Chip | Chip | ✅ 可用 | [查看指南 →](/docs/react/migration/chip) |
| Code | ❌ | ❌ 已移除 | [查看指南 →](/docs/react/migration/code) |
| DateInput | DateField | ✅ 已重命名 | [查看指南 →](/docs/react/migration/dateinput) |
| DatePicker | DatePicker | ✅ 可用 | [查看指南 →](/docs/react/migration/date-picker) |
| DateRangePicker | DateRangePicker | ✅ 可用 | [查看指南 →](/docs/react/migration/date-range-picker) |
| TimeInput | TimeField | ✅ 已重命名 | [查看指南 →](/docs/react/migration/timeinput) |
| Divider | Separator | ✅ 已重命名 | [查看指南 →](/docs/react/migration/divider) |
| Drawer | Drawer | ✅ 可用 | [查看指南 →](/docs/react/migration/drawer) |
| Dropdown | Dropdown | ✅ 可用 | [查看指南 →](/docs/react/migration/dropdown) |
| Form | Form | ✅ 可用 | [查看指南 →](/docs/react/migration/form) |
| Image | ❌ | ❌ 已移除 | [查看指南 →](/docs/react/migration/image) |
| Input | TextField、Input、InputGroup | ✅ 可用 | [查看指南 →](/docs/react/migration/input) |
| InputOTP | InputOTP | ✅ 可用 | [查看指南 →](/docs/react/migration/input-otp) |
| Kbd | Kbd | ✅ 可用 | [查看指南 →](/docs/react/migration/kbd) |
| Link | Link | ✅ 可用 | [查看指南 →](/docs/react/migration/link) |
| Listbox | ListBox | ✅ 可用 | [查看指南 →](/docs/react/migration/listbox) |
| Modal | Modal | ✅ 可用 | [查看指南 →](/docs/react/migration/modal) |
| Navbar | ❌ | ❌ 已移除 | [查看指南 →](/docs/react/migration/navbar) |
| NumberInput | NumberField | ✅ 已重命名 | [查看指南 →](/docs/react/migration/numberinput) |
| Pagination | Pagination | ✅ 可用 | [查看指南 →](/docs/react/migration/pagination) |
| Popover | Popover | ✅ 可用 | [查看指南 →](/docs/react/migration/popover) |
| Progress | ProgressBar | ✅ 已重命名 | [查看指南 →](/docs/react/migration/progress) |
| CircularProgress | ProgressCircle | ✅ 已重命名 | [查看指南 →](/docs/react/migration/circular-progress) |
| Radio | Radio | ✅ 可用 | [查看指南 →](/docs/react/migration/radio) |
| RadioGroup | RadioGroup | ✅ 可用 | [查看指南 →](/docs/react/migration/radio-group) |
| RangeCalendar | RangeCalendar | ✅ 可用 | [查看指南 →](/docs/react/migration/range-calendar) |
| Ripple | ❌ | ❌ 已移除 | [参见 Button 的水波纹效果 →](/docs/react/components/button#adding-ripple-effect) |
| ScrollShadow | ScrollShadow | ✅ 可用 | [查看指南 →](/docs/react/migration/scroll-shadow) |
| Select | Select | ✅ 可用 | [查看指南 →](/docs/react/migration/select) |
| Skeleton | Skeleton | ✅ 可用 | [查看指南 →](/docs/react/migration/skeleton) |
| Slider | Slider | ✅ 可用 | [查看指南 →](/docs/react/migration/slider) |
| Snippet | ❌ | ❌ 已移除 | [查看指南 →](/docs/react/migration/snippet) |
| Spacer | ❌ | ❌ 已移除 | [查看指南 →](/docs/react/migration/spacer) |
| Spinner | Spinner | ✅ 可用 | [查看指南 →](/docs/react/migration/spinner) |
| Switch | Switch | ✅ 可用 | [查看指南 →](/docs/react/migration/switch) |
| Table | Table | ✅ 可用 | [查看指南 →](/docs/react/migration/table) |
| Tabs | Tabs | ✅ 可用 | [查看指南 →](/docs/react/migration/tabs) |
| Toast | Toast | ✅ 可用 | [查看指南 →](/docs/react/migration/toast) |
| Tooltip | Tooltip | ✅ 可用 | [查看指南 →](/docs/react/migration/tooltip) |
| User | ❌ | ❌ 已移除 | [查看指南 →](/docs/react/migration/user) |
## v3 中新增的组件
v3 引入了一系列 v2 中尚未提供的全新组件:
| 组件 | 用途 | 文档 |
| --------------- | -------------------------------------------------------------------- | ------------------------------------------------- |
| TextField | 增强型文本输入框,支持 label 与 description | [查看文档 →](/docs/react/components/text-field) |
| TextArea | 多行文本输入组件 | [查看文档 →](/docs/react/components/text-area) |
| AlertDialog | 用于确认与提醒的模态对话框 | [查看文档 →](/docs/react/components/alert-dialog) |
| Label | 无障碍的表单标签组件 | [查看文档 →](/docs/react/components/label) |
| Description | 表单字段的辅助说明文本 | [查看文档 →](/docs/react/components/description) |
| FieldError | 表单字段的错误信息显示 | [查看文档 →](/docs/react/components/field-error) |
| Fieldset | 对相关表单字段进行分组 | [查看文档 →](/docs/react/components/fieldset) |
| InputGroup | 将多个输入框组合在一起 | [查看文档 →](/docs/react/components/input-group) |
| Surface | 带有层级样式的容器组件 | [查看文档 →](/docs/react/components/surface) |
| Disclosure | 可展开 / 可折叠的内容区域 | [查看文档 →](/docs/react/components/disclosure) |
| DisclosureGroup | 用于管理多个 Disclosure 区域的复合组件 | [查看文档 →](/docs/react/components/disclosure-group) |
| SearchField | 带清除按钮与可选加载状态的搜索输入框 | [查看文档 →](/docs/react/components/search-field) |
| DateField | 配合日历选择器的日期输入框 | [查看文档 →](/docs/react/components/date-field) |
| TimeField | 时间输入组件 | [查看文档 →](/docs/react/components/time-field) |
| Tag、TagGroup | 用于选择或展示的 Tag 与 TagGroup | [查看文档 →](/docs/react/components/tag-group) |
| ColorPicker | 颜色选择(ColorArea、ColorField、ColorSlider、ColorSwatch、ColorSwatchPicker) | [查看文档 →](/docs/react/components/color-picker) |
| CloseButton | 用于关闭或解除浮层的触发按钮 | [查看文档 →](/docs/react/components/close-button) |
| ErrorMessage | 表单字段错误信息展示(基于 React Aria 集成) | [查看文档 →](/docs/react/components/error-message) |
## 其他迁移指南
* **[Hooks 迁移指南](/docs/react/migration/hooks)**:将 Hooks 从 v2 迁移到 v3 的详细说明
* **[样式迁移指南](/docs/react/migration/styling)**:更新工具类、颜色 token 与组件样式的综合指南
## 获取帮助
如果你在迁移过程中遇到问题:
1. 查看 [v3 文档](/docs/react)
2. 查阅具体组件的迁移指南
3. 在 [GitHub Discussions](https://github.com/heroui-inc/heroui/discussions) 中查找或提问
4. 加入 [Discord 社区](https://discord.gg/9b6yyZKmH4)
# 样式与主题
**Category**: react
**URL**: https://heroui.com/cn/docs/react/migration/styling
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/migration/styling.mdx
> 从 HeroUI v2 到 v3 的样式变更与主题系统迁移完整指南
本指南涵盖了 HeroUI v2 与 v3 之间所有与样式相关的变更,包括工具类、组件样式、主题系统架构以及视觉差异。具体组件的 API 变更请参阅各个组件的迁移指南。
**注:** v3 已将 `classNames` 这一对象类型的 prop 替换为标准的 React `className` prop。所有组件现在都使用标准的 React `className` prop,而不再使用 v2 中的 `classNames` 对象属性。
## 概述
HeroUI v3 对样式系统进行了重大变更:
* **CSS 优先架构**:以纯 CSS 文件取代 Tailwind 插件
* **标准 Tailwind 工具类**:以标准 Tailwind 类取代自定义工具类
* **CSS 变量**:全新的 CSS 变量命名与结构
* **组件样式**:调整了默认尺寸、间距与视觉表现
* **无需插件**:移除了对 Tailwind 插件配置的依赖
* **颜色系统重构**:语义颜色被重新组织(`primary` → `accent`,移除 `secondary`,移除数字色阶)
* **移除 Content 颜色**:`content1-4` 由 `surface` 与 `overlay` 体系替代
## 快速参考
### 工具类对照
| v2 工具类 | v3 对应类 | 说明 |
| ---------------------------- | --------------------------- | ----------------------------------- |
| `text-tiny` | `text-xs` | 字体大小:0.75rem → 0.75rem(相同) |
| `text-small` | `text-sm` | 字体大小:0.875rem → 0.875rem(相同) |
| `text-medium` | `text-base` | 字体大小:1rem → 1rem(相同) |
| `text-large` | `text-lg` | 字体大小:1.125rem → 1.125rem(相同) |
| `rounded-small` | `rounded-sm` | 圆角:8px → 4px(不同) |
| `rounded-medium` | `rounded-md` | 圆角:12px → 6px(不同) |
| `rounded-large` | `rounded-lg` | 圆角:14px → 8px(不同) |
| `border-small` | `border` | 边框宽度:1px → 1px(使用标准 Tailwind) |
| `border-medium` | `border-2` | 边框宽度:2px → 2px(使用标准 Tailwind) |
| `border-large` | `border-[3px]` | 边框宽度:3px → 3px(使用任意值) |
| `bg-content1` | `bg-surface` 或 `bg-overlay` | Content 颜色已移除,请改用 surface / overlay |
| `bg-content2` | `bg-surface-secondary` | Content 颜色已移除,请改用 surface 层级 |
| `bg-primary` | `bg-accent` | `primary` 已重命名为 `accent` |
| `bg-secondary` | `bg-default` | `secondary` 颜色已移除,请改用 `default` |
| `bg-primary-50` | `bg-accent-soft` | 数字色阶已移除 |
| `bg-primary-100` | `bg-accent-soft` | 数字色阶已移除 |
| `text-primary-600` | `text-accent` | 数字色阶已移除 |
| `.transition-background` | 标准 CSS 过渡 | 已移除的工具类 |
| `.transition-colors-opacity` | 标准 CSS 过渡 | 已移除的工具类 |
## 工具类迁移
### 文本工具类
HeroUI v2 提供了一组自定义的文本尺寸工具类,并映射到 CSS 变量。v3 改用标准的 Tailwind 文本尺寸类。
**v2 文本工具类:**
```tsx
// v2 - Custom utilities with CSS variables
Tiny text
Small text
Medium text
Large text
```
**v3 文本工具类:**
```tsx
// v3 - Standard Tailwind classes
Tiny text
Small text
Medium text
Large text
```
**对照详情:**
| v2 类 | 字体大小 | 行高 | v3 类 | 字体大小 | 行高 |
| ------------- | -------------- | ------------- | ----------- | -------------- | ------------- |
| `text-tiny` | 0.75rem(12px) | 1rem(16px) | `text-xs` | 0.75rem(12px) | 1rem(16px) |
| `text-small` | 0.875rem(14px) | 1.25rem(20px) | `text-sm` | 0.875rem(14px) | 1.25rem(20px) |
| `text-medium` | 1rem(16px) | 1.5rem(24px) | `text-base` | 1rem(16px) | 1.5rem(24px) |
| `text-large` | 1.125rem(18px) | 1.75rem(28px) | `text-lg` | 1.125rem(18px) | 1.75rem(28px) |
### 圆角工具类
v2 使用了自定义的圆角工具类(`rounded-small`、`rounded-medium`、`rounded-large`),并映射到 CSS 变量。v3 改用标准的 Tailwind 圆角类,但实际取值有所不同。
**v2 圆角:**
```tsx
// v2 - Custom utilities
Small radius
Medium radius
Large radius
```
**v3 圆角:**
```tsx
// v3 - Standard Tailwind classes
Small radius
Medium radius
Large radius
```
**取值对比:**
| v2 类 | v2 取值 | v3 类 | v3 取值 | 差异 |
| ---------------- | -------------- | ------------ | ------------- | -- |
| `rounded-small` | 8px(0.5rem) | `rounded-sm` | 4px(0.25rem) | 更小 |
| `rounded-medium` | 12px(0.75rem) | `rounded-md` | 6px(0.375rem) | 更小 |
| `rounded-large` | 14px(0.875rem) | `rounded-lg` | 8px(0.5rem) | 更小 |
**注意:** v3 默认的圆角取值更小。如果你需要精确还原 v2 的取值,请使用任意值:
```tsx
// Match v2 rounded-small (8px)
Custom radius
// Match v2 rounded-medium (12px)
Custom radius
// Match v2 rounded-large (14px)
Custom radius
```
### 边框宽度工具类
v2 提供了自定义的边框宽度工具类(`border-small`、`border-medium`、`border-large`)。v3 改用标准的 Tailwind 边框宽度类。
**v2 边框宽度:**
```tsx
// v2 - Custom utilities
1px border
2px border
3px border
```
**v3 边框宽度:**
```tsx
// v3 - Standard Tailwind classes
1px border
2px border
3px border
```
**对照:**
| v2 类 | 宽度 | v3 类 | 宽度 |
| --------------- | --- | -------------- | -------- |
| `border-small` | 1px | `border` | 1px |
| `border-medium` | 2px | `border-2` | 2px |
| `border-large` | 3px | `border-[3px]` | 3px(任意值) |
### 过渡工具类
v2 为常见的动画模式提供了一组自定义的过渡工具类,默认持续时间为 250ms。v3 移除了这些工具类,转而推荐使用标准的 Tailwind `transition-*` 工具类,由你显式指定要应用过渡的属性。
**v2 过渡工具类:**
v2 提供了默认持续时间为 250ms、缓动函数为 `ease` 的自定义过渡工具类。下表展示了每个工具类对应的 CSS 过渡属性:
| v2 工具类 | 过渡属性 |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `.transition-background` | `background` |
| `.transition-colors-opacity` | `color, background-color, border-color, text-decoration-color, fill, stroke, opacity` |
| `.transition-width` | `width` |
| `.transition-height` | `height` |
| `.transition-size` | `width, height` |
| `.transition-left` | `left` |
| `.transition-transform-opacity` | `transform, scale, opacity rotate` |
| `.transition-transform-background` | `transform, scale, background` |
| `.transition-transform-colors` | `transform, scale, color, background, background-color, border-color, text-decoration-color, fill, stroke` |
| `.transition-transform-colors-opacity` | `transform, scale, color, background, background-color, border-color, text-decoration-color, fill, stroke, opacity` |
**注意:** 这些工具类在 v3 中不再可用。请使用 Tailwind 标准的 `transition-*` 工具类,并显式指定要应用过渡的属性。
### 其他工具类
**滚动条工具类:**
v2 提供了 `.scrollbar-hide` 和 `.scrollbar-default` 工具类。v3 现在通过 `@heroui/styles` 暴露基于标准属性的滚动条工具类:`scrollbar`、`scrollbar-thin`、`scrollbar-default` 和 `scrollbar-none`。如需按子树控制,可在祖先元素上使用 `data-scrollbar="thin"`、`data-scrollbar="default"` 或 `data-scrollbar="none"`。
**动画工具类:**
v2 提供了 spinner 相关的动画工具类(如 `.spinner-bar-animation`、`.spinner-dot-animation` 等)。在 v3 中,这些动画由组件内部处理,不再作为公开的工具类暴露。
**其他自定义工具类:**
v2 中还包含一些自定义工具类,例如:
* `.leading-inherit` → 改用 `leading-[inherit]`
* `.tap-highlight-transparent` → 改用 `[-webkit-tap-highlight-color:transparent]`
* `.input-search-cancel-button-none` → 如有需要,请使用自定义 CSS
## 主题系统架构
### v2:基于插件的体系
v2 采用了 Tailwind CSS 插件方式:
1. **生成工具类**:通过 JavaScript 创建自定义工具类
2. **CSS 变量**:通过插件注入 CSS 变量
3. **主题配置**:需要在 `tailwind.config.js` 中进行配置
4. **构建时生成**:工具类在构建时生成
**v2 配置:**
```js
// tailwind.config.js
const {heroui} = require("@heroui/react");
module.exports = {
plugins: [
heroui({
layout: {
fontSize: {
tiny: "0.75rem",
small: "0.875rem",
medium: "1rem",
large: "1.125rem",
},
radius: {
small: "8px",
medium: "12px",
large: "14px",
},
},
themes: {
light: {
colors: {
primary: {
// color definitions
},
},
},
},
}),
],
};
```
### v3:CSS 优先体系
v3 采用纯 CSS 的方式:
1. **CSS 文件**:样式直接定义在 CSS 文件中(位于 `packages/styles/`)
2. **CSS 变量**:变量在 CSS 中定义,而非由插件生成
3. **无需插件**:不再需要 Tailwind 插件
4. **基于导入**:通过 CSS `@import` 引入样式
**v3 配置:**
```css
/* globals.css */
@import "tailwindcss";
@import "@heroui/styles";
```
**无需 Tailwind 配置:**
如果你只使用 HeroUI,可以完全删除 `tailwind.config.js`。如果你已有自定义的 Tailwind 配置,请保留它,但移除其中的 HeroUI 插件。
### 架构对比
| 对比项 | v2 | v3 |
| ----------- | ----------------------- | --------- |
| **样式方案** | Tailwind 插件(JavaScript) | CSS 文件 |
| **工具类生成方式** | 由插件在构建时生成 | 预定义的 CSS |
| **CSS 变量** | 由插件生成 | 在 CSS 中定义 |
| **配置方式** | `tailwind.config.js` | CSS 导入 |
| **定制方式** | 插件配置 | 覆盖 CSS 变量 |
| **构建依赖** | 需要插件 | 无需插件 |
## CSS 变量与设计 token
### 变量命名变更
v2 采用 `--heroui-{property}-{scale}` 的命名模式,而 v3 改用 `--{property}` 或 `--color-{property}`。
**v2 CSS 变量:**
```css
--heroui-font-size-tiny: 0.75rem;
--heroui-font-size-small: 0.875rem;
--heroui-radius-small: 8px;
--heroui-radius-medium: 12px;
--heroui-border-width-medium: 2px;
--heroui-disabled-opacity: 0.5;
```
**v3 CSS 变量:**
```css
/* Typography - handled by Tailwind */
/* No custom font-size variables */
/* Radius */
--radius-xs: calc(var(--radius) * 0.25);
--radius-sm: calc(var(--radius) * 0.5);
--radius-md: calc(var(--radius) * 0.75);
--radius-lg: calc(var(--radius) * 1);
--radius-xl: calc(var(--radius) * 1.5);
/* Colors */
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-accent: var(--accent);
--color-muted: var(--muted);
/* Opacity */
--disabled-opacity: 0.5;
```
### 颜色系统变更
**v2 颜色结构:**
```css
--heroui-primary: 210 100% 50%;
--heroui-primary-50: 210 100% 95%;
--heroui-primary-100: 210 100% 90%;
/* ... more shades ... */
```
**v3 颜色结构:**
```css
--accent: oklch(0.6204 0.195 253.83);
--accent-foreground: var(--snow);
--accent-hover: color-mix(in oklab, var(--accent) 90%, var(--accent-foreground) 10%);
```
**主要差异:**
1. **颜色格式**:v2 使用 HSL,v3 使用 OKLCH
2. **命名**:v2 使用数字色阶(50-900),v3 使用语义命名
3. **计算颜色**:v3 通过 `color-mix()` 计算悬停等状态色
4. **前景色**:v3 显式定义了前景色
5. **primary → accent**:`primary` 颜色已重命名为 `accent`
6. **移除 secondary 颜色**:v2 中的 `secondary` 语义颜色(紫色)已被移除
7. **移除数字色阶**:`primary-50`、`primary-100` 等数字色阶不再存在
### primary → accent 重命名
v2 使用 `primary` 作为主品牌色。v3 将其重命名为 `accent`,使语义更加清晰。
**v2 中的 primary 颜色:**
```tsx
// v2 - Primary color with numbered scales
Primary Button
Primary background
Light primary
Lighter primary
Primary text
```
**v3 中的 accent 颜色:**
```tsx
// v3 - Accent color (no numbered scales)
Primary Button
Accent background
Soft accent
Accent text
```
**迁移:**
| v2 类 | v3 对应类 | 说明 |
| ------------------ | ---------------- | ------------ |
| `bg-primary` | `bg-accent` | 基础 accent 色 |
| `text-primary` | `text-accent` | accent 文本颜色 |
| `bg-primary-50` | `bg-accent-soft` | 浅色 accent 变体 |
| `bg-primary-100` | `bg-accent-soft` | 浅色 accent 变体 |
| `bg-primary-500` | `bg-accent` | 基础 accent 色 |
| `text-primary-600` | `text-accent` | accent 文本颜色 |
| `border-accent` | `border-accent` | accent 边框 |
**注意:** v3 不再提供数字色阶(`-50`、`-100`、`-200` 等)。请使用语义化的变体(如 `-soft`、`-hover`),或自定义的 Tailwind 类。
### secondary 颜色已移除
v2 提供了 `secondary` 语义颜色(紫色),该颜色已在 v3 中移除。名为「secondary」的组件变体现在改用其他颜色。
**v2 中的 secondary 颜色:**
```tsx
// v2 - Secondary as a semantic color (purple)
Secondary Button
Secondary background
Light secondary
Secondary text
```
**v3 中的 secondary 变体:**
```tsx
// v3 - Secondary is a variant, not a color
Secondary Button
Default background (used by secondary variant)
Accent text
```
**迁移:**
| v2 类 | v3 对应类 | 说明 |
| ------------------ | --------------- | ------------------------- |
| `bg-secondary` | `bg-default` | secondary 变体改用 default 颜色 |
| `text-secondary` | `text-accent` | 使用 accent 进行强调 |
| `bg-secondary-50` | `bg-default` | 改用 default 颜色 |
| `border-secondary` | `border-accent` | 使用 accent 边框 |
**注意:** 在 v3 中,「secondary」指的是组件变体样式(例如 `button--secondary`),而不是颜色 token。secondary 变体通常使用 `bg-default` 和 `text-accent`。
### 数字色阶已移除
v2 为所有语义颜色都提供了 50–900 的数字色阶。v3 移除了这些数字色阶,改用语义化的变体与计算得出的颜色。
**v2 数字色阶:**
```tsx
// v2 - Numbered color scales
Lightest
Lighter
Light
Base
Dark
Darkest
```
**v3 语义化变体:**
```tsx
// v3 - Semantic variants and calculated colors
Soft variant
Base color
Hover state
```
**迁移:**
* **浅色调**(`-50`、`-100`、`-200`):改用 `-soft` 变体或自定义的 Tailwind 透明度类
* **基础色**(`-500`):直接使用基础色名(`bg-accent`、`bg-danger` 等)
* **深色调**(`-600`、`-700`、`-800`、`-900`):改用 hover 变体或自定义的 Tailwind 类
### Content 颜色已移除
v2 提供了 `content1`、`content2`、`content3` 和 `content4` 颜色,用于分层背景。这些颜色已在 v3 中移除,并由语义化的 surface 颜色替代。
**v2 Content 颜色:**
```tsx
// v2 - Content colors for layered backgrounds
Base content
Secondary content
Tertiary content
Quaternary content
```
**v3 Surface 颜色:**
```tsx
// v3 - Surface colors for non-overlay components
Base surface
Secondary surface
Tertiary surface
Quaternary surface
// v3 - Overlay colors for floating components
Overlay (tooltips, popovers, modals)
```
**迁移对照:**
| v2 类 | v3 对应类 | 用法 |
| ------------- | ----------------------- | ----------------------------- |
| `bg-content1` | `bg-surface` | 非浮层组件(Card、Accordion 等) |
| `bg-content1` | `bg-overlay` | 浮层组件(Tooltip、Popover、Modal 等) |
| `bg-content2` | `bg-surface-secondary` | 二级 surface 层级 |
| `bg-content3` | `bg-surface-tertiary` | 三级 surface 层级 |
| `bg-content4` | `bg-surface-quaternary` | 四级 surface 层级 |
**主要变化:**
1. **语义命名**:`content1-4` 已替换为 `surface` 与 `overlay`,使语义更清晰
2. **针对不同组件**:页面级组件使用 `bg-surface`,浮层组件使用 `bg-overlay`
3. **自动计算**:surface 的各级(`secondary`、`tertiary`、`quaternary`)通过 `color-mix()` 从基础 `surface` 颜色自动计算得出
### 间距与布局 token
**v2 布局 token:**
```css
--heroui-divider-weight: 1px;
--heroui-disabled-opacity: 0.5;
--heroui-hover-opacity: 0.8;
```
**v3 布局 token:**
```css
--border-width: 0px;
--field-border-width: var(--border-width);
--disabled-opacity: 0.5;
--cursor-interactive: pointer;
--cursor-disabled: not-allowed;
--radius: 0.5rem;
--field-radius: calc(var(--radius) * 1.5);
```
### 阴影 token
**v2 阴影:**
```css
--heroui-box-shadow-small: 0px 0px 5px 0px rgb(0 0 0 / 0.02), ...;
--heroui-box-shadow-medium: 0px 0px 15px 0px rgb(0 0 0 / 0.03), ...;
--heroui-box-shadow-large: 0px 0px 30px 0px rgb(0 0 0 / 0.04), ...;
```
**v3 阴影:**
```css
--surface-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.04), ...;
--overlay-shadow: 0 4px 16px 0 rgba(24, 24, 27, 0.08), ...;
--field-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.04), ...;
```
**主要变化:**
1. **语义命名**:v3 使用语义名称(`surface-shadow`、`overlay-shadow`),而非按尺寸命名
2. **针对不同组件**:阴影与组件类型(surface、overlay、field)相绑定
3. **深色模式**:在 v3 中,深色模式下的阴影为透明
## 视觉差异
### 对齐变化
**Button 对齐:**
* v2:图标与文本通过 `items-center justify-center` 对齐
* v3:对齐方式相同,但加入了响应式高度调整
**Input 对齐:**
* v2:文本通过 `text-left` 对齐
* v3:对齐方式相同,但内边距的调整可能影响视觉平衡
### 间距变化
**组件内边距:**
v3 中大多数组件的内边距都有所增加:
* **Card**:12px → 16px
* **Button**:内边距相近,但高度改为响应式
* **Input**:新增垂直内边距(`py-2`)
**间隙(gap):**
v3 使用更一致的间隙:
* **Card**:页眉、内容、页脚之间使用 `gap-3`
* **Button**:图标与文字之间使用 `gap-2`
* **Chip**:元素之间使用 `gap-1.5`
### 尺寸变化
**Button 高度:**
* **Small**:32px → 36px(移动端)/ 32px(桌面端)
* **Medium**:40px → 40px(移动端)/ 36px(桌面端)
* **Large**:48px → 44px(移动端)/ 40px(桌面端)
**Input 高度:**
* **Medium**:40px → 36px(默认值,且为唯一可用尺寸)
### 圆角变化
**默认圆角:**
* v2:组件默认使用 `rounded-medium`(12px)
* v3:组件使用更大的圆角值:
* Button:`rounded-3xl`(24px)
* Card:`rounded-3xl`(24px)
* Chip:`rounded-2xl`(16px)
* Input:`rounded-field`(通常为 12–16px)
### 颜色表现变化
**颜色系统:**
* v2:HSL 颜色格式
* v3:OKLCH 颜色格式(在感知上更均匀)
**默认颜色:**
* v2:`primary`、`secondary`、`success`、`warning`、`danger`
* v3:`accent`(替代 `primary`)、`success`、`warning`、`danger`
**Muted 颜色:**
* v2:使用 `foreground-400`、`foreground-500` 表示弱化文本
* v3:使用 `muted` 颜色 token 表示弱化文本
## 迁移示例
### 工具类迁移
**示例:文本工具类**
```tsx
```
```tsx
```
### 圆角迁移
**示例:还原 v2 的圆角取值**
```tsx
Content
```
```tsx
{/* Option 1: Use standard Tailwind (smaller radius) */}
Content
{/* Option 2: Match exact v2 value (12px) */}
Content
```
### 主题定制迁移
**示例:自定义颜色**
```js
// tailwind.config.js
const {heroui} = require("@heroui/react");
module.exports = {
plugins: [
heroui({
themes: {
light: {
colors: {
primary: {
DEFAULT: "#006FEE",
50: "#E6F1FE",
// ... more shades
},
},
},
},
}),
],
};
```
```css
/* globals.css */
@import "tailwindcss";
@import "@heroui/styles";
:root {
--accent: oklch(0.6204 0.195 253.83);
--accent-foreground: oklch(0.9911 0 0);
}
```
## 最佳实践
1. **优先使用标准 Tailwind**:相比自定义工具类,优先使用标准的 Tailwind 工具类
2. **还原 v2 取值**:如果需要精确还原 v2 的视觉效果,请使用任意值
3. **响应式测试**:v3 支持响应式尺寸——请在多种屏幕尺寸下进行测试
4. **更新 CSS 变量**:自定义时请通过覆盖 CSS 变量来实现,而非修改 Tailwind 配置
5. **查阅组件文档**:API 变更请参阅各个组件的迁移指南
## 相关指南
* [迁移总指南](/docs/react/migration)
* [主题文档](/docs/react/getting-started/handbook/theming)
* [样式指南](/docs/react/getting-started/handbook/styling)
# 所有组件(Native)
**Category**: native
**URL**: https://heroui.com/cn/docs/native/components
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/components/index.mdx
> 浏览 HeroUI Native 提供的全部组件;更多组件将陆续推出。
## 按钮
## 集合
## 控件
## 表单
## 导航
## 浮层
## 反馈
## 布局
## 媒体
## 数据展示
## 工具
# 所有版本
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/index.mdx
> HeroUI v3 的所有更新与变更,包含新功能、修复以及破坏性变更。
**正在使用 AI 助手?** 只需对它说一句「Hey Cursor,把 HeroUI 升级到最新版本」,AI 助手就会自动对比版本并应用必要的变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 最新版本
### v3.2.5
**2026 年 9 月 8 日**
补丁版本:[Toast](/docs/components/toast) 支持堆叠并在悬停时展开,[Select](/docs/components/select) 新增 `ClearButton`,[Tabs](/docs/components/tabs) 新增 `align` 变体,`@heroui/react` 再导出 `Pressable`、`Focusable`、`OverlayTriggerStateContext` 与 `DisclosureStateContext`,React Aria 升级到 `1.21.0`(`react-aria@3.52.0`)。同时修复了嵌套 `data-theme` 作用域与 Shadow DOM 中的主题 token、导出变体上的原生 `:focus-visible` 焦点环、Modal 级浮层被关闭中的 Popover 遮挡等问题,以及 [ScrollShadow](/docs/components/scroll-shadow)、[Table](/docs/components/table)、[Drawer](/docs/components/drawer)、[NumberField](/docs/components/number-field)、[Accordion](/docs/components/accordion)、[Label](/docs/components/label) 与 [Tag](/docs/components/tag) 的若干问题。
[阅读完整发布说明 →](/docs/react/releases/v3-2-5)
### v3.2.4
**2026 年 8 月 4 日**
补丁版本:[Autocomplete](/docs/components/autocomplete) 弹层不再裁剪末尾选项,`scroll="outside"` 的 [Modal](/docs/components/modal) 重新支持点击遮罩关闭,[Tabs](/docs/components/tabs) 的箭头滚动会精确停在边缘,`tailwind-variants` 升级到 `3.3.1` 以修复重新渲染后变体修饰符回退到错误类名的问题,React Aria 升级到 `1.20.0`(`react-aria@3.51.0`),并为 `@heroui/react` 添加了行为测试套件。
[阅读完整发布说明 →](/docs/react/releases/v3-2-4)
### v3.2.3
**2026 年 7 月 30 日**
补丁版本:[ComboBox](/docs/components/combo-box) 新增多选支持,样式采用逻辑 CSS 属性以更好地支持 RTL,`tailwind-variants` 升级到 `3.3.0`,并修复 `ScrollShadow`、`Spinner`、`InputOTP`、`Table` 以及 accent `Button` 焦点样式的问题。
[阅读完整发布说明 →](/docs/react/releases/v3-2-3)
### v3.2.2
**2026 年 6 月 19 日**
补丁版本:升级到 React Aria `1.19.0`(`react-aria@3.50.0`),为 `Tabs.ListContainer` 添加溢出滚动,修复清除/关闭按钮意外提交表单,以及 `Checkbox`、`Radio` 和 `Switch` 中视觉隐藏输入框导致的溢出滚动。
[阅读完整发布说明 →](/docs/react/releases/v3-2-2)
### v3.2.1
**2026 年 6 月 17 日**
补丁版本:`@heroui/react` 不再内置自己的 `react-aria` 副本。`react-aria` 的子路径在 Rollup 构建中被外部化,使消费方解析到项目中安装的单一 `react-aria`,而非内联副本。同时修复了 `SwitchGroup` 横向布局。
[阅读完整发布说明 →](/docs/react/releases/v3-2-1)
### v3.2.0
**2026 年 6 月 6 日**
基于 React Aria 1.18 的 Calendar 周/日视图、重做的年份选择器与范围日历演示,新增 Tooltip 延迟主题变量,并纳入随之发布的补丁修复。破坏性变更:`Radio`、`Checkbox`、`Switch` 改为显式的 `*.Content` 组合(控件嵌套进 `*.Content`,标签为纯文本、不嵌套 ``,帮助文本变为兄弟节点)。
[阅读完整发布说明 →](/docs/react/releases/v3-2-0)
### v3.1.0
**2026 年 5 月 25 日**
小版本发布:新增中文 React 文档与本地化示例,加入更可访问的 soft foreground 令牌和 vibrant palette 选项,统一滚动条系统,修复 `useTheme`、Toast、Fieldset、Link、浮层问题,并改进 Table、Picker 与 MenuItem 的 RTL 支持。
[阅读完整发布说明 →](/docs/react/releases/v3-1-0)
### v3.0.5
**2026 年 5 月 15 日**
补丁版本:`Text` 重命名为 `Typography` 以解决 `tailwind-merge` 冲突(⚠️ **破坏性变更**),派生颜色令牌重构为无前缀源变量,Checkbox 与 Radio 的 field-border 边框样式对齐,Calendar 悬停改用 `accent-soft-foreground` 以提升可读性,并新增 CLI 文档页。
[阅读完整发布说明 →](/docs/react/releases/v3-0-5)
### v3.0.4
**2026 年 5 月**
补丁版本:从 HeroUI Pro 移植的全新 `Text` 复合组件、文档主题选择器、在 45+ 个组件 CSS 文件中采用 `min()` 上限约束的圆角令牌、重做的 Table 聚焦环,以及对 Checkbox、Autocomplete、Tooltip 与表单字段内边距的修复。
[阅读完整发布说明 →](/docs/react/releases/v3-0-4)
### v3.0.3
**2026 年 4 月 17 日**
补丁版本:升级到 React Aria Components 1.17(合并依赖、安装更快、Table 支持可展开行),为 Vite 与 CRA 提供 `useTheme` Hook,为轻量级组件提供 DOM 多态的 render prop,并修复了 NumberField 的重置问题以及嵌套 Tabs 的样式问题。
[阅读完整发布说明 →](/docs/react/releases/v3-0-3)
### v3.0.2
**2026 年 4 月 3 日**
修复了多个 bug,Drawer 过渡更加平滑,新增了 `--backdrop` 主题变量,并优化了 trigger、arrow 与 Tag 的样式。修复了 Autocomplete 弹出层的宽度跟踪问题,浮层触发器现在使用 `inline-block`,Tag 在间距与无障碍方面也有所改进。
[阅读完整发布说明 →](/docs/react/releases/v3-0-2)
### v3.0.0
**2026 年 3 月**
面向 React 与 React Native 的彻底重写。包含 75+ Web 组件、37 个原生组件、Tailwind CSS v4、React Aria、复合组件架构、基于 OKLCH token 的 CSS 优先主题、通过 `data-reduce-motion` 控制动画,并面向利用 MCP Server、Agent Skills 与 LLMs.txt 的 AI 辅助开发而打造。
[阅读完整发布说明 →](/docs/react/releases/v3-0-0)
### HeroUI Pro
面向 React 与 React Native 的高级组件、模板与 AI 工具。预售价格现已上线。
[访问 heroui.pro 查看套餐与定价 →](https://heroui.pro)
### v3.0.0-rc.1
**2026 年 3 月 14 日**
新增七个组件([Drawer](/docs/components/drawer)、[ToggleButton](/docs/components/toggle-button)、[ToggleButtonGroup](/docs/components/toggle-button-group)、[Meter](/docs/components/meter)、[ProgressBar](/docs/components/progress-bar)、[ProgressCircle](/docs/components/progress-circle)、[Toolbar](/docs/components/toolbar)),为 [Table](/docs/components/table) 和 [ListBox](/docs/components/list-box) 引入了 **虚拟化**,[ButtonGroup](/docs/components/button-group) 新增 `ButtonGroup.Separator` 与垂直方向支持,React Aria Components 升级到 v1.16.0。
[阅读完整发布说明 →](/docs/react/releases/v3-0-0-rc-1)
### v3.0.0-beta.8
**2026 年 3 月 2 日**
此版本新增三个组件([Badge](/docs/components/badge)、[Pagination](/docs/components/pagination)、[Table](/docs/components/table)),并为 [DateField](/docs/components/date-field) 与 [TimeField](/docs/components/time-field) 提供了新的 `InputContainer` 组合 API。⚠️ **破坏性变更**:TextField 的 CSS 类已从 `.text-field` 重命名为 `.textfield`。
[阅读完整发布说明 →](/docs/react/releases/v3-0-0-beta-8)
### v3.0.0-beta.7
**2026 年 2 月 18 日**
此版本引入了完整的**日期与时间**系统,包含四个新组件([Calendar](/docs/components/calendar)、[RangeCalendar](/docs/components/range-calendar)、[DatePicker](/docs/components/date-picker)、[DateRangePicker](/docs/components/date-range-picker)),新增了 [Switch.Content](/docs/components/switch) 子组件、显式的 [Tabs.Separator](/docs/components/tabs) 用于按需启用分隔线,以及 ⚠️ **破坏性变更**:从 Tabs 中移除 `hideSeparator`,并将 `DateInputGroup` / `ColorInputGroup` 合并到各自的 Field 组件之下。
[阅读完整发布说明 →](/docs/react/releases/v3-0-0-beta-7)
### v3.0.0-beta.6
**2026 年 2 月 6 日**
此版本引入了完整的**颜色系统**,包含六个新组件([ColorPicker](/docs/components/color-picker)、[ColorArea](/docs/components/color-area)、[ColorSlider](/docs/components/color-slider)、[ColorField](/docs/components/color-field)、[ColorSwatch](/docs/components/color-swatch)、[ColorSwatchPicker](/docs/components/color-swatch-picker)),对 [Toast](/docs/components/toast) 进行了重大改进,加入了加载状态与 Promise 支持,[Separator](/docs/components/separator) 新增变体,以及 ⚠️ **破坏性变更**:将 `Toast.Container` 重命名为 `Toast.Provider`,并将 CSS 类名统一为连字符格式。
[阅读完整发布说明 →](/docs/react/releases/v3-0-0-beta-6)
### v3.0.0-beta.5
* 修复构建问题
### v3.0.0-beta.4
**2026 年 1 月 20 日**
**已修复关键构建问题**:此版本(beta.4)存在一个关键构建问题,已在 **beta.5** 中修复。请升级到 `@heroui/styles@3.0.0-beta.5` 与 `@heroui/react@3.0.0-beta.5`,以确保 TypeScript 声明文件能正确生成、导出能正确解析。
此版本引入了用于可视化主题定制的全新[主题构建器](/themes)、三个新组件([Autocomplete](/docs/components/autocomplete)、[Breadcrumbs](/docs/components/breadcrumbs)、[Toast](/docs/components/toast)),为 [Tabs](/docs/components/tabs) 添加了 secondary 变体,为 [Input](/docs/components/input) 与 [InputGroup](/docs/components/input-group) 添加了 primary / secondary 变体,以及 ⚠️ **破坏性变更**:移除了 Link 的下划线变体,并从表单组件中移除了 `isInSurface` prop。
[阅读完整发布说明 →](/docs/react/releases/v3-0-0-beta-4)
### v3.0.0-beta.3
**2025 年 12 月 19 日**
此版本引入了七个新组件([ButtonGroup](/docs/components/button-group)、[DateField](/docs/components/date-field)、[ErrorMessage](/docs/components/error-message)、[ScrollShadow](/docs/components/scroll-shadow)、[SearchField](/docs/components/search-field)、[TagGroup](/docs/components/tag-group)、[TimeField](/docs/components/time-field)),为表单与输入组件添加了 `fullWidth` 支持,为 [Tabs](/docs/components/tabs)、[ButtonGroup](/docs/components/button-group) 和 [Accordion](/docs/components/accordion) 引入 `hideSeparator` 以获得更简洁的布局,包含若干样式修复,以及 ⚠️ **破坏性变更**:移除 `asChild` prop,并更新了 [AlertDialog](/docs/components/alert-dialog) 与 [Modal](/docs/components/modal) 的 backdrop 变体。
[阅读完整发布说明 →](/docs/react/releases/v3-0-0-beta-3)
### v3.0.0-beta.2
**2025 年 11 月 20 日**
此版本引入了六个重要的新组件([AlertDialog](/docs/components/alert-dialog)、[ComboBox](/docs/components/combo-box)、[Dropdown](/docs/components/dropdown)、[InputGroup](/docs/components/input-group)、[Modal](/docs/components/modal)、[NumberField](/docs/components/number-field)),增强了主题兼容性与动效偏好支持,改进了 [Select](/docs/components/select) 组件的 API(包含 ⚠️ **破坏性变更**),并附带多项优化和 bug 修复。
[阅读完整发布说明 →](/docs/react/releases/v3-0-0-beta-2)
### v3.0.0-beta.1
**2025 年 11 月 6 日**
此版本对 HeroUI v3 进行了全面重新设计,将 v2 的美观与动效与 v3 的简洁性融为一体。所有组件均经过重新设计,新增 8 个组件([Alert](/docs/components/alert)、[Checkbox](/docs/components/checkbox)、[InputOTP](/docs/components/input-otp)、[ListBox](/docs/components/list-box)、[Select](/docs/components/select)、[Slider](/docs/components/slider)、[Surface](/docs/components/surface)),并对设计系统进行了彻底重构,包括更完善的颜色 token、阴影体系与整体架构。本版本还包含对设计系统变量、组件 API 以及灵活组件模式的破坏性变更。
[阅读完整发布说明 →](/docs/react/releases/v3-0-0-beta-1)
## 早期版本
### v3.0.0-alpha.35
**2025 年 10 月 21 日**
#### React Server Components 支持
* 修复了复合组件在 React Server Components(RSC)中无法正常工作的关键问题
* 将复合组件模式的逻辑从组件移至 index 文件,解决 `"use client"` 冲突
* **(⚠️ 破坏性变更)**:主组件现在需要 `.Root` 后缀(例如 `` → ``)
* 命名导出保持不变,并完全继续支持
#### React 19 相关改进
* 移除了 `forwardRef`([React 19](https://react.dev/blog/2024/12/05/react-19#ref-as-a-prop) 现已原生支持)
* 简化了 Context 的使用方式(`Context.Provider` → [React 19](https://react.dev/blog/2024/12/05/react-19#context-as-a-provider))
#### Switch 组件重构
* **(⚠️ 破坏性变更)**:将 Switch 与 SwitchGroup 拆分为独立组件
* 更简洁的 API:`` 取代 `` 和 ``
* 与 Radio / RadioGroup 模式保持一致
* 各自拥有独立的样式、类型和实现
#### 受影响的组件
以下复合组件均需要使用 `.Root` 后缀:`Accordion`、`Avatar`、`Card`、`Disclosure`、`Fieldset`、`Kbd`、`Link`、`Popover`、`Radio`、`Switch`、`Tabs`、`Tooltip`
[阅读完整发布说明 →](/docs/react/releases/v3-0-0-alpha-35)
### v3.0.0-alpha.34
**2025 年 10 月 15 日**
* 新增基于表单的组件:[Description](/docs/components/description)、[FieldError](/docs/components/field-error)、[Fieldset](/docs/components/fieldset)、[Form](/docs/components/form)、[Input](/docs/components/input)、[Label](/docs/components/label)、[RadioGroup](/docs/components/radio-group)、[TextField](/docs/components/text-field) 以及 [TextArea](/docs/components/textarea)
* 引入表单字段相关的 token `--field-*`
* 按类别重新组织 Storybook
* **(破坏性变更)**:在 [Skeleton](/docs/components/skeleton) 中将 `--skeleton-default-animation-type` 重命名为 `--skeleton-animation`
* 统一了各组件中 `data-slot` 标记的命名
* 改进了文档
[阅读完整发布说明 →](/docs/react/releases/v3-0-0-alpha-34)
### v3.0.0-alpha.33
**2025 年 10 月 5 日**
* 将 RAC 升级至 [2025 年 10 月 2 日发布的版本](https://react-spectrum.adobe.com/releases/2025-10-02.html)
* 调整了 [Tabs](/docs/components/tabs) 中 Indicator 的顺序(**破坏性变更**)
* 将 [Tabs](/docs/components/tabs) 组件改为使用 React Aria 的 `SelectionIndicator`,现已支持 SSR
* 更新了 [Disclosure](/docs/components/disclosure) 和 [Disclosure Group](/docs/components/disclosure-group) 组件,使其在展开/折叠动画中使用 RAC 的 CSS 变量
* 更新了 [Switch](/docs/components/switch) 组件的样式与动画
* 为 [Switch](/docs/components/switch#sizes) 新增 `size` 变体并补充了对应演示
* 在 [Button](/docs/components/button)、[Tabs](/docs/components/tabs)、[Disclosure](/docs/components/disclosure)、[Disclosure Group](/docs/components/disclosure-group) 中添加了相关示例
* 改进了文档
[阅读完整发布说明 →](/docs/react/releases/v3-0-0-alpha-33)
### v3.0.0-alpha.32
**2025 年 10 月 1 日**
重新设计了 Card 组件,引入了[新变体](/docs/components/card),新增了 [CloseButton](/docs/components/close-button) 组件,发布了面向 AI 编码助手的 [MCP 服务器](/docs/ui-for-agents/mcp-server),并改进了文档。
[阅读完整发布说明 →](/docs/react/releases/v3-0-0-alpha-32)
### v3.0.0-alpha.31
**2025 年 9 月 22 日**
* 🎨 **展示页面** - 使用 HeroUI 构建的站点案例集
* 🌀 **DisclosureGroup 组件** - 将多个 Disclosure 组合在一起
* 📇 **Card 组件**(预览) - Card 组件的首个版本
* 🔀 **Switch 组件**(预览) - 用于设置项的切换开关
## 发布周期
HeroUI v3 现已稳定。后续版本将遵循固定的发布周期:
* **补丁版本**:按需修复 bug 与小幅优化
* **次要版本**:新增组件与功能,通常每月一次
* **主版本**:包含架构层面的变更,并提供迁移指南
## 参与贡献
发现问题或希望参与贡献?欢迎查看我们的 [GitHub 仓库](https://github.com/heroui-inc/heroui)。
# v3.0.0-alpha.32
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-0-alpha-32
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-0-alpha-32.mdx
> Card 组件重新设计、CloseButton 组件,以及面向 AI 助手的 MCP 服务器。
2025 年 10 月 1 日
此版本新增了用于 AI 开发的工具,并更新了 [Card 组件](/docs/components/card) 的 API,以提升开发者体验。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@alpha @heroui/react@alpha
```
```bash
pnpm add @heroui/styles@alpha @heroui/react@alpha
```
```bash
yarn add @heroui/styles@alpha @heroui/react@alpha
```
```bash
bun add @heroui/styles@alpha @heroui/react@alpha
```
## 新增功能
### MCP 服务器
HeroUI 现已包含一个 [MCP 服务器](/docs/ui-for-agents/mcp-server),可让 Cursor、Claude Code、VS Code Copilot 等 AI 助手直接访问 HeroUI v3 的文档与组件信息。
**快速配置:**
### Cursor
或在 **Cursor Settings** → **Tools** → **MCP Servers** 中手动添加:
```json
{
"mcpServers": {
"heroui-react": {
"command": "npx",
"args": ["-y", "@heroui/react-mcp@latest"]
}
}
}
```
### Claude Code
在终端中运行以下命令:
```bash
claude mcp add heroui-react -- npx -y @heroui/react-mcp@latest
```
[了解更多](/docs/ui-for-agents/mcp-server)
### Card 组件 API 重新设计
[Card 组件](/docs/components/card) 已升级到全新的变体系统,使用更加灵活。
**破坏性变更:**
* 将 `surface` prop 替换为新的 `variant` 系统
* 移除了 `Card.Image`、`Card.Details` 与 `Card.CloseButton`(请改用组合方式实现)
* 新增变体:`flat`、`outlined`、`elevated`、`filled`
**之前:**
```tsx
Old Card
```
**之后:**
```tsx
New Card
```
**新功能:**
* 支持水平布局
* 与 Avatar 集成
* 支持背景图片
* 通过语义化 HTML 提升无障碍体验
[查看 Card 组件文档](/docs/components/card)
### CloseButton 组件
新增 [CloseButton 组件](/docs/components/close-button),用于关闭对话框、模态框以及其他可关闭的元素。
```tsx
import {CloseButton} from "@heroui/react";
// Basic usage
console.log("Closed")} />
// With custom icon
```
## 文档改进
### 面向 AI 的 UI
* **[MCP 服务器文档](/docs/ui-for-agents/mcp-server)** —— 介绍如何借助 AI 助手进行开发
* **[llms.txt](/docs/ui-for-agents/llms-txt)** —— 对 LLM 更友好的文档文件
* 主流 AI 编码工具的配置指南
### 组件文档
* **[Card](/docs/components/card)**:重写了文档,包含 anatomy、变体与更多示例
* **[Switch](/docs/components/switch)**:新增 anatomy 示意图与更完善的示例
* **[CloseButton](/docs/components/close-button)**:全新文档,附带使用示例
## 迁移指南
### Card 组件迁移
1. **更新 variant prop:**
* `surface="1"` → `variant="flat"`
* `surface="2"` → `variant="outlined"`
* `surface="3"` → `variant="elevated"`
* `surface="4"` → `variant="filled"`
* 自定义 surface → 改用新的变体系统
2. **更新组件结构:**
* 将 `Card.Image` 替换为放在 `Card.Header` 中的 ` `
* 将 `Card.Details` 替换为 `Card.Body`
* 将 `Card.CloseButton` 迁移为使用新的 `CloseButton` 组件
3. **更新导入:**
```tsx
// Add CloseButton if needed
import {Card, CloseButton} from "@heroui/react";
```
## 链接
* [GitHub PR #5747](https://github.com/heroui-inc/heroui/pull/5747)
* [MCP 服务器文档](/docs/ui-for-agents/mcp-server)
* [Card 组件指南](/docs/components/card)
* [CloseButton 组件](/docs/components/close-button)
## 贡献者
感谢每一位为本次发布做出贡献的开发者!
# v3.0.0-alpha.33
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-0-alpha-33
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-0-alpha-33.mdx
> 升级 RAC、重新设计 Tabs 指示器、新增 Switch 尺寸变体,以及相关示例展示。
2025 年 10 月 5 日
此版本升级了 React Aria Components,重新设计了 Tabs 指示器,为 Switch 新增尺寸支持,并补充了一系列组件示例。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@alpha @heroui/react@alpha
```
```bash
pnpm add @heroui/styles@alpha @heroui/react@alpha
```
```bash
yarn add @heroui/styles@alpha @heroui/react@alpha
```
```bash
bun add @heroui/styles@alpha @heroui/react@alpha
```
## 新增功能
### RAC 升级
将 React Aria Components 升级到 [2025 年 10 月 2 日发布版本](https://react-spectrum.adobe.com/releases/2025-10-02.html)。
本次升级包括:
* 用于动画的 CSS 变量
* 更好的 SSR 支持
* 选择指示器的性能改进
### Disclosure 与 DisclosureGroup 更新
[Disclosure](/docs/components/disclosure) 与 [DisclosureGroup](/docs/components/disclosure-group) 现在使用 React Aria 的 CSS 变量来驱动动画。组件会通过 `--disclosure-panel-width` 与 `--disclosure-panel-height` 变量在展开 / 折叠期间跟踪面板的实际尺寸。
### Tabs 指示器重新设计
[Tabs](/docs/components/tabs) 现在使用 React Aria 的 `SelectionIndicator` 并支持 SSR,这修复了初次渲染时的布局抖动问题。
**🚧 破坏性变更:**
* 将 `Tabs.Indicator` 移至每一个 `Tabs.Tab` 内部
**之前:**
```diff tsx
+
-
```
### Switch 更新
[Switch](/docs/components/switch) 的样式与动画都得到了更新。新增 `size` prop,可选值为 `sm`、`md`、`lg`。
```tsx
import {Switch} from "@heroui/react";
export function Sizes() {
return (
小
中
大
);
}
```
### 相关示例
我们在 [Button](/docs/components/button)、[Disclosure](/docs/components/disclosure)、[DisclosureGroup](/docs/components/disclosure-group) 与 [Tabs](/docs/components/tabs) 中新增了「相关示例」展示。
## 文档改进
### 组件文档
* **[Tabs](/docs/components/tabs)**:更新了 anatomy,根据新的指示器设计重写了示例,并新增了相关示例展示
* **[Switch](/docs/components/switch)**:新增尺寸示例,并重写了 with-icon 示例
* **[Button](/docs/components/button)**、**[Disclosure](/docs/components/disclosure)**、**[DisclosureGroup](/docs/components/disclosure-group)**:新增相关示例展示
## 迁移指南
### Tabs 组件迁移
1. **更新组件结构:**
* 将 ` ` 移至每一个 ` ` 内部
## 链接
* [GitHub PR #5777](https://github.com/heroui-inc/heroui/pull/5777)
* [Tabs 组件](/docs/components/tabs)
* [Switch 组件](/docs/components/switch)
* [Button 组件](/docs/components/button)
* [Disclosure 组件](/docs/components/disclosure)
* [DisclosureGroup 组件](/docs/components/disclosure-group)
## 贡献者
感谢每一位为本次发布做出贡献的开发者!
# v3.0.0-alpha.34
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-0-alpha-34
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-0-alpha-34.mdx
> 用 Form、TextField、RadioGroup、Label、Input、Fieldset 等简洁 API 构建表单的核心组件。
2025 年 10 月 15 日
此版本引入了一系列基于表单的组件、表单字段 token,重新组织了 Storybook,并对各组件之间的 data-slot 标识做了统一对齐。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@alpha @heroui/react@alpha
```
```bash
pnpm add @heroui/styles@alpha @heroui/react@alpha
```
```bash
yarn add @heroui/styles@alpha @heroui/react@alpha
```
```bash
bun add @heroui/styles@alpha @heroui/react@alpha
```
**正在使用 AI 助手?** 只需对它说一句「Hey Cursor,把 HeroUI 升级到最新版本」,AI 助手就会自动对比版本并应用必要的变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新增功能
### 基于表单的组件
我们引入了一整套基于 React Aria Components 构建的表单类组件,为构建表单提供了无障碍且可组合的基础构件。这些组件包括 [Description](/docs/components/description)、[FieldError](/docs/components/field-error)、[Fieldset](/docs/components/fieldset)、[Form](/docs/components/form)、[Input](/docs/components/input)、[Label](/docs/components/label)、[RadioGroup](/docs/components/radio-group)、[TextField](/docs/components/text-field) 与 [TextArea](/docs/components/textarea)。
#### Description
```tsx
import {Description, Input, Label} from "@heroui/react";
export function Basic() {
return (
邮箱
我们不会将你的邮箱分享给任何人。
);
}
```
#### FieldError
```tsx
"use client";
import {FieldError, Input, Label, TextField} from "@heroui/react";
import {useState} from "react";
export function Basic() {
const [value, setValue] = useState("jr");
const isInvalid = value.length > 0 && value.length < 3;
return (
用户名
setValue(e.target.value)}
/>
用户名至少需要 3 个字符
);
}
```
#### Fieldset
```tsx
"use client";
import {FloppyDisk} from "@gravity-ui/icons";
import {
Button,
Description,
FieldError,
FieldGroup,
Fieldset,
Form,
Input,
Label,
TextArea,
TextField,
} from "@heroui/react";
export function Basic() {
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const data: Record = {};
// Convert FormData to plain object
formData.forEach((value, key) => {
data[key] = value.toString();
});
alert("表单提交成功!");
};
return (
);
}
```
#### Form
```tsx
"use client";
import {Check} from "@gravity-ui/icons";
import {Button, Description, FieldError, Form, Input, Label, TextField} from "@heroui/react";
export function Basic() {
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const data: Record = {};
// Convert FormData to plain object
formData.forEach((value, key) => {
data[key] = value.toString();
});
alert(`表单提交数据:${JSON.stringify(data, null, 2)}`);
};
return (
{
if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(value)) {
return "请输入有效的邮箱地址";
}
return null;
}}
>
邮箱
{
if (value.length < 8) {
return "密码至少需要 8 个字符";
}
if (!/[A-Z]/.test(value)) {
return "密码至少需要包含一个大写字母";
}
if (!/[0-9]/.test(value)) {
return "密码至少需要包含一个数字";
}
return null;
}}
>
密码
至少 8 个字符,且包含 1 个大写字母和 1 个数字
提交
重置
);
}
```
#### Input
```tsx
import {Input} from "@heroui/react";
export function Basic() {
return ;
}
```
#### Label
```tsx
import {Input, Label} from "@heroui/react";
export function Basic() {
return (
姓名
);
}
```
#### RadioGroup
```tsx
import {Description, Label, Radio, RadioGroup} from "@heroui/react";
export function Basic() {
return (
选择套餐
选择最适合你的套餐
基础版
每月包含 100 条消息
高级版
每月包含 200 条消息
商业版
无限消息
);
}
```
#### TextField
#### TextArea
```tsx
import {TextArea} from "@heroui/react";
export function Basic() {
return (
);
}
```
### 表单字段 token
引入 `--field-*` 表单字段 token,确保各表单组件之间样式保持一致。`--field-*` 变量的具体说明请参阅 [主题](/docs/handbook/theming#calculated-variables-tailwind)。
### Storybook 重新组织
按类别重新组织了 Storybook,方便导航与组件查找。
### Skeleton 动画 token
**🚧 破坏性变更:** 为了与其他组件 token 保持一致,[Skeleton](/docs/components/skeleton) 中的 `--skeleton-default-animation-type` 已重命名为 `--skeleton-animation`。
### data-slot 对齐
我们统一了各组件的 data-slot 标识,使样式与定制更加一致。这项标准化让通过 CSS 选择器定位特定组件部件变得更容易,整体上也优化了自定义组件样式时的开发体验。
组件现在使用一致的 `data-slot` 属性,例如:
* `data-slot="base"` —— 用于根元素
* `data-slot="label"` —— 用于标签文本
* `data-slot="description"` —— 用于描述文本
* `data-slot="error"` —— 用于错误信息
这样在所有表单组件中都能用可预期的方式进行 CSS 定位:
```css
.radio {
[data-slot="label"] {
/* Styles apply to radio labels */
}
}
```
## 文档改进
### 组件文档
* **[Link](/docs/components/link)**:新增 anatomy 与带图标的示例,更新了 Link 与 Link.Icon 的 prop 章节。
* **[Description](/docs/components/description)**、**[FieldError](/docs/components/field-error)**、**[Fieldset](/docs/components/fieldset)**、**[Form](/docs/components/form)**、**[Input](/docs/components/input)**、**[Label](/docs/components/label)**、**[RadioGroup](/docs/components/radio-group)**、**[TextField](/docs/components/text-field)**,以及 **[TextArea](/docs/components/textarea)**:附带使用示例的全新文档
## 迁移指南
### Skeleton 组件迁移
1. **更新动画 token:**
* 将 `--skeleton-default-animation-type` 替换为 `--skeleton-animation`
## 链接
* [GitHub PR #5780](https://github.com/heroui-inc/heroui/pull/5780)
* [Description 组件](/docs/components/description)
* [FieldError 组件](/docs/components/field-error)
* [Fieldset 组件](/docs/components/fieldset)
* [Form 组件](/docs/components/form)
* [Input 组件](/docs/components/input)
* [Label 组件](/docs/components/label)
* [RadioGroup 组件](/docs/components/radio-group)
* [TextField 组件](/docs/components/text-field)
* [TextArea 组件](/docs/components/textarea)
* [Skeleton 组件](/docs/components/skeleton)
## 贡献者
感谢每一位为本次发布做出贡献的开发者!
# v3.0.0-alpha.35
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-0-alpha-35
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-0-alpha-35.mdx
> 复合组件支持 React Server Components、面向 React 19 的改进,以及关键 bug 修复。
2025 年 10 月 21 日
此版本修复了一个关键问题:**复合组件在 React Server Components(RSC)中无法正常工作**。同时,本版本采用了 React 19 的最佳实践,移除了 `forwardRef`,并简化了 Context 的使用方式。Switch 组件已经过重构,与 Radio / RadioGroup 模式保持一致,提供更清晰、更统一的 API。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@alpha @heroui/react@alpha
```
```bash
pnpm add @heroui/styles@alpha @heroui/react@alpha
```
```bash
yarn add @heroui/styles@alpha @heroui/react@alpha
```
```bash
bun add @heroui/styles@alpha @heroui/react@alpha
```
**正在使用 AI 助手?** 只需对它说一句「Hey Cursor,把 HeroUI 升级到最新版本」,AI 助手就会自动对比版本并应用必要的变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新增功能
### React Server Components 支持
复合组件现在可以在 React Server Components 中正常工作。此前的实现把复合模式逻辑放在了组件内部,与 `"use client"` 指令存在冲突。通过将模式逻辑迁移到组件的索引文件中,这一问题已被修复。
### 面向 React 19 的改进
本版本采用了 React 19 的最佳实践:
1. **移除 `forwardRef`**:在 React 19 中已不再需要,`ref` 现在可以作为普通的 prop 使用(参见 [React 19 文档](https://react.dev/blog/2024/12/05/react-19#ref-as-a-prop))
2. **简化 Context**:将 `Context.Provider` 替换为直接使用 `Context`(参见 [React 19 文档](https://react.dev/blog/2024/12/05/react-19#context-as-a-provider))
### Switch 组件架构改进
Switch 组件已经过重构,遵循与 Radio / RadioGroup 相同的清晰拆分模式:
* **拆分组件**:Switch 与 SwitchGroup 现在是独立的组件(此前合并在一起)
* **更清晰的 API**:用 `` 取代了嵌套的 `` 与 `` 模式
* **更合理的组织**:每个组件都有各自独立的样式、类型与实现
* **一致的模式**:与 Radio / RadioGroup 架构保持一致,API 更具可预测性
**之前:**
```tsx
...
```
**之后:**
```tsx
...
...
```
## ⚠️ 破坏性变更
### 主组件需要使用 `.Root` 后缀
为支持 React Server Components,复合组件模式已经过重构。在使用复合写法时,主组件现在需要带上 `.Root` 后缀。
**之前:**
```tsx
import { Avatar } from "@heroui/react"
JR
```
**之后:**
```tsx
import { Avatar } from "@heroui/react"
JR
```
**说明:** 命名导出(例如 ``、``、``)保持不变,依然完全支持。
### Switch 组件 API 变更
Switch 组件的分组 API 已经过重构,与 Radio / RadioGroup 模式保持一致:
**之前:**
```tsx
import { Switch } from "@heroui/react"
Notifications
Marketing
```
**之后:**
```tsx
import { Switch, SwitchGroup } from "@heroui/react"
Notifications
Marketing
```
这次变更带来了:
* **拆分组件**:Switch 与 SwitchGroup 现在是独立的组件(此前合并在一起)
* **更清晰的 API**:用 `` 取代了嵌套的 `` 与 `` 模式
* **更合理的组织**:每个组件都有各自独立的样式、类型与实现
* **一致的模式**:与 Radio / RadioGroup 架构保持一致,API 更具可预测性
**迁移步骤:**
1. 单独导入 `SwitchGroup`:`import { Switch, SwitchGroup } from "@heroui/react"`
2. 将 `` 替换为 ``
3. 移除嵌套的 `` 包装
4. 单个的 `Switch.Root` 组件保持不变
#### 受影响的组件
所有复合组件都受到影响:
* `Accordion` → `Accordion.Root`
* `Avatar` → `Avatar.Root`
* `Card` → `Card.Root`
* `Disclosure` → `Disclosure.Root`
* `Fieldset` → `Fieldset.Root`
* `Kbd` → `Kbd.Root`
* `Link` → `Link.Root`
* `Popover` → `Popover.Root`
* `RadioGroup` → `RadioGroup.Root`
* `Switch` → `Switch.Root`
* `Tabs` → `Tabs.Root`
* `Tooltip` → `Tooltip.Root`
## 迁移指南
使用 HeroUI 的复合组件有两种选择:
### 选项 1:改为使用 `.Root`(复合写法)
如果你使用的是复合写法(点号语法),请将主组件改为使用 `.Root`:
**Card 示例:**
```tsx
import { Card } from "@heroui/react"
Card Title
Card description
Card content
Card footer
```
**Tabs 示例:**
```tsx
import { Tabs } from "@heroui/react"
Tab 1
Tab 2
Panel 1
Panel 2
```
[更多示例请参阅文档](/docs/components/card)
**Avatar 示例:**
```tsx
import { Avatar } from "@heroui/react"
JD
```
[更多示例请参阅文档](/docs/components/avatar)
### 选项 2:使用命名导出
我们已经为所有复合组件添加了命名导出支持,你可以这样使用:
**Card 示例:**
```tsx
import {
CardRoot,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
} from "@heroui/react"
Card Title
Card description
Card content
Card footer
```
**Tabs 示例:**
```tsx
import { TabsRoot, TabListContainer, TabList, Tab, TabIndicator, TabPanel } from "@heroui/react"
Tab 1
Tab 2
Panel 1
Panel 2
```
**Avatar 示例:**
```tsx
import { Avatar, AvatarImage, AvatarFallback } from "@heroui/react"
JD
```
### 迁移步骤
如果你使用的是复合写法,只需将主组件改为使用 `.Root`:
1. **查找复合组件的所有使用位置**(例如内部包含 `` 等的 ``)
2. **为主组件添加 `.Root`**:
```tsx
// Before
// After
```
3. **就这样!** 所有子组件(如 `Avatar.Image`、`Avatar.Fallback`)保持不变。
### 完整的迁移参考
| 组件 | 命名导出写法 | 复合写法(带 `.Root`) | 额外变更 |
| -------------- | ------------------------------ | ------------------------------------ | ---------------------------------------- |
| **Accordion** | `` | `` | - |
| **Avatar** | `` | `` | - |
| **Card** | `` | `` | - |
| **Disclosure** | `` | `` | - |
| **Fieldset** | `` | `` | - |
| **Kbd** | `` | `` | - |
| **Link** | ` ` | `` | - |
| **Popover** | `` | `` | - |
| **Radio** | `` | `` | - |
| **Switch** | ``、`` | ``、`` | `` → ``(独立组件) |
| **Tabs** | ``、`` | ``、`` | - |
| **Tooltip** | ``、`` | ``、`` | - |
### 自动化迁移
对于使用复合写法的大型代码库,可以借助查找 / 替换:
```bash
# Example for Avatar component
# Update the main component to use .Root
sed -i 's///g' **/*.tsx
sed -i 's/<\/Avatar>/<\/Avatar.Root>/g' **/*.tsx
# Switch component requires additional steps
# First, ensure SwitchGroup is imported
# Then replace Switch.Group with SwitchGroup
sed -i 's//<\/SwitchGroup>/g' **/*.tsx
# Remove Switch.GroupItems wrapper
sed -i 's///g' **/*.tsx
sed -i 's/<\/Switch\.GroupItems>//g' **/*.tsx
# Repeat for other compound components (Card, Tabs, etc.)
# Note: This only affects files using the compound pattern
```
**重要事项:**
* 使用自动替换时务必小心,确保只替换复合写法的用法,而不要影响命名导出。
* Switch 的迁移完成后,请确认 `SwitchGroup` 已被导入:`import { Switch, SwitchGroup } from "@heroui/react"`
* 在执行完自动迁移后请测试代码,确认所有变更均符合预期。
## 为什么需要这次变更?
这次变更是修复 React Server Components 兼容性所必需的。此前的实现存在一些架构上的限制:
1. **RSC 兼容性**:复合模式逻辑与 `"use client"` 指令存在冲突
2. **拥抱 React 19**:移除了 `forwardRef` 与 `Context.Provider` 等已被弃用的写法
3. **更清晰的架构**:模式逻辑现在位于索引文件中,而不是组件文件中
4. **更彻底的拆分**:服务端组件与客户端组件现在可以无缝协作
## 文档更新
组件文档将同步更新,以反映新的写法:
* 示例将展示带 `.Root` 的复合写法
* 命名导出形式的示例依然有效且仍受支持
* 迁移指南将帮助你顺利完成升级
* 两种写法都获得完整支持,行为完全一致
## 需要帮助?
如果你在迁移过程中遇到任何问题:
1. **复合写法用户**:将主组件改为使用 `.Root`(例如 `` → ``)
2. **命名导出用户**:无需做任何修改,你的代码仍可正常工作
3. 查阅组件文档中的示例
4. 反馈问题:[GitHub Issues](https://github.com/heroui-inc/heroui/issues)
## 链接
* [组件文档](/docs/react/components)
* [React Server Components](https://react.dev/reference/rsc/server-components)
* [React 19 发布](https://react.dev/blog/2024/12/05/react-19)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
## 贡献者
感谢每一位为本次发布做出贡献的开发者,是你们让 React Server Components 支持与 React 19 兼容性得到了改进!
# v3.0.0-beta.1
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-0-beta-1
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-0-beta-1.mdx
> 重大重新设计,带来全新的设计系统、8 个新组件以及更佳的开发者体验。
2025 年 11 月 6 日
此版本对 HeroUI v3 进行了全面重新设计,将 v2 的美观与动效与 v3 的简洁性融为一体。所有组件均经过重新设计,新增 8 个组件,并对设计系统进行了改进,包括更完善的颜色 token、阴影体系与整体架构。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@beta @heroui/react@beta
```
```bash
pnpm add @heroui/styles@beta @heroui/react@beta
```
```bash
yarn add @heroui/styles@beta @heroui/react@beta
```
```bash
bun add @heroui/styles@beta @heroui/react@beta
```
**正在使用 AI 助手?** 只需对它说一句「Hey Cursor,把 HeroUI 升级到最新版本」,AI 助手就会自动对比版本并应用必要的变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新增功能
### 全新的设计系统
我们花了数周时间打造一套全新的设计系统,将 HeroUI v2 的灵魂与 v3 的简洁性融合在一起。每一个组件都经过重新设计,注重细节、流畅的动效以及更佳的开发者体验。新的设计系统已发布在我们的 [Figma Kit v3](https://www.figma.com/community/file/1546526812159103429/heroui-figma-kit-v3)。
本次重新设计带来了:
* 让 v3 的视觉愿景落地、并具备独特辨识度的全新色彩系统
* 更精致的阴影系统,呈现更好的层次感
* 全新的变量与 token,提供更强的定制能力
* 基于表单的组件自动具备 `isOnSurface` 支持
* 增强的边框与间距 token
* 更好的对比度与无障碍体验
* Web 与 Native 之间一致的组件模式
### 新组件
本次发布共引入 **8 个** 新的基础组件:
* **[Alert](#alert)**:带状态指示器,用于展示重要的消息与通知。
* **[Checkbox 与 CheckboxGroup](#checkbox-checkboxgroup)**:用于在列表中选择多个条目。
* **[InputOTP](#inputotp)**:用于身份验证流程的一次性密码输入框。
* **[ListBox](#listbox)**:展示一组可单选或多选的选项。
* **[Select](#select)**:基于 ListBox 构建的下拉选择组件。
* **[Slider](#slider)**:从一个范围中选择数值,支持自定义刻度与标签。
* **[Surface](#surface)**:用于构建带高度的容器的基础 surface 组件。
### Alert
```tsx
import {Alert, Button, CloseButton, Spinner} from "@heroui/react";
import React from "react";
export function Basic() {
return (
{/* 默认 — 一般信息 */}
新功能已上线
查看我们的最新更新,包括深色模式支持与改进的无障碍体验。
{/* 强调 — 重要信息含操作 */}
有可用更新
应用有新版本可用。请刷新页面以获取最新功能与问题修复。
刷新
刷新
{/* 危险 — 错误与排查步骤 */}
无法连接到服务器
当前遇到连接问题,请尝试以下操作:
重试
重试
{/* 无描述 */}
个人资料已更新
{/* 自定义指示器 — 加载中 */}
正在处理你的请求
正在同步你的数据,请稍候,这可能需要一点时间。
{/* 无关闭按钮 */}
计划维护
我们将于 UTC 时间 3 月 15 日(周日)凌晨 2:00 至上午 6:00
进行计划维护,期间服务将暂时不可用。
);
}
```
### Checkbox 与 CheckboxGroup
```tsx
import {Checkbox} from "@heroui/react";
export function Basic() {
return (
接受条款与条件
);
}
```
```tsx
import {Checkbox, CheckboxGroup, Description, Label} from "@heroui/react";
export function Basic() {
return (
选择你的兴趣
可多选
编程
热爱构建软件
设计
喜欢打造精美界面
写作
热衷于内容创作
);
}
```
### InputOTP
```tsx
import {InputOTP, Label, Link} from "@heroui/react";
export function Basic() {
return (
验证账户
我们已向 a****@gmail.com 发送验证码
);
}
```
### ListBox
```tsx
import {Avatar, Description, Label, ListBox} from "@heroui/react";
export function Default() {
return (
B
Bob
bob@heroui.com
F
Fred
fred@heroui.com
M
Martha
martha@heroui.com
);
}
```
### Select
```tsx
import {Label, ListBox, Select} from "@heroui/react";
export function Default() {
return (
州
佛罗里达
特拉华
加利福尼亚
德克萨斯
纽约
华盛顿
);
}
```
### Slider
```tsx
import {Label, Slider} from "@heroui/react";
export function Default() {
return (
音量
);
}
```
### Surface
```tsx
import {Surface} from "@heroui/react";
export function Variants() {
return (
默认
表面内容
这是默认表面变体,使用 bg-surface 样式。
次要
表面内容
这是次要表面变体,使用 bg-surface-secondary 样式。
第三
表面内容
这是第三表面变体,使用 bg-surface-tertiary 样式。
透明
表面内容
这是透明表面变体,无背景,适用于遮罩层和自定义背景的卡片。
);
}
```
### 组件 API 改进
多个组件的 API 都得到了改进:
* **Link**:新增 `underline` 与 `underlineOffset` prop,支持更细粒度的定制
```tsx
import {Link} from "@heroui/react";
export function LinkBasic() {
return (
立即行动
);
}
```
* **Card**:变体与样式系统得到改进
```tsx
import {CircleDollar} from "@gravity-ui/icons";
import {Avatar, Button, Card, CloseButton, Link} from "@heroui/react";
export function WithImages() {
return (
{/* 第 1 行:大图商品卡 */}
成为 ACME 创作者!
这是一段占位说明文字,用于展示横向卡片布局、配图与右上角关闭按钮的排版效果。
仅剩 10 个名额
报名截止:10 月 10 日
立即申请
{/* 第 2 行 */}
{/* 左栏 */}
{/* 上方卡片 */}
支付
现已支持加密货币提现
在设置中添加钱包即可提现
前往设置
{/* 下方小卡 */}
{/* 左卡 */}
JK
Indie Hackers
148 位成员
JK
创建者:约翰
{/* 右卡 */}
AB
AI Builders
362 位成员
M
创建者:玛莎
{/* 右栏 */}
{/* 背景图 */}
{/* 标题区 */}
NEO
家用机器人
{/* 底部 */}
通知我
{/* 第 3 行 */}
{/* 左:大图卡 */}
立即购买
{/* 右:堆叠小卡 */}
{/* 1 */}
连接未来
今天 18:30
{/* 2 */}
牛油果黑客松
周三 16:30
{/* 3 */}
Sound Electro|超越艺术
周五 20:00
);
}
```
* **Chip**:新增尺寸变体并改进了颜色系统
```tsx
import {Chip} from "@heroui/react";
export function ChipBasic() {
return (
默认
强调
成功
警告
危险
);
}
```
* **Switch**:从底层重新设计,视觉与动画都得到优化
```tsx
import {Switch} from "@heroui/react";
export function Basic() {
return (
启用通知
);
}
```
* **RadioGroup**:从底层重新设计,API 与样式更佳
```tsx
import {Description, Label, Radio, RadioGroup} from "@heroui/react";
export function Basic() {
return (
选择套餐
选择最适合你的套餐
基础版
每月包含 100 条消息
高级版
每月包含 200 条消息
商业版
无限消息
);
}
```
### 灵活的组件模式
HeroUI 现在支持更灵活的组件写法。复合组件可以带 `.Root` 也可以不带 `.Root`,也可以使用命名导出——三种写法表现完全一致。
**可用模式:**
```tsx
import { Avatar } from "@heroui/react"
// 1. Compound pattern (no .Root needed) - recommended
JD
// 2. Compound pattern with .Root - still supported
JD
// 3. Named exports
import { AvatarRoot, AvatarImage, AvatarFallback } from "@heroui/react"
JD
```
**简单组件**(如 Button)的写法也完全一致:
```tsx
import { Button } from "@heroui/react"
// No .Root needed
Label
// Or with .Root
Label
// Or named export
import { ButtonRoot } from "@heroui/react"
Label
```
**你也可以在同一个组件中混用复合写法与命名导出:**
```tsx
import { Avatar, AvatarFallback } from "@heroui/react"
JD
```
由此带来的好处:
* **更简洁的 API**:主组件不再强制要求 `.Root` 后缀
* **灵活性**:可以在「复合写法」、「带 `.Root` 的复合写法」与「命名导出」之间自由选择
* **向后兼容**:`.Root` 写法依然可用
* **命名一致性**:统一了命名约定(例如使用「Container」而非「Wrapper」)
### 全局动画控制
HeroUI 现在通过 `data-reduce-motion` 属性提供了便捷的全局动画控制方式。只需在 `` 或 `` 标签上加上 `data-reduce-motion="true"`,即可禁用整个应用中的所有动画。
```html
```
HeroUI 会自动通过 `prefers-reduced-motion` 媒体查询尊重用户的动画偏好,并扩展了 Tailwind 的 `motion-reduce:` 变体,使其同时支持系统偏好与基于 data 属性的手动控制。这样既能灵活控制动画,也能符合无障碍最佳实践。
了解更多关于动画与动效偏好的内容,请参阅 [动画文档](/docs/handbook/animation)。
## ⚠️ 破坏性变更
### 设计系统变量
#### Panel → Surface 与 Overlay
`--panel` 变量已被替换为 `--surface` 与 `--overlay`,以更好地区分非浮层组件(Card、Accordion)与浮层组件(Tooltip、Popover、Modal)。
**之前:**
```css
--panel: var(--white);
--panel-foreground: var(--foreground);
--shadow-panel: 0 0 1px 0 rgba(0, 0, 0, 0.3) inset, 0 2px 8px 0 rgba(0, 0, 0, 0.08);
```
**之后:**
```css
--surface: var(--white);
--surface-foreground: var(--foreground);
--overlay: var(--white);
--overlay-foreground: var(--foreground);
--shadow-surface: 0 2px 4px 0 rgba(0, 0, 0, 0.04), 0 1px 2px 0 rgba(0, 0, 0, 0.06), 0 0 1px 0 rgba(0, 0, 0, 0.06);
--shadow-overlay: 0 4px 16px 0 rgba(24, 24, 27, 0.08), 0 8px 24px 0 rgba(24, 24, 27, 0.09);
```
**迁移:**
* 非浮层组件请将 `bg-panel` 替换为 `bg-surface`
* 浮层组件请将 `bg-panel` 替换为 `bg-overlay`
* 将 `shadow-panel` 替换为 `shadow-surface` 或 `shadow-overlay`
* 将 `--color-panel` 替换为 `--color-surface` 或 `--color-overlay`
#### Surface 层级简化
`--surface-1`、`--surface-2` 与 `--surface-3` 变量已被移除。Surface 各层级现在通过 `color-mix` 自动从 `--surface` 计算得出,因此你只需声明基础的 surface 颜色。
**之前(手动声明):**
```css
--surface-1: var(--background);
--surface-2: var(--color-neutral-100);
--surface-3: var(--color-neutral-200);
```
**之后(自动计算):**
```css
/* You only declare the base surface */
--surface: var(--white);
--surface-foreground: var(--foreground);
/* HeroUI automatically calculates these using color-mix */
--color-surface-secondary: color-mix(in oklab, var(--surface) 94%, var(--surface-foreground) 6%);
--color-surface-tertiary: color-mix(in oklab, var(--surface) 92%, var(--surface-foreground) 8%);
--color-surface-quaternary: color-mix(in oklab, var(--surface) 86%, var(--surface-foreground) 14%);
```
**自定义:**
可以通过 Tailwind 的 `@theme` 指令覆盖默认的计算结果:
```css
@theme inline {
--color-surface-secondary: color-mix(in oklab, var(--surface) 96%, var(--surface-foreground) 4%);
--color-surface-tertiary: color-mix(in oklab, var(--surface) 94%, var(--surface-foreground) 6%);
--color-surface-quaternary: color-mix(in oklab, var(--surface) 90%, var(--surface-foreground) 10%);
}
```
**迁移:**
* 将 `bg-surface-1` 替换为 `bg-surface`(基础 surface)
* 将 `bg-surface-2` 替换为 `bg-surface-secondary`(自动计算)
* 将 `bg-surface-3` 替换为 `bg-surface-tertiary`(自动计算)
同样的自动计算模式也适用于:
* **背景色阶**:从 `--background` 计算 → `background-secondary`、`background-tertiary`、`background-quaternary`
* **柔和色**:从状态色计算 → `accent-soft`、`danger-soft`、`warning-soft`、`success-soft`
#### 边框宽度默认值变更
默认边框宽度已从 `1px` 改为 `0px`。边框现在改为按需启用,而不是默认存在。
**之前:**
```css
--border-width: 1px;
```
**之后:**
```css
--border-width: 0px; /* no border by default */
```
**迁移:**
* 如果你的样式依赖默认边框,请在自定义样式中显式设置 `border-width`
* 表单字段现在默认使用 `transparent` 边框
#### 边框颜色默认值变更
默认边框颜色的不透明度已从 `15%` 改为 `0%`(透明)。
**之前:**
```css
--border: oklch(0 0 0 / 15%);
```
**之后:**
```css
--border: oklch(0 0 0 / 0%);
```
**字段边框默认值:**
```css
--field-border: transparent; /* no border by default on form fields */
```
#### 阴影系统更新
阴影系统已被完全重新设计,为 surface 与 overlay 各自提供独立的阴影。
**之前:**
```css
--panel-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.3) inset, 0 2px 8px 0 rgba(0, 0, 0, 0.08);
--field-shadow: 0 0 0 0 rgba(255, 255, 255, 0.1) inset, 0 1px 2px 0 rgba(0, 0, 0, 0.05);
```
**之后(浅色模式):**
```css
--surface-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.04), 0 1px 2px 0 rgba(0, 0, 0, 0.06), 0 0 1px 0 rgba(0, 0, 0, 0.06);
--overlay-shadow: 0 4px 16px 0 rgba(24, 24, 27, 0.08), 0 8px 24px 0 rgba(24, 24, 27, 0.09);
--field-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.04), 0 1px 2px 0 rgba(0, 0, 0, 0.06), 0 0 1px 0 rgba(0, 0, 0, 0.06);
```
**之后(深色模式):**
```css
--surface-shadow: 0 0 0 0 transparent inset; /* No shadow on dark mode */
--overlay-shadow: 0 0 0 0 transparent inset; /* No shadow on dark mode */
--field-shadow: 0 0 0 0 transparent inset; /* Transparent shadow to allow ring utilities to work */
```
#### 强调色更新
强调色经过更新,对比度与视觉吸引力都有所提升。
**之前:**
```css
--accent: var(--color-neutral-950);
--accent-foreground: var(--snow);
```
**之后:**
```css
--accent: oklch(0.6204 0.195 253.83);
--accent-foreground: var(--snow);
```
#### 状态颜色优化
success、warning 与 danger 颜色经过优化,一致性与对比度都更佳。
**Success:**
* **之前:** `oklch(0.5503 0.1244 153.56)`
* **之后:** `oklch(0.7329 0.1935 150.81)`
* 浅色模式下,前景色从 `var(--snow)` 改为 `var(--eclipse)`
**Warning:**
* **之前:** `oklch(0.7186 0.1521 64.85)`
* **之后:** `oklch(0.7819 0.1585 72.33)`(浅色),`oklch(0.8203 0.1388 76.34)`(深色)
**Danger:**
* **之前:** `oklch(0.6259 0.1908 29.19)`
* **之后:** `oklch(0.6532 0.2328 25.74)`(浅色),`oklch(0.594 0.1967 24.63)`(深色)
### 组件 API 变更
#### Chip 组件
Chip 组件的 `type` prop 已重命名为 `color`,同时新增 `size` prop,并引入了新的 `soft` 变体。
**之前:**
```tsx
import { Chip } from "@heroui/react";
Label
```
**之后:**
```tsx
import { Chip } from "@heroui/react";
Label
```
**迁移:**
* 将 `type` prop 替换为 `color` prop
* 使用 `size` prop(`sm`、`md`、`lg`)控制 Chip 尺寸
* `soft` 变体提供低调的外观,适用于不那么突出的 Chip
#### Link 组件
Link 组件现在支持 `underline` 与 `underlineOffset` prop,并加入了对 `asChild` 的支持。
**之前:**
```tsx
import { Link } from "@heroui/react";
Link text
```
**之后:**
```tsx
import { Link } from "@heroui/react";
Link text
```
**新增 prop:**
* `underline`:`"none" | "hover" | "always"` —— 控制下划线的可见性
* `underlineOffset`:`number` —— 控制下划线相对文本的偏移
#### 类型引用语法
由于采用了双模式实现,通过命名空间语法引用类型的方式不再支持。请改用对象样式语法或具名类型导入。
**之前(不再可用):**
```tsx
type AvatarProps = Avatar.RootProps
```
**之后(方式 1 —— 对象样式语法):**
```tsx
type AvatarProps = Avatar["RootProps"]
```
**之后(方式 2 —— 具名类型导入,推荐):**
```tsx
import type { AvatarRootProps } from "@heroui/react"
type AvatarProps = AvatarRootProps
```
此变更会影响访问 prop 类型的所有复合组件。
#### Tabs 组件重命名
为保持一致性,Tabs 组件的包装元素已重命名:
* **复合属性**:`Tabs.ListWrapper` → `Tabs.ListContainer`
* **命名导出**:`TabListWrapper` → `TabListContainer`
* **CSS 类**:`.tabs__list-wrapper` → `.tabs__list-container`
* **data 属性**:`data-slot="tabs-list-wrapper"` → `data-slot="tabs-list-container"`
**迁移:**
请查找并替换所有 `TabListWrapper`,将其改为 `TabListContainer`:
```bash
# Component usage
TabListWrapper → TabListContainer
Tabs.ListWrapper → Tabs.ListContainer
# CSS selectors (if using custom styles)
.tabs__list-wrapper → .tabs__list-container
[data-slot="tabs-list-wrapper"] → [data-slot="tabs-list-container"]
```
#### 已移除的变量
以下变量已被移除:
* `--panel` → 改用 `--surface` 或 `--overlay`
* `--panel-foreground` → 改用 `--surface-foreground` 或 `--overlay-foreground`
* `--surface-1`、`--surface-2`、`--surface-3` → 改用背景色阶或 surface 层级
* `--accent-soft` → 改用 `--color-accent-soft`(现已自动计算)
* `--radius-panel` 与 `--radius-panel-inner` → 改用标准的 radius 取值
## 设计系统更新
### 全新的色彩系统
#### Surface 与 Overlay 概念
设计系统现在区分两类带高度的组件:
* **Surface**:用于直接放置在页面上的非浮层组件,如 Card、Accordion、Disclosure Group
* **Overlay**:用于浮在页面之上的浮层组件,如 Tooltip、Popover、Modal、Menu
这种区分带来:
* 更好的视觉层级
* 更合适的阴影深度
* 更优的深色模式对比度
* 更清晰的组件语义
#### 自动计算的色彩系统
HeroUI 现在使用 CSS `color-mix` 自动计算各种色阶以及柔和色变体。你只需声明基础颜色,剩下的交给 HeroUI 处理。
**背景色阶**
背景色阶会自动从 `--background` 计算:
```css
/* You only declare the base */
--background: oklch(0.9702 0 0);
--foreground: var(--eclipse);
/* HeroUI automatically calculates these */
--color-background-secondary: color-mix(in oklab, var(--color-background) 96%, var(--color-foreground) 4%);
--color-background-tertiary: color-mix(in oklab, var(--color-background) 92%, var(--color-foreground) 8%);
--color-background-quaternary: color-mix(in oklab, var(--color-background) 86%, var(--color-foreground) 14%);
```
**Surface 层级**
Surface 各层级会自动从 `--surface` 计算:
```css
/* You only declare the base */
--surface: var(--white);
--surface-foreground: var(--foreground);
/* HeroUI automatically calculates these */
--color-surface-secondary: color-mix(in oklab, var(--surface) 94%, var(--surface-foreground) 6%);
--color-surface-tertiary: color-mix(in oklab, var(--surface) 92%, var(--surface-foreground) 8%);
--color-surface-quaternary: color-mix(in oklab, var(--surface) 86%, var(--surface-foreground) 14%);
```
**柔和色变体**
柔和色变体会自动从状态色计算:
```css
/* You declare the base status colors */
--accent: oklch(0.6204 0.195 253.83);
--danger: oklch(0.6532 0.2328 25.74);
--warning: oklch(0.7819 0.1585 72.33);
--success: oklch(0.7329 0.1935 150.81);
/* HeroUI automatically calculates these at 15% opacity */
--color-accent-soft: color-mix(in oklab, var(--color-accent) 15%, transparent);
--color-danger-soft: color-mix(in oklab, var(--color-danger) 15%, transparent);
--color-warning-soft: color-mix(in oklab, var(--color-warning) 15%, transparent);
--color-success-soft: color-mix(in oklab, var(--color-success) 15%, transparent);
```
每个柔和色变体都包含悬停态(20% 不透明度)以及对应的前景色,以保证合适的对比度。
**自定义:**
可以通过 Tailwind 的 `@theme` 指令覆盖任意自动计算结果:
```css
@theme inline {
/* Adjust surface levels */
--color-surface-secondary: color-mix(in oklab, var(--surface) 96%, var(--surface-foreground) 4%);
/* Adjust soft colors */
--color-accent-soft: color-mix(in oklab, var(--color-accent) 20%, transparent);
}
```
这套自动计算系统减少了你需要管理的变量数量,同时在需要时仍能完全自定义。
### 阴影系统
阴影系统经过重新设计,提供:
* 为 surface 与 overlay 提供各自独立的阴影
* 更好的层次感
* 深色模式支持(透明阴影)
* 一致的字段阴影
阴影会自动适配浅色与深色模式,为每种主题提供合适的层次提示。
### 焦点系统
焦点颜色现在使用强调色,以保持一致性:
```css
--focus: var(--accent);
```
这样既能让焦点指示器与你的品牌色一致,也能保留无障碍能力。
### 排版 token
部分与排版相关的变量已被移除,转而推荐直接使用 Tailwind 的排版工具类。设计系统现在专注于颜色与间距 token,将排版交给 Tailwind 处理。
## 迁移指南
### 第 1 步:更新设计系统变量
将旧的 panel 变量替换为 surface / overlay:
```css
/* Before */
.my-card {
background: var(--panel);
box-shadow: var(--shadow-panel);
}
/* After */
.my-card {
background: var(--surface);
box-shadow: var(--shadow-surface);
}
.my-tooltip {
background: var(--overlay);
box-shadow: var(--shadow-overlay);
}
```
### 第 2 步:更新 surface 层级
Surface 层级现在会自动从 `--surface` 计算得出,因此无需手动声明。直接使用新的工具类即可:
```css
/* Before */
.bg-surface-1 → .bg-surface (base surface)
.bg-surface-2 → .bg-surface-secondary (auto-calculated)
.bg-surface-3 → .bg-surface-tertiary (auto-calculated)
/* You can also use background shades */
.bg-surface-2 → .bg-background-secondary (auto-calculated from --background)
.bg-surface-3 → .bg-background-tertiary (auto-calculated from --background)
```
**说明:** Surface 层级(`surface-secondary`、`surface-tertiary` 等)会基于你的 `--surface` 颜色自动计算。除非你想自定义计算方式,否则不需要手动声明任何 CSS 变量。
### 第 3 步:更新组件 props
更新 Chip 与 Link 组件:
```tsx
// Chip: type → color, add size if needed
→
// Link: Add underline props if customizing underlines
Text // Still works, underline props are optional
```
### 第 4 步:简化组件写法(可选)
如果你在 v3.0.0-alpha.35 中已经采用了 `.Root` 后缀,现在可以将其移除以简化代码:
**之前(v3.0.0-alpha.35):**
```tsx
JD
```
**之后(更简洁):**
```tsx
JD
```
**说明:** 如果你更喜欢 `.Root` 写法,它仍然可用。
### 第 5 步:更新类型引用
如果你之前用命名空间语法来引用类型,请改用对象样式语法或具名导入:
**之前:**
```tsx
type ButtonProps = Button.RootProps
```
**之后(方式 1 —— 对象样式):**
```tsx
type ButtonProps = Button["RootProps"]
```
**之后(方式 2 —— 具名导入,推荐):**
```tsx
import type { ButtonRootProps } from "@heroui/react"
type ButtonProps = ButtonRootProps
```
### 第 6 步:更新 Tabs 组件
将 `TabListWrapper` 替换为 `TabListContainer`:
**之前:**
```tsx
import { Tabs } from "@heroui/react"
Home
Content
```
**之后:**
```tsx
import { Tabs } from "@heroui/react"
Home
Content
```
### 第 7 步:处理边框相关变更
如果你的自定义样式依赖默认边框:
```css
/* Add explicit borders where needed */
.my-component {
border-width: 1px;
border-color: var(--color-border);
}
```
### 第 8 步:更新状态颜色
如果你曾经定制过状态颜色,请查阅新的取值并按需调整你的自定义主题:
```css
/* Check if your custom status colors need updates */
--success: oklch(0.7329 0.1935 150.81); /* New value */
--warning: oklch(0.7819 0.1585 72.33); /* New value */
--danger: oklch(0.6532 0.2328 25.74); /* New value */
```
### 自动化迁移
对于较大的代码库,可以借助查找 / 替换:
```bash
# Panel → Surface
--panel → --surface
bg-panel → bg-surface
shadow-panel → shadow-surface
# Panel → Overlay (for floating components)
--panel → --overlay (where appropriate)
bg-panel → bg-overlay (for tooltips, popovers, etc.)
shadow-panel → shadow-overlay (for floating components)
# Chip type prop
type=" → color="
# Surface levels
bg-surface-1 → bg-surface
bg-surface-2 → bg-surface-secondary
bg-surface-3 → bg-surface-tertiary
# Tabs component
TabListWrapper → TabListContainer
Tabs.ListWrapper → Tabs.ListContainer
# Type references
Component.RootProps → Component["RootProps"] or use named imports
```
## 组件更新
### Card 组件
Card 组件经过优化,变体更丰富、语义结构更合理。该组件现已使用新的 surface 系统,样式更加一致。
### Accordion 组件
Accordion 现在也使用 surface 系统,与其他组件在视觉上更加一致。
### 表单组件
表单组件(Input、TextField、TextArea)已更新为使用新的字段边框系统(默认透明),在保留无障碍能力的前提下呈现更简洁的外观。
### 组件模式更新
所有组件现在都支持灵活的写法。支持双模式的组件包括:
* **简单组件**:Button、Link、Spinner、Chip、Kbd
* **复合组件**:Accordion、Avatar、Card、Disclosure、Fieldset、Popover、RadioGroup、Switch、Tabs、Tooltip
以上所有组件都可以使用三种写法中的任意一种:不带 `.Root` 的复合写法、带 `.Root` 的复合写法,或具名导出。
## HeroUI Pro
HeroUI Pro 正基于全新的设计系统从零进行重塑。新版 Pro 将带来:
* 基于 HeroUI v3 构建的新组件
* Tailwind CSS v4 原生支持
* 基于 CSS 的原生动画
* 更强的可定制能力
我们将很快分享更多更新。
## 路线图
我们正以发布稳定版本为目标,计划在 2025 年的 **第四季度** 完成。本次 beta 让我们距离这个目标更进一步:
* 更完整的组件集合
* 更精炼的设计系统
* 更佳的开发者体验
* 更好的性能
## 社区
Native 端的反响非常热烈。感谢你在我们打造 HeroUI v3 的过程中给予的支持!你的反馈让我们每一天都在变得更好。
来看看社区的声音:[HeroUI Native 用户反响](https://x.com/hero_ui/status/1985721976220966926)
## 链接
* [组件文档](/docs/react/components)
* [设计系统 - Figma Kit v3](https://www.figma.com/community/file/1546526812159103429/heroui-figma-kit-v3)
* [HeroUI Native](https://link.heroui.com/native)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #5872](https://github.com/heroui-inc/heroui/pull/5872)
## 贡献者
感谢每一位为本次发布做出贡献的开发者,是你们让我们打造出了一套既美观又实用的设计系统!
# v3.0.0-beta.2
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-0-beta-2
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-0-beta-2.mdx
> 六个新组件(AlertDialog、ComboBox、Dropdown、InputGroup、Modal、NumberField)、Select API 改进以及多项组件优化。
2025 年 11 月 20 日
此版本引入了六个重要的新组件,改进了 Select 组件的 API,并包含多项优化与 bug 修复。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@beta @heroui/react@beta
```
```bash
pnpm add @heroui/styles@beta @heroui/react@beta
```
```bash
yarn add @heroui/styles@beta @heroui/react@beta
```
```bash
bun add @heroui/styles@beta @heroui/react@beta
```
**正在使用 AI 助手?** 只需对它说一句「Hey Cursor,把 HeroUI 升级到最新版本」,AI 助手就会自动对比版本并应用必要的变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新增功能
### 新组件
本次发布引入了 **6 个** 新的基础组件:
* **[AlertDialog](#alert-dialog)**:用于需要用户确认的重要决策的模态对话框。([文档](/docs/components/alert-dialog))
* **[ComboBox](#combo-box)**:将文本输入与列表框结合,让用户可以在选项列表中过滤。([文档](/docs/components/combo-box))
* **[Dropdown](#dropdown)**:展示一组可供用户选择的操作或选项。([文档](/docs/components/dropdown))
* **[InputGroup](#inputgroup)**:通过 prefix 与 suffix 元素将相关输入控件组合在一起,强化表单字段。([文档](/docs/components/input-group))
* **[Modal](#modal)**:用于聚焦用户交互与重要内容的对话框浮层。([文档](/docs/components/modal))
* **[NumberField](#numberfield)**:数字输入框,带有递增 / 递减按钮、表单校验以及国际化格式化。([文档](/docs/components/number-field))
### AlertDialog
```tsx
"use client";
import {AlertDialog, Button} from "@heroui/react";
export function Default() {
return (
删除项目
要永久删除项目吗?
此操作将永久删除 我的精彩项目 及其全部数据,且无法撤销。
取消
删除项目
);
}
```
### ComboBox
```tsx
"use client";
import {ComboBox, Input, Label, ListBox} from "@heroui/react";
export function Default() {
return (
最喜欢的动物
土豚
猫
狗
袋鼠
熊猫
蛇
);
}
```
### Dropdown
```tsx
"use client";
import {Button, Dropdown, Label} from "@heroui/react";
export function Default() {
return (
操作
console.log(`Selected: ${key}`)}>
新建文件
复制链接
编辑文件
删除文件
);
}
```
### Modal
```tsx
"use client";
import {Rocket} from "@gravity-ui/icons";
import {Button, Modal} from "@heroui/react";
export function Default() {
return (
打开模态框
欢迎使用 HeroUI
一套美观、快速、现代的 React UI 库,可轻松构建无障碍且高度可定制的 Web 应用。
继续
);
}
```
### InputGroup
```tsx
"use client";
import {Globe} from "@gravity-ui/icons";
import {InputGroup, Label, TextField} from "@heroui/react";
export function WithIconPrefixAndTextSuffix() {
return (
网站
.com
);
}
```
### NumberField
```tsx
import {Label, NumberField} from "@heroui/react";
export function Basic() {
return (
宽度
);
}
```
### 样式改进
#### 自定义变体与主题兼容性
增强了 CSS 变体与主题系统,提供更好的可定制性:
**动效偏好:**
* 新增 `motion-safe` 变体,可与 `data-reduce-motion="true"` 属性配合使用
* 增强后的 `motion-reduce` 现在支持祖先元素与伪元素
**深色模式:**
* 类与 `data-theme="dark"` 属性选择器现在优先于 `prefers-color-scheme`
* 在深色模式下完整支持伪元素
**主题变量:**
* 扩展了浅色主题的覆盖范围,以支持嵌套主题(`:root`、`.light`、`.default`、`[data-theme="light"]`、`[data-theme="default"]`)
### 组件改进
#### Select 组件 API 更新
Select 组件的 API 已经过改进,与其他组件保持一致。`Content` 子组件已重命名为 `Popover`。
**之前:**
```tsx
{/* items */}
```
**之后:**
```tsx
{/* items */}
```
#### Chip 组件改进
Chip 组件的尺寸已更新,以提升一致性:
* **小(`sm`)**:`px-1 py-0 text-xs`
* **中(`md`)**:`text-xs`(现在显式设置)
* **大(`lg`)**:`px-3 py-1 text-sm font-medium`
#### Separator 组件增强
Separator 组件现在能自动检测是否被放置在 surface 组件中(使用 `bg-surface`),并应用合适的分隔线颜色以获得更好的可见性。同时新增了 `isOnSurface` prop,用于手动控制。
**新增的计算变量:**
* `--color-separator-on-surface`:通过 `color-mix` 自动生成的计算变量,确保分隔线在 surface 背景上仍然清晰可见。与其他计算变量一样,可在你的主题中覆盖它。
**用法:**
```tsx
```
当 Separator 检测到外层存在 `SurfaceContext` Provider(由 Card、Alert、Popover、Modal 等组件提供)时,`isOnSurface` prop 会自动启用。
你也可以直接在 Tailwind 类中使用这个计算变量:
```tsx
```
#### 动画改进
* 更新了加载状态 spinner 的颜色,提升可见性
* 调整了 Select 与 Slider 组件的样式,改进动画效果
* 改进了 Checkbox 动画(过渡更快)
* 在伪元素中更好地支持 `prefers-reduced-motion`
## ⚠️ 破坏性变更
### Select 组件
为与 ComboBox、Dropdown 等组件保持一致,`Select.Content` 子组件已重命名为 `Select.Popover`。
**迁移:**
将所有 `Select.Content` 替换为 `Select.Popover`:
```tsx
// Before
...
// After
...
```
**类型导入:**
```tsx
// Before
import type { SelectContentProps } from "@heroui/react"
// After
import type { SelectPopoverProps } from "@heroui/react"
```
**命名导出:**
```tsx
// Before
import { SelectContent } from "@heroui/react"
// After
import { SelectPopover } from "@heroui/react"
```
### CSS 变量与工具类:divider → separator
为与 Separator 组件名保持一致,所有与 `divider` 相关的 CSS 变量与工具类均已重命名为 `separator`。
**CSS 变量:**
```css
/* Before */
border-bottom: 1px solid var(--divider);
/* After */
border-bottom: 1px solid var(--separator);
```
**Tailwind 工具类:**
```tsx
// Before
// After
```
**主题覆盖:**
如果你的自定义主题中覆盖了 separator 相关变量,请同步更新:
```css
/* Before */
:root {
--divider: oklch(92% 0.004 286.32);
}
.dark {
--divider: oklch(22% 0.006 286.033);
}
/* After */
:root {
--separator: oklch(92% 0.004 286.32);
}
.dark {
--separator: oklch(22% 0.006 286.033);
}
```
## Bug 修复
* 修复了加载状态 spinner 的颜色,提升可见性
* 修复了 bordered 状态下焦点样式优先于 hover 状态的表现
* 修复了文档中的动画卡顿问题
* 改进了模态表单的样式
* 增强了 motion-reduce 在伪元素上的支持
* 修复了移动端触摸交互后悬停状态保留的问题——将 hover 样式包裹在 `@media (hover: hover)` 媒体查询中。同时通过移除不必要的 `="true"` data 属性值选择器,简化了相关代码。
## 链接
* [组件文档](/docs/react/components)
* [设计系统 - Figma Kit v3(已更新)](https://www.figma.com/community/file/1546526812159103429/heroui-figma-kit-v3)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #5885](https://github.com/heroui-inc/heroui/pull/5885)
## 贡献者
感谢每一位为本次发布做出贡献的开发者!
# v3.0.0-beta.3
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-0-beta-3
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-0-beta-3.mdx
> 七个新组件、fullWidth 与 hideSeparator 支持、样式修复,以及 AlertDialog / Modal backdrop 变体调整与移除 asChild prop 等破坏性变更。
2025 年 12 月 19 日
此版本引入了七个新组件([ButtonGroup](/docs/components/button-group)、[DateField](/docs/components/date-field)、[ErrorMessage](/docs/components/error-message)、[ScrollShadow](/docs/components/scroll-shadow)、[SearchField](/docs/components/search-field)、[TagGroup](/docs/components/tag-group)、[TimeField](/docs/components/time-field)),为表单组件添加 `fullWidth` 支持,为 [Tabs](/docs/components/tabs)、[ButtonGroup](/docs/components/button-group) 与 [Accordion](/docs/components/accordion) 引入 `hideSeparator`,包含若干样式修复,以及 ⚠️ **破坏性变更**:移除 `asChild` prop,并更新了 [AlertDialog](/docs/components/alert-dialog) 与 [Modal](/docs/components/modal) 的 backdrop 变体。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@beta @heroui/react@beta
```
```bash
pnpm add @heroui/styles@beta @heroui/react@beta
```
```bash
yarn add @heroui/styles@beta @heroui/react@beta
```
```bash
bun add @heroui/styles@beta @heroui/react@beta
```
**正在使用 AI 助手?** 只需对它说一句「Hey Cursor,把 HeroUI 升级到最新版本」,AI 助手就会自动对比版本并应用必要的变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新增功能
### 新组件
本次发布引入了 **7 个** 新的基础组件:
* **[ButtonGroup](#button-group)**:以一致的样式与间距将相关按钮分组。([文档](/docs/components/button-group))
* **[DateField](#date-field)**:日期输入字段,支持 label、description 与表单校验,基于 React Aria DateField 构建。([文档](/docs/components/date-field))
* **[ErrorMessage](#error-message)**:底层的错误信息组件,用于在非表单组件中展示错误。([文档](/docs/components/error-message))
* **[ScrollShadow](#scroll-shadow)**:通过视觉阴影提示可滚动内容溢出,并可自动检测滚动位置。([文档](/docs/components/scroll-shadow))
* **[SearchField](#search-field)**:带有内置搜索图标与清除按钮的搜索输入字段。([文档](/docs/components/search-field))
* **[TagGroup](#tag-group)**:一组可聚焦的标签,支持键盘导航、选择与删除。([文档](/docs/components/tag-group))
* **[TimeField](#time-field)**:时间输入字段,支持 label、description 与表单校验,基于 React Aria TimeField 构建。([文档](/docs/components/time-field))
### ButtonGroup
```tsx
import {
ChevronDown,
ChevronLeft,
ChevronRight,
CodeFork,
Ellipsis,
Picture,
Pin,
QrCode,
Star,
TextAlignCenter,
TextAlignJustify,
TextAlignLeft,
TextAlignRight,
ThumbsDown,
ThumbsUp,
Video,
} from "@gravity-ui/icons";
import {Button, ButtonGroup, Chip, Description, Dropdown, Label} from "@heroui/react";
export function Basic() {
return (
{/* 单个按钮与下拉菜单 */}
合并拉取请求
创建合并提交
此分支上的所有提交都将加入基础分支
压缩并合并
此分支上的 14 个提交将合并为一次提交并加入基础分支
变基并合并
此分支上的 14 个提交将变基后加入基础分支
{/* 独立按钮 */}
复刻
24
扫码支付
2.4K
星标
104
已置顶
{/* 上一页 / 下一页 */}
上一页
下一页
{/* 内容类型选择 */}
{/* 文本对齐 */}
左对齐
居中
右对齐
{/* 仅图标:对齐 */}
);
}
```
### DateField
```tsx
"use client";
import {DateField, Label} from "@heroui/react";
export function Basic() {
return (
日期
{(segment) => }
);
}
```
### ErrorMessage
```tsx
"use client";
import type {Key} from "@heroui/react";
import {Description, ErrorMessage, Label, Tag, TagGroup} from "@heroui/react";
import {useMemo, useState} from "react";
export function ErrorMessageBasic() {
const [selected, setSelected] = useState>(new Set());
const isInvalid = useMemo(() => Array.from(selected).length === 0, [selected]);
return (
setSelected(keys)}
>
必选分类
新闻
旅游
游戏
购物
请至少选择一个分类
{!!isInvalid && <>请至少选择一个分类>}
);
}
```
### SearchField
```tsx
import {Label, SearchField} from "@heroui/react";
export function Basic() {
return (
搜索
);
}
```
### ScrollShadow
```tsx
import {Card, ScrollShadow} from "@heroui/react";
const images = [
"https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/docs/robot1.jpeg",
"https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/docs/avocado.jpeg",
"https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/docs/oranges.jpeg",
];
export default function Orientation() {
const getRandomImage = (idx: number) => {
return images[idx % images.length];
};
return (
垂直
{Array.from({length: 10}).map((_, idx) => (
段落 {idx + 1}:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam
pulvinar risus non risus hendrerit venenatis. Pellentesque sit amet hendrerit
risus, sed porttitor quam. Morbi accumsan cursus enim, sed ultricies sapien.
))}
水平
{Array.from({length: 10}).map((_, idx) => (
连接未来
今天 18:30
))}
);
}
```
### TagGroup
```tsx
"use client";
import {PlanetEarth, Rocket, ShoppingBag, SquareArticle} from "@gravity-ui/icons";
import {Tag, TagGroup} from "@heroui/react";
export function TagGroupBasic() {
return (
资讯
旅行
游戏
购物
);
}
```
### TimeField
```tsx
"use client";
import {Label, TimeField} from "@heroui/react";
export function Basic() {
return (
时间
{(segment) => }
);
}
```
### 全宽支持
为表单与输入组件新增 `fullWidth` 支持,可以让它们撑满容器的整个宽度。这在构建一致的表单布局与响应式设计时尤其有用。
**支持的组件:**
* [ButtonGroup](/docs/components/button-group)
* [Button](/docs/components/button)
* [ComboBox](/docs/components/combo-box)
* [DateField](/docs/components/date-field)
* [DateInputGroup](/docs/components/date-input-group)
* [InputGroup](/docs/components/input-group)
* [Input](/docs/components/input)
* [NumberField](/docs/components/number-field)
* [SearchField](/docs/components/search-field)
* [Select](/docs/components/select)
* [TextField](/docs/components/text-field)
* [TextArea](/docs/components/textarea)
* [TimeField](/docs/components/time-field)
## 组件改进
### 分隔线控制增强
为 [Tabs](/docs/components/tabs)、[ButtonGroup](/docs/components/button-group) 与 [Accordion](/docs/components/accordion) 组件新增 `hideSeparator` 支持,可隐藏条目之间的分隔线,呈现更简洁、更纯粹的外观。
**Tabs:**
```tsx
Overview
Analytics
```
**ButtonGroup:**
```tsx
First
Second
Third
```
**Accordion:**
```tsx
Item 1
Content
```
### 文档图标集成
将 [@gravity-ui/icons](https://github.com/gravity-ui/icons) 集成到文档组件中,统一图标渲染,同时改进了 SSR 支持并提升了性能。
## 依赖更新
### React Aria Components v1.14.0
将 [React Aria Components](https://react-aria.adobe.com/releases/v1-14-0) 升级到 v1.14.0。本次升级包含:
**增强:**
* SearchField:新增 `isReadOnly` 与 `isRequired` 渲染属性
* Tooltip:新增 `shouldCloseOnPress` 属性
* Tabs:支持在 tab 面板之间进行动画过渡
* 其他:`useControlledState` 现已在 `setState` 回调中提供支持
**修复:**
* ComboBox:修复 VoiceOver 不读取 ListBox 项 `aria-label` 的问题
* 日期与时间:增强了对 absolute 日期与日期时间字符串的错误处理
* NumberField:在移动端滚动时不再误触发递增 / 递减
* Overlay:修复了设置 boundary container 时 overlay 定位与 flip 的问题
* Table:修复了在键盘导航期间进行拖放时的崩溃问题
* 其他多项 bug 修复与改进
完整变更请参阅 [React Aria Components v1.14.0 发布说明](https://react-aria.adobe.com/releases/v1-14-0)。
### 其他依赖升级
* `@internationalized/date`:3.10.0 → 3.10.1
* `@radix-ui/react-avatar`:1.1.10 → 1.1.11
* `tailwind-merge`:3.3.1 → 3.4.0
* `tailwind-variants`:3.1.1 → 3.2.2
## 样式修复
### 表单组件的禁用状态
修复了 [Input](/docs/components/input) 与 [TextArea](/docs/components/textarea) 组件的禁用状态样式。
### 样式优化
* **提高选择器精确度**:增强 CSS 选择器特异性,让样式隔离更好、性能更优
* **动画增强**:改进了多个组件的动画性能与流畅度
* **新增 no-highlight 工具类**:新增 `no-highlight` 工具类,用于防止交互元素中的文字被选中,从而提升体验
* **优化 will-change 属性**:在多个组件中调整 `will-change` CSS 属性,以获得更好的动画性能
* **移除全局滚动条样式**:移除了全局滚动条样式,避免与自定义滚动条实现冲突,并修复了 modal / overlay 的交互问题
## ⚠️ 破坏性变更
### AlertDialog 与 Modal 的 backdrop 变体
`backdropVariant` / `variant` prop 的取值已从 `"solid"` 重命名为 `"opaque"`,以提升语义清晰度——「opaque」(不透明)更准确地描述了遮罩的视觉外观。
**迁移:**
将 AlertDialog 中所有 `backdropVariant="solid"` 替换为 `backdropVariant="opaque"`,将 Modal 中所有 `variant="solid"` 替换为 `variant="opaque"`:
```tsx
// Before
{/* content */}
{/* content */}
// After
{/* content */}
{/* content */}
```
**可用的 backdrop 变体:**
* `"opaque"` —— 深色不透明遮罩,完全遮挡背景(即此前的 `"solid"`)
* `"blur"` —— 模糊遮罩,柔和地遮挡背景
* `"transparent"` —— 透明遮罩,保持背景可见
### 移除 `asChild` prop
为提供更清晰的 API、更强的类型安全性以及更简单的使用方式,组件中的 `asChild` 模式已被移除。
关于组件组合模式的更多细节,请参阅 [组合指南](/docs/handbook/composition)。
## Bug 修复
* 修复了 `isInvalid` 样式在 surface 背景上使用相关组件时的表现
* 修复了 AlertDialog 与 Modal 关闭后重新渲染的问题
* 修复了浮层关闭时未能正确清理的问题
* 修复了文档中 Storybook 链接与导航的问题
## 链接
* [组件文档](/docs/react/components)
* [设计系统 - Figma Kit v3(已更新)](https://www.figma.com/community/file/1546526812159103429/heroui-figma-kit-v3)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #5923](https://github.com/heroui-inc/heroui/pull/5923)
## 贡献者
感谢每一位为本次发布做出贡献的开发者!
# v3.0.0-beta.4
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-0-beta-4
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-0-beta-4.mdx
> 全新的主题构建器、三个新组件(Autocomplete、Breadcrumbs、Toast)、Tabs 的 secondary 变体、Input / InputGroup 变体,以及多项改进。
2026 年 1 月 20 日
**已修复关键构建问题**:此版本(beta.4)存在一个关键构建问题,已在 **beta.5** 中修复。请升级到 `@heroui/styles@3.0.0-beta.5` 与 `@heroui/react@3.0.0-beta.5`,以确保 TypeScript 声明文件能正确生成、导出能正确解析。
此版本引入了用于可视化主题定制的全新 [主题构建器](/themes),三个新组件([Autocomplete](/docs/components/autocomplete)、[Breadcrumbs](/docs/components/breadcrumbs)、[Toast](/docs/components/toast)),为 [Tabs](/docs/components/tabs) 添加 secondary 变体,为 [Input](/docs/components/input) 与 [InputGroup](/docs/components/input-group) 添加 primary / secondary 变体,InputGroup 新增对 TextArea 的支持,以及 ⚠️ **破坏性变更**:移除 Link 的下划线变体,并从表单组件中移除 `isInSurface` prop。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@beta @heroui/react@beta
```
```bash
pnpm add @heroui/styles@beta @heroui/react@beta
```
```bash
yarn add @heroui/styles@beta @heroui/react@beta
```
```bash
bun add @heroui/styles@beta @heroui/react@beta
```
**正在使用 AI 助手?** 只需对它说一句「Hey Cursor,把 HeroUI 升级到最新版本」,AI 助手就会自动对比版本并应用必要的变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新增功能
### 主题构建器
我们很高兴推出 **[主题构建器](/themes)** —— 用于创建与定制 HeroUI 主题的强大可视化工具。可在实时预览中构建你专属的主题,并导出可直接使用的 CSS。
**主要特性:**
* **可视化颜色编辑**:通过 OKLCH 颜色选择器以及直观的亮度、色度、色相滑块来调整颜色
* **实时预览**:在实时组件预览中立即查看你的修改
* **自定义强调色**:定义你的品牌色,并观察它如何贯穿到所有组件
* **预设主题**:从精选预设(如 Default、Airbnb、Coinbase、Discord)入手
* **导出即可用**:生成 CSS 变量,直接复制到你的项目即可
* **浅色与深色模式**:可联动也可独立地同时定制两套主题
* **键盘快捷键**:支持撤销 / 重做以及快速操作,提升工作流效率
立即在 [v3.heroui.com/themes](/themes) 上试用。
### 新组件
本次发布共引入 **3 个** 新的基础组件:
* **[Autocomplete](#autocomplete)**:将 Select 与过滤功能结合,让用户可以在选项列表中搜索并选择。([文档](/docs/components/autocomplete))
* **[Breadcrumbs](#breadcrumbs)**:导航面包屑,用于展示当前页面在层级结构中的位置。([文档](/docs/components/breadcrumbs))
* **[Toast](#toast)**:用于展示临时通知与消息,支持自动关闭以及自定义放置位置。([文档](/docs/components/toast))
### Autocomplete
```tsx
"use client";
import type {Key} from "@heroui/react";
import {
Autocomplete,
EmptyState,
Label,
ListBox,
SearchField,
Tag,
TagGroup,
useFilter,
} from "@heroui/react";
import {useState} from "react";
export default function Default() {
const {contains} = useFilter({sensitivity: "base"});
const [selectedKeys, setSelectedKeys] = useState([]);
const items = [
{id: "florida", name: "Florida"},
{id: "delaware", name: "Delaware"},
{id: "california", name: "California"},
{id: "texas", name: "Texas"},
{id: "new-york", name: "New York"},
{id: "washington", name: "Washington"},
];
const onRemoveTags = (keys: Set) => {
setSelectedKeys((prev) => prev.filter((key) => !keys.has(key)));
};
return (
setSelectedKeys(keys as Key[])}
>
计划前往的州
{({defaultChildren, isPlaceholder, state}: any) => {
if (isPlaceholder || state.selectedItems.length === 0) {
return defaultChildren;
}
const selectedItemsKeys = state.selectedItems.map((item: any) => item.key);
return (
{selectedItemsKeys.map((selectedItemKey: Key) => {
const item = items.find((s) => s.id === selectedItemKey);
if (!item) return null;
return (
{item.name}
);
})}
);
}}
未找到结果 }>
{items.map((item) => (
{item.name}
))}
);
}
```
### Breadcrumbs
```tsx
"use client";
import {Breadcrumbs} from "@heroui/react";
export default function BreadcrumbsBasic() {
return (
首页
产品
电子产品
笔记本电脑
);
}
```
### Toast
该组件目前处于预览阶段,部分功能可能尚未按预期工作。
```tsx
"use client";
import {HardDrive, Persons} from "@gravity-ui/icons";
import {Button, toast} from "@heroui/react";
export function Variants() {
return (
{
const id = toast("您已被邀请加入团队", {
actionProps: {
children: "忽略",
onPress: () => toast.close(id),
variant: "tertiary",
},
description: "Bob 邀请您加入 HeroUI 团队",
indicator: ,
variant: "default",
});
}}
>
默认 Toast
{
const id = toast.info("您还剩 2 个积分", {
actionProps: {children: "升级", onPress: () => toast.close(id)},
description: "升级付费方案以获取更多积分",
});
}}
>
强调 Toast
{
const id = toast.success("您已升级方案", {
actionProps: {
children: "账单",
className: "bg-success text-success-foreground",
onPress: () => toast.close(id),
},
description: "您可以继续使用 HeroUI Chat",
});
}}
>
成功 Toast
{
const id = toast.warning("您的积分已用完", {
actionProps: {
children: "升级",
className: "bg-warning text-warning-foreground",
onPress: () => toast.close(id),
},
description: "升级付费方案以继续使用",
});
}}
>
警告 Toast
{
const id = toast.danger("存储空间已满", {
actionProps: {children: "删除", onPress: () => toast.close(id), variant: "danger"},
description: "删除文件以释放空间。此处增加更多文字以演示较长内容的显示效果",
indicator: ,
});
}}
>
危险 Toast
);
}
```
## 组件改进
### Tabs 的 secondary 变体
为 [Tabs](/docs/components/tabs) 新增 `secondary` 变体,使用下划线指示器样式。该变体同时支持水平与垂直方向。
```tsx
import {Tabs} from "@heroui/react";
export function Secondary() {
return (
概览
分析
报告
查看项目概览与近期活动。
跟踪指标并分析性能数据。
生成并下载详细报告。
);
}
```
**用法:**
```tsx
Overview
Analytics
Content
Content
```
### Input 变体
为 [Input](/docs/components/input) 组件新增 `primary` 与 `secondary` 变体:
* **`primary`**(默认):带阴影的标准样式,适用于大多数场景
* **`secondary`**:不带阴影的低调变体,适合在 Surface 组件内部使用
```tsx
import {Input} from "@heroui/react";
export function Variants() {
return (
);
}
```
### InputGroup 增强
[InputGroup](/docs/components/input-group) 组件获得多项改进:
**TextArea 支持**:可使用 `InputGroup.TextArea` 来构建带有 prefix 与 suffix 的多行文本输入。
```tsx
"use client";
import {ArrowUp, At, Microphone, PlugConnection, Plus} from "@gravity-ui/icons";
import {Button, InputGroup, Kbd, Spinner, TextField, Tooltip} from "@heroui/react";
import {useState} from "react";
export function WithTextArea() {
const [value, setValue] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = () => {
if (!value.trim()) return;
setIsSubmitting(true);
setTimeout(() => {
setIsSubmitting(false);
setValue("");
}, 1000);
};
return (
添加上下文
setValue(event.target.value)}
/>
添加文件等
连接应用
语音输入
{({isPending}) => (isPending ? : )}
发送
);
}
```
**变体**:新增与 Input 组件相匹配的 `primary` 与 `secondary` 变体。
```tsx
import {Envelope} from "@gravity-ui/icons";
import {InputGroup, Label, TextField} from "@heroui/react";
export function Variants() {
return (
主要变体
次要变体
);
}
```
### Button 与 ButtonGroup 的 outline 变体
为 [Button](/docs/components/button) 与 [ButtonGroup](/docs/components/button-group) 同时新增 `outline` 变体,用于呈现描边样式。
```tsx
import {Button, ButtonGroup} from "@heroui/react";
export function OutlineVariant() {
return (
);
}
```
### AlertDialog 尺寸支持
为 [AlertDialog](/docs/components/alert-dialog) 组件新增尺寸支持,让你可以控制对话框的大小。
```tsx
"use client";
import {Rocket} from "@gravity-ui/icons";
import {AlertDialog, Button} from "@heroui/react";
const SIZE_LABELS = {
cover: "通栏",
lg: "大",
md: "中",
sm: "小",
xs: "超小",
} as const;
export function Sizes() {
const sizes = ["xs", "sm", "md", "lg", "cover"] as const;
return (
{sizes.map((size) => (
{SIZE_LABELS[size]}
尺寸:{SIZE_LABELS[size]}
{size === "cover" ? (
<>
此警告框使用 cover 尺寸:在移动端与桌面端保留边距(移动端约
16px、桌面端约
40px)铺满可视区域,仍保持圆角与标准内边距,适合需要最大宽度又保留对话框气质的关键确认。
>
) : (
<>
此警告框使用 {size}{" "}
尺寸。在移动端各尺寸都会接近全宽以便阅读;在桌面端则对应不同的最大宽度,以适配不同信息量。
>
)}
取消
确认
))}
);
}
```
### Checkbox 动画改进
为 [Checkbox](/docs/components/checkbox) 提供更快的动画与更粗的描边宽度,反馈更明显。
```tsx
import {Checkbox} from "@heroui/react";
export function Basic() {
return (
接受条款与条件
);
}
```
### Link 的文本装饰
[Link](/docs/components/link) 组件现在使用 Tailwind CSS 类来设置文本装饰,而不再依赖内置变体。这样既更灵活,也更贴合 Tailwind 的使用习惯。
**可用的 Tailwind 工具类:**
* `underline` —— 始终显示下划线
* `no-underline` —— 移除下划线
* `hover:underline` —— 仅在悬停时显示下划线
* `decoration-primary`、`decoration-secondary` 等 —— 设置下划线颜色
* `decoration-1`、`decoration-2`、`decoration-4` —— 控制下划线粗细
* `underline-offset-1`、`underline-offset-2` 等 —— 调整下划线偏移
```tsx
import {Link} from "@heroui/react";
export function LinkUnderlineAndOffset() {
return (
调整下划线偏移
偏移 1(1px 间距)
偏移 2(2px 间距)
偏移 3(3px 间距)
偏移 4(4px 间距)
);
}
```
## ⚠️ 破坏性变更
### Link 组件 —— 移除下划线相关变体
Link 组件内置的 `underline` 与 `underlineOffset` prop 已被移除。请改用 Tailwind CSS 类来控制文本装饰。
**之前:**
```tsx
Link text
```
**之后:**
```tsx
Link text
```
**可用的 Tailwind 类:**
* `underline`、`no-underline`、`hover:underline` —— 装饰线
* `decoration-primary`、`decoration-muted` 等 —— 装饰线颜色
* `decoration-solid`、`decoration-dashed`、`decoration-dotted` —— 装饰线样式
* `decoration-1`、`decoration-2`、`decoration-4` —— 装饰线粗细
* `underline-offset-1`、`underline-offset-2`、`underline-offset-4` —— 下划线偏移
详见 [Link 文档](/docs/components/link)。
### 表单组件 —— 移除 `isInSurface` prop
`isInSurface` prop 以及自动 surface 检测已从基于表单的组件中移除。当你将表单组件放置在 Surface、Card 或其他基于 Surface 的容器中时,请改用 `variant="secondary"`。
**之前:**
```tsx
{/* Input automatically detected surface context */}
```
**之后:**
```tsx
{/* Use variant="secondary" for surface backgrounds */}
```
**受影响的组件:**
* Input
* InputGroup
* TextField
* TextArea
* SearchField
* NumberField
* DateField
* TimeField
* Select
* ComboBox
* Autocomplete
`secondary` 变体提供不带阴影的低调样式,更适合在 surface 背景上使用。
## 样式修复
* **Button**:更新 secondary 按钮颜色,提升视觉一致性
* **Checkbox**:优化动画速度并加粗描边,反馈更明显(详见 [Checkbox 动画改进](#checkbox-animation-improvements))
* **Link**:更新装饰线样式与过渡时长
* **Focus Visible**:在 focus-visible 选择器中加入 `:not(:focus)`,避免与 hover 状态冲突
* **Separator**:将固定样式仅应用到水平方向的分隔线
## Bug 修复
* 修复使用按钮变体样式的 Link
* 修复 Safari 中 BEM 样式下 Fieldset 的 Flexbox 兼容性问题
* 修复 SearchField 在空状态时未正确禁用清除按钮的问题
* 修复 ButtonGroup 的 context 仅对直接子元素生效的问题
* 修复 ButtonGroup 中 `BUTTON_GROUP_CHILD` 重新导出的类型声明
## 依赖更新
### 直接从 React Aria Components 重新导出
HeroUI 现在直接从 `react-aria-components` 重新导出了一系列基元与工具,方便你访问。这些导出对于 [React Aria 框架配置](https://react-aria.adobe.com/frameworks) 尤其有用。
**Provider:**
* `RouterProvider` —— 配置 React Aria 的 Link 使用客户端路由器
* `I18nProvider` —— 设置 React Aria Components 使用的 locale
**Hook 与工具:**
* `isRTL` —— 检查某个 locale 是否为从右到左
* `useLocale` —— 访问当前 locale 与方向
* `useFilter` —— 对集合进行过滤与排序
**组件:**
* `Collection` —— 用于管理列表的集合组件
* `ListBoxLoadMoreItem` —— 用于加载更多条目的 ListBox 项
**国际化工具:**
* `getLocalizationScript` —— 获取用于服务端渲染的本地化脚本(来自 `react-aria-components/i18n`)
以上这些都可以直接从 `@heroui/react` 引入:
```tsx
import {
RouterProvider,
I18nProvider,
isRTL,
useLocale,
useFilter,
getLocalizationScript
} from "@heroui/react";
```
## 链接
* [主题构建器](/themes)
* [组件文档](/docs/react/components)
* [设计系统 - Figma Kit v3(已更新)](https://www.figma.com/community/file/1546526812159103429/heroui-figma-kit-v3)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #6121](https://github.com/heroui-inc/heroui/pull/6121)
## 贡献者
感谢每一位为本次发布做出贡献的开发者!
# v3.0.0-beta.6
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-0-beta-6
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-0-beta-6.mdx
> 新增 6 个颜色组件(ColorPicker、ColorArea、ColorSlider、ColorField、ColorSwatch、ColorSwatchPicker)、Toast 改进,以及多项样式修复。
2026 年 2 月 6 日
本次发布引入了完整的**颜色系统**,新增六个用于颜色选择与处理的组件:[ColorPicker](/docs/components/color-picker)、[ColorArea](/docs/components/color-area)、[ColorSlider](/docs/components/color-slider)、[ColorField](/docs/components/color-field)、[ColorSwatch](/docs/components/color-swatch) 与 [ColorSwatchPicker](/docs/components/color-swatch-picker)。同时还包含 [Separator](/docs/components/separator) 的新变体以及多项样式改进。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@beta @heroui/react@beta
```
```bash
pnpm add @heroui/styles@beta @heroui/react@beta
```
```bash
yarn add @heroui/styles@beta @heroui/react@beta
```
```bash
bun add @heroui/styles@beta @heroui/react@beta
```
**正在使用 AI 助手?** 只需对它说一句「Hey Cursor,把 HeroUI 升级到最新版本」,AI 助手就会自动对比版本并应用必要的变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新增功能
### 颜色系统
我们很高兴推出完整的**颜色系统**——一整套用于颜色选择、处理与展示的组件。这些组件基于 React Aria 的颜色基元构建,可以无缝协同工作。
**主要特性:**
* **完整的色彩空间支持**:支持 HSL、HSB 与 RGB 色彩空间
* **基于通道的编辑**:可单独操作每一个颜色通道(hue、saturation、lightness、brightness、red、green、blue、alpha)
* **默认无障碍**:完整支持键盘导航与屏幕阅读器
* **可组合的设计**:自由搭配组件,构建你自己的颜色选择器
### 新组件
本次发布共引入 **6 个** 新的颜色组件:
* **[ColorPicker](#colorpicker)**:完整的颜色选择器,包含 trigger、popover 以及可组合的内部部件。([文档](/docs/components/color-picker))
* **[ColorArea](#colorarea)**:二维渐变区域,可同时选择两个颜色通道。([文档](/docs/components/color-area))
* **[ColorSlider](#colorslider)**:单通道滑块,用于精细调整颜色。([文档](/docs/components/color-slider))
* **[ColorField](#colorfield)**:用于输入与编辑颜色值的文本框。([文档](/docs/components/color-field))
* **[ColorSwatch](#colorswatch)**:可视化的颜色预览,支持透明度。([文档](/docs/components/color-swatch))
* **[ColorSwatchPicker](#colorswatchpicker)**:可选的颜色块网格,便于快速选择颜色。([文档](/docs/components/color-swatch-picker))
### ColorPicker
ColorPicker 是一个复合组件,将所有颜色组件组合在一起,提供完整的颜色选择体验。
```tsx
import {ColorArea, ColorPicker, ColorSlider, ColorSwatch, Label} from "@heroui/react";
export function Basic() {
return (
选择颜色
色相
);
}
```
### ColorArea
二维渐变区域,可同时选择两个颜色通道,通常用于 saturation 与 brightness。
```tsx
import {ColorArea} from "@heroui/react";
export function ColorAreaBasic() {
return (
);
}
```
### ColorSlider
用于调整单个颜色通道(如 hue、saturation、lightness 或 alpha)的滑块。
```tsx
import {ColorSlider, Label} from "@heroui/react";
export function Basic() {
return (
色相
);
}
```
**不同的通道:**
```tsx
"use client";
import {ColorSlider, ColorSwatch, Label} from "@heroui/react";
import {useState} from "react";
import {parseColor} from "react-aria-components";
export function Channels() {
const [color, setColor] = useState(parseColor("hsl(0, 100%, 50%)"));
return (
色相
饱和度
明度
当前颜色:{color.toString("hsl")}
);
}
```
### ColorField
用于直接输入颜色值的文本输入框,支持多种颜色格式。
```tsx
"use client";
import type {Color} from "@heroui/react";
import {ColorField, ColorSwatch, Label, parseColor} from "@heroui/react";
import {useState} from "react";
export function Basic() {
const [color, setColor] = useState(parseColor("#0485F7"));
return (
颜色
);
}
```
### ColorSwatch
颜色值的可视化展示,支持透明度图案。
```tsx
import {ColorSwatch} from "@heroui/react";
export function ColorSwatchBasic() {
return (
);
}
```
### ColorSwatchPicker
色块网格,可从预定义的调色板中快速选择颜色。
```tsx
import {ColorSwatchPicker} from "@heroui/react";
const colors = ["#F43F5E", "#D946EF", "#8B5CF6", "#3B82F6", "#06B6D4", "#10B981", "#84CC16"];
export function Basic() {
return (
{colors.map((color) => (
))}
);
}
```
## 组件改进
### Toast 增强
[Toast](/docs/components/toast) 组件经过了重大改进,新增了多项功能并提升了稳定性(#6151):
**新功能:**
* **加载状态**:新增 `isLoading` prop,会显示一个 spinner 替代默认指示器
* **默认超时**:Toast 现在默认 4 秒后自动关闭(可通过 `timeout` prop 配置)
* **宽度控制**:在 `Toast.Provider` 上新增 `width` prop,可自定义 Toast 的宽度
* **自适应高度**:Toast 会根据内容自适应高度
* **更好的堆叠效果**:通过绝对定位与高度同步,修复了 Toast 堆叠时出现的布局抖动
* **更稳健的关闭处理**:将 `onClose` 回调延迟执行,避免 Toast 过渡死锁
* **仅最前 Toast 显示关闭按钮**:关闭按钮仅出现在最前一个 Toast 上,UI 更加干净
* **Promise 支持增强**:改进了 `toast.promise()`,加载状态与错误处理更加完善
**新增演示:**
* Promise 与加载状态
* 回调与超时处理
```tsx
"use client";
import {HardDrive, Persons} from "@gravity-ui/icons";
import {Button, toast} from "@heroui/react";
export function Variants() {
return (
{
const id = toast("您已被邀请加入团队", {
actionProps: {
children: "忽略",
onPress: () => toast.close(id),
variant: "tertiary",
},
description: "Bob 邀请您加入 HeroUI 团队",
indicator: ,
variant: "default",
});
}}
>
默认 Toast
{
const id = toast.info("您还剩 2 个积分", {
actionProps: {children: "升级", onPress: () => toast.close(id)},
description: "升级付费方案以获取更多积分",
});
}}
>
强调 Toast
{
const id = toast.success("您已升级方案", {
actionProps: {
children: "账单",
className: "bg-success text-success-foreground",
onPress: () => toast.close(id),
},
description: "您可以继续使用 HeroUI Chat",
});
}}
>
成功 Toast
{
const id = toast.warning("您的积分已用完", {
actionProps: {
children: "升级",
className: "bg-warning text-warning-foreground",
onPress: () => toast.close(id),
},
description: "升级付费方案以继续使用",
});
}}
>
警告 Toast
{
const id = toast.danger("存储空间已满", {
actionProps: {children: "删除", onPress: () => toast.close(id), variant: "danger"},
description: "删除文件以释放空间。此处增加更多文字以演示较长内容的显示效果",
indicator: ,
});
}}
>
危险 Toast
);
}
```
### Separator 变体
为 [Separator](/docs/components/separator) 组件新增了变体,提供不同的视觉风格。
### Chip 组件 —— Label slot
[Chip](/docs/components/chip) 组件现在支持 `Chip.Label` 子组件,以获得更好的视觉对齐。当移除起始或末尾的内容(如图标)时,标签文字会过于贴近 Chip 的边缘。为了向后兼容,纯文本的 children 会自动被包裹在 `` 中。
**用法:**
```tsx
import { Chip } from '@heroui/react';
// Automatic wrapping (backward compatible)
Label text
// Explicit label with custom styling
Custom Label
// Mixing icons and labels
With Icon
```
## 样式修复
* **浮层内容**:修复了浮层内容上的模糊效果(#6136)
* **Invalid 字段**:在字段处于 invalid 状态时,将 ring 改为 outline(#6184)
* **Link 与按钮**:修复了使用按钮变体的 Link 组件的样式(#6138)
* **Toast 内容**:修复了 Toast 内容的垂直对齐问题(#6147)
* **Safari SVG**:修复了 SVG 在 Safari 中位置偏移的问题(#6149)
* **Placeholder 颜色**:将 placeholder 的颜色与输入文本对齐(#6139)
* **Tooltip**:从 tooltip 触发组件中移除了 cursor 样式
* **CSS 变量**:让计算变量仅依赖根变量(#6154)
## Bug 修复
* 修复了视图过渡期间页面交互不可用的问题(#6128)
* 修复了 Markdown URL 的格式化问题(#6162)
* 修复了指向 ComboBox 页面的链接错误(#6164)
* 修复了 `index.css` 中 Autocomplete 样式的引入顺序
* 修复了 CSS 类名的连字符格式(#6191)
## ⚠️ 破坏性变更
### Toast 组件 —— Container 重命名为 Provider
为提升语义清晰度,`Toast.Container` 已重命名为 `Toast.Provider`(#6151)。
**之前:**
```tsx
```
**之后:**
```tsx
```
**其他变更:**
* 默认的 `gap` prop 从 `14` 改为 `12` 像素
* 默认 `timeout` 现在为 `4000`(4 秒),无需再显式设置
* 为保持一致性,`Toast.Action` 已重命名为 `Toast.ActionButton`
### CSS 类名命名约定
为了一致性,CSS 类名已统一改为连字符格式(#6141)。这一调整更贴合 BEM 规范,也提升了与 Tailwind CSS 的兼容性。
**重要说明**:`textarea` 类名最初被改为 `text-area`,但由于与 Tailwind 原生的 `textarea` 类名冲突,已在 PR #6191 中回滚为 `textarea`。TextArea 组件相关的类名无需修改。
#### 组件类名变更
以下 CSS 类名已更新。如果你的自定义 CSS 直接使用了这些类名,请同步更新选择器:
| 组件 | 旧类名 | 新类名 | 说明 |
| ------------------ | -------------------------- | --------------------------- | ------------------------------ |
| **ComboBox** | `.combobox` | `.combo-box` | 全部相关类名同步更新 |
| | `.combobox__input-group` | `.combo-box__input-group` | |
| | `.combobox__trigger` | `.combo-box__trigger` | |
| | `.combobox__popover` | `.combo-box__popover` | |
| | `.combobox--full-width` | `.combo-box--full-width` | |
| **ListBox** | `.listbox` | `.list-box` | 全部相关类名同步更新 |
| **ListBoxItem** | `.listbox-item` | `.list-box-item` | 全部相关类名同步更新 |
| | `.listbox-item__indicator` | `.list-box-item__indicator` | |
| | `.listbox-item--default` | `.list-box-item--default` | |
| | `.listbox-item--danger` | `.list-box-item--danger` | |
| **ListBoxSection** | `.listbox-section` | `.list-box-section` | 全部相关类名同步更新 |
| **TextArea** | `.textarea` | `.textarea` | **未变更** —— 为避免与 Tailwind 冲突已回滚 |
#### 迁移指南
**之前:**
```css
/* Custom styles targeting old class names */
.combobox {
/* styles */
}
.listbox-item {
/* styles */
}
```
**之后:**
```css
/* Update to new hyphenated class names */
.combo-box {
/* styles */
}
.list-box-item {
/* styles */
}
```
**JavaScript / TypeScript 更新:**
如果你在 JavaScript 或 TypeScript 代码中使用了这些类名:
```tsx
// Before
// After
```
**说明**:组件 props 与 TypeScript 类型保持不变,仅 CSS 类名做了更新。
### 移除的 CSS 变量
作为 surface 颜色重构的一部分,部分 CSS 变量已被移除(#6204)。这些变量要么改为直接引用其他变量,要么被完全移除。
#### Surface 颜色变量
以下经过计算的 surface 颜色变量已被移除,并改为直接引用对应的变量:
**已移除:**
* `--color-surface-secondary`(之前通过 `color-mix` 计算得到)
* `--color-surface-tertiary`(之前通过 `color-mix` 计算得到)
**替代方案:**
这些变量现在直接引用 `variables.css` 中定义的基础变量:
* `--color-surface-secondary` → 直接使用 `var(--surface-secondary)`
* `--color-surface-tertiary` → 直接使用 `var(--surface-tertiary)`
基础变量 `--surface-secondary` 与 `--surface-tertiary` 现在直接定义在 `variables.css` 中,而不再在 `theme.css` 中通过计算得出。
#### On Surface 颜色变量
所有 `--color-on-surface-*` 变量都已被完全移除:
**已移除:**
* `--color-on-surface`
* `--color-on-surface-foreground`
* `--color-on-surface-hover`
* `--color-on-surface-focus`
* `--color-on-surface-secondary`
* `--color-on-surface-secondary-foreground`
* `--color-on-surface-secondary-hover`
* `--color-on-surface-secondary-focus`
* `--color-on-surface-tertiary`
* `--color-on-surface-tertiary-foreground`
* `--color-on-surface-tertiary-hover`
* `--color-on-surface-tertiary-focus`
**迁移方式:**
如果你之前用到了这些变量,请改用对应的 surface 变量:
```css
/* Before */
.element {
background: var(--color-on-surface);
color: var(--color-on-surface-foreground);
}
.element:hover {
background: var(--color-on-surface-hover);
}
/* After */
.element {
background: var(--surface-secondary);
color: var(--surface-secondary-foreground);
}
.element:hover {
background: color-mix(in oklab, var(--surface-secondary) 92%, var(--surface-secondary-foreground) 8%);
}
```
或者使用 Tailwind 工具类:
```tsx
// Before
// After
```
**相关 PR:** [#6204](https://github.com/heroui-inc/heroui/pull/6204)
## 链接
* [组件文档](/docs/react/components)
* [设计系统 - Figma Kit v3](https://www.figma.com/community/file/1546526812159103429/heroui-figma-kit-v3)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #6201](https://github.com/heroui-inc/heroui/pull/6201)
## 贡献者
感谢每一位为本次发布做出贡献的开发者!
# v3.0.0-beta.7
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-0-beta-7
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-0-beta-7.mdx
> 新增 4 个组件(Calendar、RangeCalendar、DatePicker、DateRangePicker)以及多项 API 改进。
2026 年 2 月 19 日
本次发布新增 4 个组件:[Calendar](/docs/components/calendar)、[RangeCalendar](/docs/components/range-calendar)、[DatePicker](/docs/components/date-picker) 与 [DateRangePicker](/docs/components/date-range-picker)。同时还引入了 [Switch.Content](#switchcontent),用于将 label 与 description 组合到 Switch 控件旁边;以及 [Tabs.Separator](#tabsseparator),用于在 Tab 之间按需添加分隔线。
⚠️ **破坏性变更**:从 Tabs 中移除了 `hideSeparator`;`DateInputGroup` 与 `ColorInputGroup` 已分别合并到 `DateField.Group`、`TimeField.Group` 与 `ColorField.Group` 之下。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@beta @heroui/react@beta
```
```bash
pnpm add @heroui/styles@beta @heroui/react@beta
```
```bash
yarn add @heroui/styles@beta @heroui/react@beta
```
```bash
bun add @heroui/styles@beta @heroui/react@beta
```
**正在使用 AI 助手?** 只需对它说一句「Hey Cursor,把 HeroUI 升级到最新版本」,AI 助手就会自动对比版本并应用必要的变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新增功能
### 日期与时间体系
**日期与时间** —— Calendar、DatePicker、RangeCalendar 与 DateRangePicker 均基于 React Aria 的日期基元构建。支持国际化、时区,以及完整的键盘导航与 ARIA 无障碍能力。
**主要特性:**
* **历法系统**:公历、佛历、波斯历等
* **年份选择器**:用于快速跳转年份的浮层
* **单元格指示器**:在单元格上展示事件、可用状态或状态点
* **范围选择**:日期范围带有视觉高亮
* **无障碍**:键盘导航、屏幕阅读器、ARIA 全部支持
所有日期值都使用 [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/) 提供的类型(`CalendarDate`、`CalendarDateTime`、`ZonedDateTime`)。可以用 [`I18nProvider`](https://react-aria.adobe.com/I18nProvider) 覆盖区域设置,并通过 [`useLocale`](https://react-aria.adobe.com/useLocale) 读取它。
### 新组件
* **[Calendar](#calendar)**:单日期选择,支持年份选择器、指示器与多月份显示。([文档](/docs/components/calendar))
* **[RangeCalendar](#rangecalendar)**:日期范围选择,支持范围高亮与多月份显示。([文档](/docs/components/range-calendar))
* **[DatePicker](#datepicker)**:日期输入框 + popover 日历。([文档](/docs/components/date-picker))
* **[DateRangePicker](#daterangepicker)**:两个日期输入框 + popover 范围日历。([文档](/docs/components/date-range-picker))
### Calendar
支持单日期选择的日历,包含年份选择器、单元格指示器、多月份视图以及国际化历法。
```tsx
"use client";
import {Calendar} from "@heroui/react";
export function Basic() {
return (
{(day) => {day} }
{(date) => }
);
}
```
**年份选择器:**
```tsx
"use client";
import {Calendar} from "@heroui/react";
export function YearPicker() {
return (
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
**国际化历法:**
```tsx
"use client";
import {Calendar} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
import {I18nProvider} from "react-aria-components";
export function InternationalCalendar() {
return (
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
### RangeCalendar
日期范围选择,支持范围高亮与多月份视图。
```tsx
"use client";
import {RangeCalendar} from "@heroui/react";
export function Basic() {
return (
{(day) => {day} }
{(date) => }
);
}
```
**多月份显示:**
```tsx
"use client";
import {RangeCalendar} from "@heroui/react";
export function MultipleMonths() {
return (
{(day) => {day} }
{(date) => }
{(day) => {day} }
{(date) => }
);
}
```
### DatePicker
日期输入框 + popover 日历。支持格式选项、国际化、自定义指示器与表单校验。
```tsx
"use client";
import {Calendar, DateField, DatePicker, Label} from "@heroui/react";
export function Basic() {
return (
日期
{(segment) => }
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
**日期与时间(搭配 TimeField):**
```tsx
"use client";
import type {TimeValue} from "@heroui/react";
import type {DateValue} from "@internationalized/date";
import {
Calendar,
DateField,
DatePicker,
Label,
ListBox,
Select,
Switch,
TimeField,
} from "@heroui/react";
import {getLocalTimeZone, parseDate, parseZonedDateTime} from "@internationalized/date";
import {useMemo, useState} from "react";
type Granularity = "day" | "hour" | "minute" | "second";
type HourCycle = 12 | 24;
const granularityOptions: {label: string; value: Granularity}[] = [
{label: "日", value: "day"},
{label: "时", value: "hour"},
{label: "分", value: "minute"},
{label: "秒", value: "second"},
];
const hourCycleOptions: {label: string; value: HourCycle}[] = [
{label: "12 小时制", value: 12},
{label: "24 小时制", value: 24},
];
export function FormatOptions() {
const [granularity, setGranularity] = useState("minute");
const [hourCycle, setHourCycle] = useState(12);
const [hideTimeZone, setHideTimeZone] = useState(false);
const [shouldForceLeadingZeros, setShouldForceLeadingZeros] = useState(false);
const timeGranularity = granularity !== "day" ? granularity : undefined;
const showTimeField = !!timeGranularity;
const defaultValue = useMemo(() => {
const localTimeZone = getLocalTimeZone();
if (granularity === "day") {
return parseDate("2026-02-03");
}
return parseZonedDateTime(`2026-02-03T08:45:00[${localTimeZone}]`);
}, [granularity]);
return (
{({state}) => (
<>
日期和时间
{(segment) => }
{(day) => {day} }
{(date) => }
{({year}) => }
{!!showTimeField && (
时间
state.setTimeValue(v as TimeValue)}
>
{(segment) => }
)}
>
)}
setGranularity(value as Granularity)}
>
粒度
{granularityOptions.map((option) => (
{option.label}
))}
setHourCycle(Number(value) as HourCycle)}
>
小时制
{hourCycleOptions.map((option) => (
{option.label}
))}
隐藏时区
强制前导零
);
}
```
### DateRangePicker
两个日期输入框 + popover 范围日历。
```tsx
"use client";
import {DateField, DateRangePicker, Label, RangeCalendar} from "@heroui/react";
export function Basic() {
return (
出行日期
{(segment) => }
{(segment) => }
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
## API 改进
### Switch.Content
`Switch.Content` 用于将 label 与 description 组合到 Switch 控件旁边([#6240](https://github.com/heroui-inc/heroui/pull/6240))。
**之前:**
```tsx
import { Switch, Label, Description } from '@heroui/react';
Email notifications
Get notified when someone mentions you
```
### Tabs.Separator
[Tabs](/docs/components/tabs) 组件现在新增了一个显式的 `Tabs.Separator` 子组件,用于在 Tab 之间添加视觉分隔线。它取代了之前自动生成的 CSS 伪元素分隔线以及 `hideSeparator` prop([#6243](https://github.com/heroui-inc/heroui/pull/6243))。
分隔线现在改为 **按需启用** —— 在希望出现分隔线的 `` 内部添加 ` ` 即可。
### Field 子组件的合并
`DateField`、`TimeField` 与 `ColorField` 现在直接暴露各自的输入组子组件,不再需要单独引入 `DateInputGroup` 或 `ColorInputGroup`。具体的迁移方式请参阅 [破坏性变更](#-breaking-changes)。
### Breadcrumbs 修复
传给 `Breadcrumbs.Item` 的 props 现在会正确转发到底层的 `Link`([#6233](https://github.com/heroui-inc/heroui/pull/6233))。
## 样式修复
* **ListBox Item**:将悬停背景色从 `bg-default-hover` 调整为 `bg-default`,以保持一致性
* **Date Input Group**:将段(segment)文本从 `tabular-nums` 调整为 `text-nowrap`,优化布局
* **Date Input Group**:改进 focus-within 样式,使其将日期选择器触发器排除在字段聚焦高亮之外
## 依赖更新
* **React Aria Components**:从 `1.14.0` 升级到 `1.15.0` —— 新增了 [`render` prop](https://react-aria.adobe.com/customization#dom-elements),可用于自定义任何 React Aria 组件渲染的 DOM 元素(适用于路由链接、Motion 等动画库)
* **@react-aria/utils**:从 `3.32.0` 升级到 `3.33.0`
* **@react-types/shared**:从 `3.32.1` 升级到 `3.33.0`
* **@internationalized/date**:从 `3.10.1` 升级到 `3.11.0` —— 日期字段现在改为在失焦时进行约束,而不是在输入过程中实时约束
* 新增 `@react-aria/i18n` 与 `@react-stately/utils`,用于日历的国际化
## ⚠️ 破坏性变更
### Tabs —— 移除 `hideSeparator` prop
`hideSeparator` prop 已从 Tabs 组件中移除。分隔线现在改为 **按需启用**,通过新增的 ` ` 子组件来添加,而不再通过 CSS 伪元素自动生成([#6243](https://github.com/heroui-inc/heroui/pull/6243))。
**之前:**
```tsx
{/* Separators shown by default, hidden via prop */}
Tab 1
Tab 2
```
**之后:**
```tsx
{/* No separators by default — explicitly add them where needed */}
Tab 1
Tab 2
```
**CSS 变更:**
* Tab 的分隔线样式已从伪元素(`.tabs__tab:not(:first-child):before`)迁移到独立的 `.tabs__separator` 类
* 已移除 `[data-hide-separator]` 这一 data 属性
### Field 子组件 API 变更
`DateInputGroup` 与 `ColorInputGroup` 不再从 `@heroui/react` 直接导出。它们的子组件已分别合并到对应的 Field 组件之下(`DateField`、`TimeField`、`ColorField`)。
#### DateField 变更
**之前:**
```tsx
import {DateField, Label, DateInputGroup, Description} from '@heroui/react';
Date
...
{(segment) => }
...
Pick a date
```
**之后:**
```tsx
import {DateField, Label, Description} from '@heroui/react';
Date
...
{(segment) => }
...
Pick a date
```
#### TimeField 变更
模式与 DateField 相同:
| 之前 | 之后 |
| ------------------------ | ------------------- |
| `DateInputGroup` | `TimeField.Group` |
| `DateInputGroup.Input` | `TimeField.Input` |
| `DateInputGroup.Segment` | `TimeField.Segment` |
| `DateInputGroup.Prefix` | `TimeField.Prefix` |
| `DateInputGroup.Suffix` | `TimeField.Suffix` |
#### ColorField 变更
| 之前 | 之后 |
| ------------------------ | ------------------- |
| `ColorInputGroup` | `ColorField.Group` |
| `ColorInputGroup.Input` | `ColorField.Input` |
| `ColorInputGroup.Prefix` | `ColorField.Prefix` |
| `ColorInputGroup.Suffix` | `ColorField.Suffix` |
**用法:**
```tsx
import {ColorField, Label, ColorInputGroup, ColorSwatch} from '@heroui/react';
Color
```
**之后:**
```tsx
import {ColorField, Label, ColorSwatch} from '@heroui/react';
Color
```
> **说明:** 底层的 CSS 类名(`.date-input-group`、`.color-input-group` 等)保持不变,仅 JavaScript 引入路径与组件名称发生了变化。
## 链接
* [组件文档](/docs/react/components)
* [设计系统 - Figma Kit v3](https://www.figma.com/community/file/1546526812159103429/heroui-figma-kit-v3)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #6237](https://github.com/heroui-inc/heroui/pull/6237)
## 贡献者
感谢每一位为本次发布做出贡献的开发者!
# v3.0.0-beta.8
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-0-beta-8
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-0-beta-8.mdx
> 新增 3 个组件(Badge、Pagination、Table)、DateField 的多项改进,以及关键的 API / 样式修复。
2026 年 3 月 2 日
本次发布新增三个组件:[Badge](/docs/components/badge)、[Pagination](/docs/components/pagination) 与 [Table](/docs/components/table),并为 [DateField](/docs/components/date-field) 与 [TimeField](/docs/components/time-field) 提供了新的 `InputContainer` 组合 API。
⚠️ **破坏性变更**:TextField 的 CSS 类已从 `.text-field` 重命名为 `.textfield`。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@beta @heroui/react@beta
```
```bash
pnpm add @heroui/styles@beta @heroui/react@beta
```
```bash
yarn add @heroui/styles@beta @heroui/react@beta
```
```bash
bun add @heroui/styles@beta @heroui/react@beta
```
**正在使用 AI 助手?** 只需对它说一句「Hey Cursor,把 HeroUI 升级到最新版本」,AI 助手就会自动对比版本并应用必要的变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新增功能
### 新组件
* **[Badge](#badge)**:紧凑的状态 + 计数指示器,可配置颜色、变体、放置位置与尺寸。([文档](/docs/components/badge))
* **[Pagination](#pagination)**:分页相关的复合组件基元,提供摘要、省略号以及上一页 / 下一页等控件。([文档](/docs/components/pagination))
* **[Table](#table)**:数据表格基元,支持排序、选择、列宽调整、异步加载以及表脚组合。([文档](/docs/components/table))
### Badge
新增徽章基元,可用于计数、标签以及通过 `Badge.Anchor` 与 `Badge.Label` 锚定的浮层。
```tsx
import {Avatar, Badge} from "@heroui/react";
const GREEN_AVATAR_URL = "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/green.jpg";
const ORANGE_AVATAR_URL =
"https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/orange.jpg";
const BLUE_AVATAR_URL = "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/blue.jpg";
export function BadgeBasic() {
return (
);
}
```
### Pagination
新增导航组件,由可组合的部件构成(`Root`、`Content`、`Item`、`Link`、`Previous`、`Next`、`Summary`、`Ellipsis`)。
```tsx
"use client";
import {Pagination} from "@heroui/react";
import {useState} from "react";
export function PaginationWithEllipsis() {
const [page, setPage] = useState(1);
const totalPages = 12;
const getPageNumbers = () => {
const pages: (number | "ellipsis")[] = [];
pages.push(1);
if (page > 3) {
pages.push("ellipsis");
}
const start = Math.max(2, page - 1);
const end = Math.min(totalPages - 1, page + 1);
for (let i = start; i <= end; i++) {
pages.push(i);
}
if (page < totalPages - 2) {
pages.push("ellipsis");
}
pages.push(totalPages);
return pages;
};
return (
setPage((p) => p - 1)}>
上一页
{getPageNumbers().map((p, i) =>
p === "ellipsis" ? (
) : (
setPage(p)}>
{p}
),
)}
setPage((p) => p + 1)}>
下一页
);
}
```
### Table
基于 React Aria 构建的复合数据表格,支持可排序的列、行选择、自定义单元格、加载更多哨兵行以及可调整宽度的列。
```tsx
import {Table} from "@heroui/react";
export function Basic() {
return (
姓名
角色
状态
邮箱
Kate Moore
首席执行官
在职
kate@acme.com
John Smith
首席技术官
在职
john@acme.com
Sara Johnson
首席营销官
休假
sara@acme.com
Michael Brown
首席财务官
在职
michael@acme.com
);
}
```
**自定义单元格:**
```tsx
"use client";
import type {Selection, SortDescriptor} from "@heroui/react";
import {Avatar, Button, Checkbox, Chip, Table} from "@heroui/react";
import {Icon} from "@iconify/react";
import {useMemo, useState} from "react";
interface User {
id: number;
name: string;
image_url: string;
role: string;
status: "在职" | "未激活" | "休假";
email: string;
}
const statusColorMap: Record = {
休假: "warning",
在职: "success",
未激活: "danger",
};
const users: User[] = [
{
email: "kate@acme.com",
id: 4586932,
image_url: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/red.jpg",
name: "Kate Moore",
role: "首席执行官",
status: "在职",
},
{
email: "john@acme.com",
id: 5273849,
image_url: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/green.jpg",
name: "John Smith",
role: "首席技术官",
status: "在职",
},
{
email: "sara@acme.com",
id: 7492836,
image_url: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/blue.jpg",
name: "Sara Johnson",
role: "首席营销官",
status: "休假",
},
{
email: "michael@acme.com",
id: 8293746,
image_url: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/purple.jpg",
name: "Michael Brown",
role: "首席财务官",
status: "在职",
},
{
email: "emily@acme.com",
id: 1234567,
image_url: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/orange.jpg",
name: "Emily Davis",
role: "产品经理",
status: "未激活",
},
];
export function CustomCells() {
const [selectedKeys, setSelectedKeys] = useState(new Set());
const [sortDescriptor, setSortDescriptor] = useState({
column: "name",
direction: "ascending",
});
const sortedUsers = useMemo(() => {
return [...users].sort((a, b) => {
const col = sortDescriptor.column as keyof User;
const first = String(a[col]);
const second = String(b[col]);
let cmp = first.localeCompare(second);
if (sortDescriptor.direction === "descending") {
cmp *= -1;
}
return cmp;
});
}, [sortDescriptor]);
return (
{({sortDirection}) => (
员工 ID
)}
{({sortDirection}) => (
成员
)}
{({sortDirection}) => (
角色
)}
{({sortDirection}) => (
状态
)}
操作
{sortedUsers.map((user) => (
#{user.id.toString()}{" "}
{user.name
.split(" ")
.map((n) => n[0])
.join("")}
{user.name}
{user.email}
{user.role}
{user.status}
))}
);
}
```
**分页:**
```tsx
"use client";
import {Pagination, Table} from "@heroui/react";
import {useMemo, useState} from "react";
const columns = [
{id: "name", name: "姓名"},
{id: "role", name: "角色"},
{id: "status", name: "状态"},
{id: "email", name: "邮箱"},
];
const users = [
{email: "kate@acme.com", id: 1, name: "Kate Moore", role: "首席执行官", status: "在职"},
{email: "john@acme.com", id: 2, name: "John Smith", role: "首席技术官", status: "在职"},
{email: "sara@acme.com", id: 3, name: "Sara Johnson", role: "首席营销官", status: "休假"},
{email: "michael@acme.com", id: 4, name: "Michael Brown", role: "首席财务官", status: "在职"},
{
email: "emily@acme.com",
id: 5,
name: "Emily Davis",
role: "产品经理",
status: "未激活",
},
{email: "davis@acme.com", id: 6, name: "Davis Wilson", role: "首席设计师", status: "在职"},
{
email: "olivia@acme.com",
id: 7,
name: "Olivia Martinez",
role: "前端工程师",
status: "在职",
},
{
email: "james@acme.com",
id: 8,
name: "James Taylor",
role: "后端工程师",
status: "在职",
},
];
const ROWS_PER_PAGE = 4;
export function PaginationDemo() {
const [page, setPage] = useState(1);
const totalPages = Math.ceil(users.length / ROWS_PER_PAGE);
const pages = Array.from({length: totalPages}, (_, i) => i + 1);
const paginatedItems = useMemo(() => {
const start = (page - 1) * ROWS_PER_PAGE;
return users.slice(start, start + ROWS_PER_PAGE);
}, [page]);
const start = (page - 1) * ROWS_PER_PAGE + 1;
const end = Math.min(page * ROWS_PER_PAGE, users.length);
return (
{(column) => (
{column.name}
)}
{(user) => (
{(column) => {user[column.id as keyof typeof user]} }
)}
{start}–{end} / 共 {users.length} 条
setPage((p) => Math.max(1, p - 1))}
>
上一页
{pages.map((p) => (
setPage(p)}>
{p}
))}
setPage((p) => Math.min(totalPages, p + 1))}
>
下一页
);
}
```
**空状态:**
```tsx
"use client";
import {EmptyState, Table} from "@heroui/react";
import {Icon} from "@iconify/react";
export function EmptyStateDemo() {
return (
姓名
角色
状态
邮箱
(
未找到结果
)}
>
{[]}
);
}
```
## 组件 + API 改进
### DateField 与 TimeField 的增强
`DateField` 与 `TimeField` 现在暴露了 `InputContainer`,用于在前缀与后缀内容之间包裹输入段(segment)。
**之前:**
```tsx
...
{(segment) => }
...
```
**之后:**
```tsx
...
{(segment) => }
...
```
```tsx
"use client";
import type {TimeValue} from "@heroui/react";
import {DateField, DateRangePicker, Label, RangeCalendar, TimeField} from "@heroui/react";
import {getLocalTimeZone, parseZonedDateTime} from "@internationalized/date";
export function InputContainer() {
const localTimeZone = getLocalTimeZone();
const defaultValue = {
end: parseZonedDateTime(`2026-02-10T18:45:00[${localTimeZone}]`),
start: parseZonedDateTime(`2026-02-03T08:45:00[${localTimeZone}]`),
};
return (
{({state}) => (
<>
日期范围
{(segment) => }
{(segment) => }
{(day) => {day} }
{(date) => }
{({year}) => }
开始时间
state.setTimeRange({
end: state.timeRange?.end as TimeValue,
start: v as TimeValue,
})
}
>
{(segment) => }
结束时间
state.setTimeRange({
end: v as TimeValue,
start: state.timeRange?.start as TimeValue,
})
}
>
{(segment) => }
>
)}
);
}
```
## ⚠️ 破坏性变更
### TextField 类名 + 路径重命名
为避免与 Tailwind 的 `text-*` 工具类前缀冲突,TextField 的样式命名已统一调整。
| 组件 | 旧类名 | 新类名 | 说明 |
| ------------------------ | ------------------------- | ------------------------ | ------ |
| **TextField Root** | `.text-field` | `.textfield` | 根类名重命名 |
| **TextField Full Width** | `.text-field--full-width` | `.textfield--full-width` | 修饰类重命名 |
同一变更涉及的其他重命名:
* 样式文件:`text-field.css` -> `textfield.css`
* 样式导出路径:`@heroui/styles/src/components/text-field` -> `@heroui/styles/src/components/textfield`
## 样式修复
* **RangeCalendar**:为日历单元格添加圆角,优化范围选择的视觉效果([#6270](https://github.com/heroui-inc/heroui/pull/6270))
## Bug 修复
* 通过将 `isRequired` 转化为 `data-required`,为 **DatePicker** 与 **DateRangePicker** 补齐了必填状态的红色星号行为([#6270](https://github.com/heroui-inc/heroui/pull/6270))
* 修复了 **Autocomplete** 与 **Select** 中触发器无效状态样式缺失的问题——将 invalid 样式限定在根状态范围内([#6270](https://github.com/heroui-inc/heroui/pull/6270))
* 更新了 TextField 的文档与演示引用,使其指向新的 `textfield-*` demo key 以及对应的源码 / 样式路径([#6270](https://github.com/heroui-inc/heroui/pull/6270))
## 链接
* [组件文档](/docs/components)
* [设计系统 - Figma Kit v3](https://www.figma.com/community/file/1546526812159103429/heroui-figma-kit-v3)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #6270](https://github.com/heroui-inc/heroui/pull/6270)
## 贡献者
感谢每一位为本次发布做出贡献的开发者!
# v3.0.0-rc.1
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-0-rc-1
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-0-rc-1.mdx
> 新增 7 个组件(Drawer、ToggleButton、ToggleButtonGroup、Meter、ProgressBar、ProgressCircle、Toolbar),Table 与 ListBox 支持虚拟化,ButtonGroup 多项改进,以及若干 bug 修复。
2026 年 3 月 14 日
新增七个组件:[Drawer](/docs/components/drawer)、[ToggleButton](/docs/components/toggle-button)、[ToggleButtonGroup](/docs/components/toggle-button-group)、[Meter](/docs/components/meter)、[ProgressBar](/docs/components/progress-bar)、[ProgressCircle](/docs/components/progress-circle) 与 [Toolbar](/docs/components/toolbar)。Table 与 ListBox 支持虚拟化,ButtonGroup 新增 `Separator` 子组件并支持垂直方向,React Aria Components 升级到 v1.16.0。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@rc @heroui/react@rc
```
```bash
pnpm add @heroui/styles@rc @heroui/react@rc
```
```bash
yarn add @heroui/styles@rc @heroui/react@rc
```
```bash
bun add @heroui/styles@rc @heroui/react@rc
```
**正在使用 AI 助手?** 只需对它说一句「Hey Cursor,把 HeroUI 升级到最新版本」,AI 助手就会自动对比版本并应用必要的变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新增功能
### 新组件
* **[Drawer](#drawer)**:滑出式面板,支持拖拽关闭、4 种放置位置、多种背景遮罩变体以及可滚动的内容区([文档](/docs/components/drawer))
* **[ToggleButton](#toggle-button)**:选中 / 未选中两态的切换按钮,支持全部按钮变体以及仅图标模式([文档](/docs/components/toggle-button))
* **[ToggleButtonGroup](#toggle-button-group)**:单选或多选的切换按钮组,支持 attached / detached 布局以及方向设置([文档](/docs/components/toggle-button-group))
* **[Meter](#meter)**:在已知范围内呈现某个数值——例如磁盘占用、密码强度、配额等([文档](/docs/components/meter))
* **[ProgressBar](#progress-bar)**:线性进度条,支持确定 / 不确定态、多种颜色与自定义格式([文档](/docs/components/progress-bar))
* **[ProgressCircle](#progress-circle)**:基于 SVG 的环形进度条,可自定义轨道圆与填充圆([文档](/docs/components/progress-circle))
* **[Toolbar](#toolbar)**:将按钮、切换控件与分隔线按水平或垂直方向组合在一起的工具栏组件([文档](/docs/components/toolbar))
### Drawer
带有背景遮罩的滑出式浮层面板,支持顶部 / 底部 / 左侧 / 右侧四种放置位置、拖拽关闭手势以及多种背景遮罩变体。复合部件包括:`Trigger`、`Backdrop`、`Content`、`Dialog`、`Header`、`Heading`、`Body`、`Footer`、`Handle`、`CloseTrigger`。
```tsx
import {Button, Drawer} from "@heroui/react";
export function Basic() {
return (
打开抽屉
抽屉标题
这是一个基于 React Aria Modal 组件构建的抽屉。它会从屏幕边缘滑入,并通过流畅的 CSS
过渡呈现动画效果。
取消
确认
);
}
```
**放置位置:**
```tsx
import {Button, Drawer} from "@heroui/react";
const PLACEMENT_LABELS = {
bottom: "底部",
left: "左侧",
right: "右侧",
top: "顶部",
} as const;
export function Placements() {
const placements = ["bottom", "top", "left", "right"] as const;
return (
{placements.map((placement) => (
{PLACEMENT_LABELS[placement]}
{placement === "bottom" && }
{PLACEMENT_LABELS[placement]}抽屉
此抽屉从屏幕{PLACEMENT_LABELS[placement]} 边缘滑入。
取消
完成
{placement === "top" && }
))}
);
}
```
**配合表单使用:**
```tsx
import {Button, Drawer, Input, Label, TextField} from "@heroui/react";
export function WithForm() {
return (
编辑资料
编辑资料
姓名
邮箱
简介
取消
保存更改
);
}
```
### Toggle Button
具备状态的切换按钮,可在选中与未选中之间切换。支持全部按钮变体与尺寸、仅图标模式,以及受控 / 非受控两种使用方式。
```tsx
import {Heart} from "@gravity-ui/icons";
import {ToggleButton} from "@heroui/react";
export function Basic() {
return (
点赞
);
}
```
**变体:**
```tsx
import {Heart} from "@gravity-ui/icons";
import {ToggleButton} from "@heroui/react";
export function Variants() {
return (
默认
幽灵
);
}
```
### Toggle Button Group
单选或多选的切换按钮组。支持 attached(连接式)与 detached(分离式)两种布局、垂直方向、整宽展示,以及一个 `Separator` 子组件。
```tsx
import {Bold, Italic, Strikethrough, Underline} from "@gravity-ui/icons";
import {ToggleButton, ToggleButtonGroup} from "@heroui/react";
export function Basic() {
return (
);
}
```
**选择模式:**
```tsx
import {
Bold,
Italic,
Strikethrough,
TextAlignCenter,
TextAlignLeft,
TextAlignRight,
Underline,
} from "@gravity-ui/icons";
import {ToggleButton, ToggleButtonGroup} from "@heroui/react";
export function SelectionMode() {
return (
);
}
```
**Attached 模式:**
```tsx
import {Bold, Italic, Strikethrough, Underline} from "@gravity-ui/icons";
import {ToggleButton, ToggleButtonGroup} from "@heroui/react";
export function Attached() {
return (
);
}
```
### Meter
在已知范围内呈现某个数值——例如磁盘占用、密码强度、配额等。复合部件包括:`Root`、`Output`、`Track`、`Fill`。
```tsx
import {Label, Meter} from "@heroui/react";
export function Basic() {
return (
存储空间
);
}
```
**颜色:**
```tsx
import {Label, Meter} from "@heroui/react";
const colors = ["default", "accent", "success", "warning", "danger"] as const;
const COLOR_LABELS: Record<(typeof colors)[number], string> = {
accent: "强调",
danger: "危险",
default: "默认",
success: "成功",
warning: "警告",
};
export function Colors() {
return (
{colors.map((color) => (
{COLOR_LABELS[color]}
))}
);
}
```
### Progress Bar
线性进度指示器,支持确定 / 不确定态、颜色变体、多种尺寸以及自定义数值显示。复合部件包括:`Root`、`Output`、`Track`、`Fill`。
```tsx
import {Label, ProgressBar} from "@heroui/react";
export function Basic() {
return (
加载中
);
}
```
**不确定态:**
```tsx
import {Label, ProgressBar} from "@heroui/react";
export function Indeterminate() {
return (
加载中…
);
}
```
### Progress Circle
基于 SVG 的环形进度条,提供 `TrackCircle` 与 `FillCircle` 两个子组件,便于直接控制 SVG。同时支持确定与不确定态。
```tsx
import {ProgressCircle} from "@heroui/react";
export function Basic() {
return (
);
}
```
**自定义 SVG:**
```tsx
import {ProgressCircle} from "@heroui/react";
export function CustomSvg() {
return (
);
}
```
### Toolbar
将按钮、切换按钮与分隔线组合到一个具备无障碍语义的工具栏中。支持水平或垂直方向,可与 `ButtonGroup` 和 `ToggleButtonGroup` 组合使用。
```tsx
import {Bold, Copy, Italic, Scissors, Underline} from "@gravity-ui/icons";
import {
Button,
ButtonGroup,
Separator,
ToggleButton,
ToggleButtonGroup,
Toolbar,
} from "@heroui/react";
export function Basic() {
return (
);
}
```
**配合 Button Group 使用:**
```tsx
import {
ArrowUturnCcwLeft,
ArrowUturnCwRight,
Bold,
Italic,
TextAlignCenter,
TextAlignLeft,
TextAlignRight,
Underline,
} from "@gravity-ui/icons";
import {
Button,
ButtonGroup,
Separator,
ToggleButton,
ToggleButtonGroup,
Toolbar,
} from "@heroui/react";
export function WithButtonGroup() {
return (
撤销
重做
);
}
```
## 组件改进
### ButtonGroup 的增强
新增的 `ButtonGroup.Separator` 子组件可在按钮之间显式插入一条视觉分隔线。在水平和垂直两种方向下都能正常工作。
```tsx
import {
ChevronDown,
ChevronLeft,
ChevronRight,
CodeFork,
Ellipsis,
Picture,
Pin,
QrCode,
Star,
TextAlignCenter,
TextAlignJustify,
TextAlignLeft,
TextAlignRight,
ThumbsDown,
ThumbsUp,
Video,
} from "@gravity-ui/icons";
import {Button, ButtonGroup, Chip, Description, Dropdown, Label} from "@heroui/react";
export function Basic() {
return (
{/* 单个按钮与下拉菜单 */}
合并拉取请求
创建合并提交
此分支上的所有提交都将加入基础分支
压缩并合并
此分支上的 14 个提交将合并为一次提交并加入基础分支
变基并合并
此分支上的 14 个提交将变基后加入基础分支
{/* 独立按钮 */}
复刻
24
扫码支付
2.4K
星标
104
已置顶
{/* 上一页 / 下一页 */}
上一页
下一页
{/* 内容类型选择 */}
{/* 文本对齐 */}
左对齐
居中
右对齐
{/* 仅图标:对齐 */}
);
}
```
### Table 与 ListBox 的虚拟化
Table 与 ListBox 现在可以借助 React Aria 的 `Virtualizer` 来支持大数据集的虚拟化渲染。`Virtualizer`、`TableLayout` 和 `ListLayout` 都已从 `@heroui/react` 重新导出。
```tsx
"use client";
import {Table, TableLayout, Virtualizer} from "@heroui/react";
interface User {
id: number;
name: string;
role: string;
email: string;
}
export function Virtualization() {
const roles = [
"软件工程师",
"高级工程师",
"资深工程师",
"产品经理",
"设计师",
"数据分析师",
"测试工程师",
"DevOps 工程师",
"营销经理",
"销售代表",
];
const firstNames = [
"Emma",
"Liam",
"Olivia",
"Noah",
"Ava",
"James",
"Sophia",
"Oliver",
"Isabella",
"Lucas",
"Mia",
"Ethan",
"Charlotte",
"Mason",
"Amelia",
"Logan",
"Harper",
"Alexander",
"Ella",
"Benjamin",
];
const lastNames = [
"Smith",
"Johnson",
"Williams",
"Brown",
"Jones",
"Garcia",
"Miller",
"Davis",
"Rodriguez",
"Martinez",
"Anderson",
"Taylor",
"Thomas",
"Jackson",
"White",
"Harris",
"Clark",
"Lewis",
"Robinson",
"Walker",
];
function generateUsers(count: number): User[] {
const users: User[] = [];
for (let i = 0; i < count; i++) {
const firstName = firstNames[i % firstNames.length];
const lastName = lastNames[Math.floor(i / firstNames.length) % lastNames.length];
const name = `${firstName} ${lastName}`;
users.push({
email: `${firstName?.toLowerCase()}.${lastName?.toLowerCase()}@acme.com`,
id: i + 1,
name,
role: roles[i % roles.length] || "",
});
}
return users;
}
const virtualizedUsers = generateUsers(1000);
return (
姓名
角色
邮箱
{(user) => (
{user.name}
{user.role}
{user.email}
)}
);
}
```
### ButtonGroup 的方向
`ButtonGroup` 现在接受一个 `orientation` prop(`"horizontal"` | `"vertical"`),并在两种方向下都正确处理边框圆角与分隔线方向。根元素也已从 `` 升级为 React Aria 的 `Group`,从而具备正确的 `role="group"` 语义。
```tsx
import {TextAlignCenter, TextAlignJustify, TextAlignLeft, TextAlignRight} from "@gravity-ui/icons";
import {Button, ButtonGroup} from "@heroui/react";
export function Orientation() {
return (
);
}
```
### ButtonGroup 的焦点环
成组按钮上的焦点环现在使用 `ring-inset`,确保焦点环留在按钮内部边界,而不会与相邻按钮重叠。
### 细粒度的组件引入
`@heroui/react` 现在支持按组件的子路径入口,方便更明确地按需引入([#6301](https://github.com/heroui-inc/heroui/pull/6301)):
```tsx
// Before — root entrypoint
import { Button } from "@heroui/react";
// After — granular subpath import
import { Button } from "@heroui/react/button";
```
## 依赖更新
将 `react-aria-components` 从 v1.15.1 升级到 v1.16.0,同时升级了相关包:
| 包名 | 旧版本 | 新版本 |
| ------------------------- | ------- | ------- |
| `react-aria-components` | 1.15.1 | 1.16.0 |
| `@react-aria/i18n` | 3.12.15 | 3.12.16 |
| `@react-aria/utils` | 3.33.0 | 3.33.1 |
| `@react-types/shared` | 3.33.0 | 3.33.1 |
| `@react-types/color` | 3.1.3 | 3.1.4 |
| `@internationalized/date` | 3.11.0 | 3.12.0 |
| `@react-stately/data` | 3.15.1 | 3.15.2 |
## Bug 修复
* **InputGroup**:聚焦样式现在仅在实际的 input / textarea 获得焦点时(`:has([data-slot]:focus)`)才会触发,不再因 `:focus-within` 而被任意可聚焦的子元素触发([#6274](https://github.com/heroui-inc/heroui/pull/6274))
* **Avatar**:fallback 元素现在会从父级继承 `border-radius`,而不再硬编码为 `rounded-full`,因此 `className` 覆盖能够正确生效([#6300](https://github.com/heroui-inc/heroui/pull/6300))
* **Modal 与 AlertDialog**:背景遮罩的点击事件不会再透过 portal 传播到父级元素([#6297](https://github.com/heroui-inc/heroui/pull/6297))
* **Table**:修复了 Firefox 中表头圆角与背景色溢出的问题([#6298](https://github.com/heroui-inc/heroui/pull/6298))
## 链接
* [组件文档](/docs/react/components)
* [Figma Kit v3](https://www.figma.com/community/file/1546526812159103429/heroui-figma-kit-v3)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #6285](https://github.com/heroui-inc/heroui/pull/6285)
## 贡献者
感谢每一位为本次发布做出贡献的开发者!
# HeroUI v3 正式发布
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-0
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-0.mdx
> 面向 React 与 React Native 的彻底重写。75+ Web 组件、37 个原生组件、Tailwind CSS v4、React Aria、复合组件架构,以及为 AI 辅助开发而打造的工具链。
2026 年 3 月
每个组件都已重写。所有动画都已迁移到 CSS。样式与实现完全解耦。全新打造的 React Native 库。以及一套把 AI 助手视为「主要开发界面」的工具链。
## 概览
### React(Web)
75+ 组件。无障碍能力由 [React Aria Components](https://react-aria.adobe.com/) 提供。基于 Tailwind CSS v4 + CSS 变量进行主题化。样式被独立成单独的包,可以与任意框架配合使用。
[查看详情](#compound-components)
### React Native
37 个组件,共享同一套设计 token、采用复合组件模式、统一的动画 API,以及自适应的呈现模式。每个平台都基于原生实现,并通过 [Uniwind](https://uniwind.dev/) 提供 Tailwind CSS v4 的支持。
[查看详情](#heroui-native)
### HeroUI Pro
面向 React 与 React Native 的高级组件、模板与 AI 工具。包含 Command Palette、Kanban、DataGrid、Dashboard 模板等。预售价格已上线 [heroui.pro](https://heroui.pro)。
[查看详情](#heroui-pro)
## 设计原则
**组合优于配置:** v2 的组件是黑盒。v3 采用复合组件模式:每一个内部部件都是真实的元素,你可以为它们设置样式、调整位置、替换或移除。
**样式与实现分离:** `@heroui/styles` 是独立的 CSS 包,`@heroui/react` 负责行为逻辑。这套样式可以配合 React、原生 HTML + Tailwind 或任意框架使用。BEM 类名让每一个 slot 都能在全局层面被定制。切换主题不仅会改变变量,还能改变组件的外观与质感。
**按需变身 Headless:** 只要不引入 `@heroui/styles`,你就拥有了一套 headless 组件库。我们负责功能与无障碍,你专注于自己的产品。
**默认就有好性能:** v2 的所有动画都依赖 Framer Motion。v3 已将其替换为原生的 CSS transition 与 keyframes。打包体积更小、可使用 GPU 加速,且无需任何 JS 动画运行时。
**从一开始就无障碍:** 已从 React Aria hooks 迁移到 [React Aria Components](https://react-aria.adobe.com/)。键盘导航、焦点管理、屏幕阅读器与 ARIA 属性均已内置。
## 复合组件
下面是复合组件模式在实际使用中的样子:
```tsx
Product
Details about this product.
Card content goes here.
Buy now
```
代码确实多了几行。但每个部件都是真实的元素,你可以自由设置样式、调整位置或替换。这一模式贯穿整个组件库,从 Accordion 到 Toast 都是如此。
```tsx
import {
ArrowsRotateLeft,
Box,
ChevronDown,
CreditCard,
PlanetEarth,
Receipt,
ShoppingBag,
} from "@gravity-ui/icons";
import {Accordion} from "@heroui/react";
const items = [
{
content: "浏览我们的商品,将商品加入购物车并前往结账。完成购买需要提供收货与支付信息。",
icon: ,
title: "如何下单?",
},
{
content: "可以,在订单发货前你可以修改或取消。订单一旦进入处理流程,将无法再更改。",
icon: ,
title: "可以修改或取消订单吗?",
},
{
content: "我们接受主流信用卡,包括 Visa、Mastercard 和 American Express。",
icon: ,
title: "支持哪些支付方式?",
},
{
content: "运费因收货地址与订单体积而异。订单满 50 美元可享受免运费。",
icon: ,
title: "运费如何计算?",
},
{
content: "是的,我们可向多数国家/地区发货。请查看运费说明与政策了解更多信息。",
icon: ,
title: "是否提供国际配送?",
},
{
content: "若对购买不满意,可在购买后 30 天内申请退款。请联系客服团队协助处理。",
icon: ,
title: "如何申请退款?",
},
];
export function Basic() {
return (
{items.map((item, index) => (
{item.icon ? (
{item.icon}
) : null}
{item.title}
{item.content}
))}
);
}
```
每个复合组件都通过 React context 共享状态。根组件会创建样式 context,子组件依次消费。你无需手动逐层传递 className:
```tsx
Profile updated
Your changes have been saved.
```
```tsx
import {Alert, Button, CloseButton, Spinner} from "@heroui/react";
import React from "react";
export function Basic() {
return (
{/* 默认 — 一般信息 */}
新功能已上线
查看我们的最新更新,包括深色模式支持与改进的无障碍体验。
{/* 强调 — 重要信息含操作 */}
有可用更新
应用有新版本可用。请刷新页面以获取最新功能与问题修复。
刷新
刷新
{/* 危险 — 错误与排查步骤 */}
无法连接到服务器
当前遇到连接问题,请尝试以下操作:
重试
重试
{/* 无描述 */}
个人资料已更新
{/* 自定义指示器 — 加载中 */}
正在处理你的请求
正在同步你的数据,请稍候,这可能需要一点时间。
{/* 无关闭按钮 */}
计划维护
我们将于 UTC 时间 3 月 15 日(周日)凌晨 2:00 至上午 6:00
进行计划维护,期间服务将暂时不可用。
);
}
```
### 渐进式呈现
组件同时支持简单写法和复合写法。先从一行代码起步,需要时再补充结构:
```tsx
// One line
Submit
// With icon
Submit
// Full control
{isLoading ? : }
{isLoading ? "Saving..." : "Submit"}
```
```tsx
import {Button} from "@heroui/react";
export function Variants() {
return (
主要
次要
第三
线框
幽灵
危险
柔和危险
);
}
```
## Tailwind CSS v4 + CSS 变量
主题系统基于 Tailwind CSS v4 原生的 CSS 变量层与 OKLCH 颜色实现。每一个设计 token 都是一个 CSS 变量:
```css
:root {
--background: oklch(0.9702 0 0);
--foreground: oklch(0.2103 0.0059 285.89);
--accent: oklch(0.6204 0.195 253.83);
--surface: oklch(100% 0 0);
--danger: oklch(0.6532 0.2328 25.74);
--radius: 0.5rem;
}
```
Tailwind 的 `@theme` 指令会将这些 token 映射为工具类。`bg-accent`、`text-foreground`、`rounded-lg` 都会解析为对应的 CSS 变量。切换浅色 / 深色模式只需替换变量值:
```css
.dark, [data-theme="dark"] {
--background: oklch(12% 0.005 285.823);
--foreground: oklch(0.9911 0 0);
--surface: oklch(0.2103 0.0059 285.89);
}
```
不需要 Provider 组件,也不需要 JavaScript 主题对象。一次 CSS 引入,两行代码:
```css
@import "tailwindcss";
@import "@heroui/styles";
```
### BEM 类名
通过标准 CSS 即可在全局覆写任意组件:
```css
@layer components {
.button {
@apply font-semibold tracking-wide;
}
.button--primary {
@apply bg-blue-600 hover:bg-blue-700;
}
}
```
无需层层传递 className,也无需在 style prop 上反复折腾。设计系统的覆写就发生在 CSS 中——它本就属于这里。
### 自定义主题
通过定义你自己的 token 集合即可创建主题,其他一切都会随之级联:
```css
@layer base {
[data-theme="ocean"] {
--accent: oklch(0.450 0.150 230);
--background: oklch(0.985 0.015 225);
--radius: 0.75rem;
--border: oklch(0.50 0.060 230 / 22%);
}
}
```
只需一个 data 属性即可应用:
```html
```
[主题构建器](/themes) 可以可视化地生成这些变量:选择颜色、调整圆角与间距,再导出 CSS。
### 按需引入
可以一次性引入完整样式库,也可以只挑选特定组件的样式:
```css
@import "tailwindcss";
@import "@heroui/styles/base" layer(base);
@import "@heroui/styles/themes/default" layer(theme);
@import "@heroui/styles/components/button.css" layer(components);
@import "@heroui/styles/components/card.css" layer(components);
```
只发布你实际用到的 CSS,避免在生产环境中携带未使用的组件样式。
## 尊重用户的动画
所有组件动画都通过 CSS transition 与 keyframes 实现,并绑定到对应的 data 属性。Popover 通过 `[data-entering]` 淡入,Button 在 `[data-pressed]` 时缩放,Accordion 通过 `[aria-hidden="false"]` 展开。
```css
.popover[data-entering] {
@apply animate-in zoom-in-90 fade-in-0 duration-200;
}
.button:active,
.button[data-pressed="true"] {
transform: scale(0.97);
}
```
### Reduce Motion
部分用户需要禁用动画。HeroUI 扩展了 Tailwind 的 `motion-reduce:` 变体,使其同时支持系统级偏好和自定义 data 属性:
```css
.button {
@apply transition-colors motion-reduce:transition-none;
}
```
它会响应原生的 `prefers-reduced-motion: reduce` 媒体查询,同时也会响应 HTML 元素上的 `data-reduce-motion="true"`,从而支持应用级别的控制:
```html
```
data 属性的优先级高于系统设置。将其设为 `data-reduce-motion="false"` 可强制开启动画,移除该属性则交由操作系统决定。所有带动画的组件都会遵循这一规则,无需额外开启。
### 自带动画库也无妨
Framer Motion、Motion One 或任何 CSS 动画库都可以与 HeroUI 内置的过渡共存:
```tsx
import { motion } from "framer-motion";
import { Button } from "@heroui/react";
const MotionButton = motion(Button);
Animated
```
## 75+ React 组件
### 日期与时间
六个组件:Calendar、RangeCalendar、DateField、DatePicker、DateRangePicker 与 TimeField。基于 React Aria 的国际化日期库构建,默认支持公历、佛历、波斯历等多种历法。键盘导航、屏幕阅读器标签以及按区域格式化全部开箱即用。
```tsx
"use client";
import {Calendar, DateField, DatePicker, Label} from "@heroui/react";
export function Basic() {
return (
日期
{(segment) => }
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
```tsx
"use client";
import {RangeCalendar} from "@heroui/react";
export function Basic() {
return (
{(day) => {day} }
{(date) => }
);
}
```
### 颜色
六个颜色组件:ColorPicker、ColorArea、ColorSlider、ColorField、ColorSwatch 与 ColorSwatchPicker。可以在二维色域中取色、调整色相与透明度滑块、输入 hex 值,或从色板中直接选择。
```tsx
import {ColorArea, ColorPicker, ColorSlider, ColorSwatch, Label} from "@heroui/react";
export function Basic() {
return (
选择颜色
色相
);
}
```
### 数据
需要一个支持排序、行选择、列宽调整、异步加载与自定义单元格的表格?Table 全部都能搞定。面对大数据集时,可借助 React Aria 的 `Virtualizer` 启用虚拟化,ListBox 也共享同样的虚拟化能力。
```tsx
"use client";
import {Table, TableLayout, Virtualizer} from "@heroui/react";
interface User {
id: number;
name: string;
role: string;
email: string;
}
export function Virtualization() {
const roles = [
"软件工程师",
"高级工程师",
"资深工程师",
"产品经理",
"设计师",
"数据分析师",
"测试工程师",
"DevOps 工程师",
"营销经理",
"销售代表",
];
const firstNames = [
"Emma",
"Liam",
"Olivia",
"Noah",
"Ava",
"James",
"Sophia",
"Oliver",
"Isabella",
"Lucas",
"Mia",
"Ethan",
"Charlotte",
"Mason",
"Amelia",
"Logan",
"Harper",
"Alexander",
"Ella",
"Benjamin",
];
const lastNames = [
"Smith",
"Johnson",
"Williams",
"Brown",
"Jones",
"Garcia",
"Miller",
"Davis",
"Rodriguez",
"Martinez",
"Anderson",
"Taylor",
"Thomas",
"Jackson",
"White",
"Harris",
"Clark",
"Lewis",
"Robinson",
"Walker",
];
function generateUsers(count: number): User[] {
const users: User[] = [];
for (let i = 0; i < count; i++) {
const firstName = firstNames[i % firstNames.length];
const lastName = lastNames[Math.floor(i / firstNames.length) % lastNames.length];
const name = `${firstName} ${lastName}`;
users.push({
email: `${firstName?.toLowerCase()}.${lastName?.toLowerCase()}@acme.com`,
id: i + 1,
name,
role: roles[i % roles.length] || "",
});
}
return users;
}
const virtualizedUsers = generateUsers(1000);
return (
姓名
角色
邮箱
{(user) => (
{user.name}
{user.role}
{user.email}
)}
);
}
```
### 表单
十三个表单组件:TextField、Select、Autocomplete、ComboBox、Checkbox、CheckboxGroup、RadioGroup、Switch、InputOTP、NumberField、SearchField、Slider 与 Fieldset。全部集成了 React Aria 的表单校验:`isRequired`、`isInvalid` 以及通过 FieldError 自定义错误信息——所有组件均可使用。
```tsx
import {Label, ListBox, Select} from "@heroui/react";
export function Default() {
return (
州
佛罗里达
特拉华
加利福尼亚
德克萨斯
纽约
华盛顿
);
}
```
```tsx
import {InputOTP, Label, Link} from "@heroui/react";
export function Basic() {
return (
验证账户
我们已向 a****@gmail.com 发送验证码
);
}
```
### 浮层
七个浮层组件。Drawer 支持四种放置位置以及拖拽关闭手势。Toast 可堆叠通知,并支持自动关闭与 Promise。Menu 支持子菜单与分组组合。此外还有 Modal、AlertDialog、Popover 与 Tooltip。
```tsx
import {Button, Drawer} from "@heroui/react";
export function Basic() {
return (
打开抽屉
抽屉标题
这是一个基于 React Aria Modal 组件构建的抽屉。它会从屏幕边缘滑入,并通过流畅的 CSS
过渡呈现动画效果。
取消
确认
);
}
```
```tsx
"use client";
import {Persons} from "@gravity-ui/icons";
import {Button, toast} from "@heroui/react";
export function Default() {
return (
{
const id = toast("您已被邀请加入团队", {
actionProps: {
children: "忽略",
onPress: () => toast.close(id),
variant: "tertiary",
},
description: "Bob 邀请您加入 HeroUI 团队",
indicator: ,
variant: "default",
});
}}
>
显示 Toast
);
}
```
### 导航
Tabs、Accordion、Breadcrumbs、Pagination 与 Link。Tabs 支持水平与垂直两种排列方向。Accordion 支持单一或多个面板同时展开。
```tsx
import {Tabs} from "@heroui/react";
export function Basic() {
return (
概览
分析
报告
查看项目概览与近期活动。
跟踪指标并分析性能数据。
生成并下载详细报告。
);
}
```
### 反馈
ProgressBar 与 ProgressCircle 同时支持确定态与不确定态。Meter 会根据数值映射到语义颜色:绿色代表安全,黄色代表警告,红色代表严重。Skeleton 与 Spinner 共同补齐这一组件家族。
```tsx
import {Label, Meter} from "@heroui/react";
const colors = ["default", "accent", "success", "warning", "danger"] as const;
const COLOR_LABELS: Record<(typeof colors)[number], string> = {
accent: "强调",
danger: "危险",
default: "默认",
success: "成功",
warning: "警告",
};
export function Colors() {
return (
{colors.map((color) => (
{COLOR_LABELS[color]}
))}
);
}
```
```tsx
import {Skeleton} from "@heroui/react";
export function Basic() {
return (
);
}
```
### 按钮与切换
Button、ButtonGroup、ToggleButton、ToggleButtonGroup、CloseButton 与 Toolbar。ButtonGroup 通过共享边框将多个按钮连接在一起,并支持垂直方向。Toolbar 会将按钮、切换控件与分隔线组合到一个具备无障碍语义的 `role="toolbar"` 容器中。
```tsx
import {Bold, Italic, Strikethrough, Underline} from "@gravity-ui/icons";
import {ToggleButton, ToggleButtonGroup} from "@heroui/react";
export function Attached() {
return (
);
}
```
### 细粒度引入
你可以从根路径引入,也可以从每个组件的子路径引入,两种方式都可用:
```tsx
// Root import
import { Button, Card, Table } from "@heroui/react";
// Subpath import
import { Button } from "@heroui/react/button";
import { Card } from "@heroui/react/card";
import { Table } from "@heroui/react/table";
```
## 面向 Agent 的 UI
如今越来越多的开发者通过 prompt 来构建产品,而不是逐字阅读 API 文档。HeroUI v3 为此做好了准备。
### MCP 服务器
HeroUI MCP 服务器将 AI 编码助手(Cursor、Claude Code、VS Code Copilot、Windsurf、Zed)连接到组件文档、props、源码、CSS 样式与主题变量。AI 可以直接读取权威信息源,而不必再依赖训练数据进行猜测。
```json
{
"mcpServers": {
"heroui-react": {
"command": "npx",
"args": ["-y", "@heroui/react-mcp@latest"]
}
}
}
```
对你的 AI 助手说一句「把 HeroUI 升级到最新版本」,它就会自动对比版本、检查更新日志中的破坏性变更,并完成必要的代码更新。
### Agent Skills
面向 Cursor 与 Claude Code 提供可安装的知识包,覆盖组件模式、变体用法、主题说明以及升级指南。提前注入上下文,让 AI 第一次就能写出正确的 HeroUI 代码。
### LLMs.txt
针对 AI 上下文窗口优化的结构化文档文件。这些文件发布在 `/llms.txt` 与 `/llms-components.txt`,为任何基于 LLM 的工具提供一份机器可读的 HeroUI API 摘要。
MCP 服务器、Agent Skills、LLMs.txt——三层组合让 AI 助手能像人类开发者从文档中获取信息一样,获得对 HeroUI 的完整访问能力。
## HeroUI Native
HeroUI Native 是与 v3 网页版同时推出的全新组件库。渲染引擎不同,但心智模型一致。在平台差异较大的地方,API 也会贴合各自平台的原生体验。
### 在你的设备上试试
用设备摄像头或 [Expo Go](https://expo.dev/go) 扫描下方二维码,即可在线体验全部 37 个组件:
**[📱 在 Expo Go 中打开演示应用](https://link.heroui.com/native-demo)**
**Android 用户:** 如果扫码后跳转到浏览器并显示 404 错误,请先打开 Expo Go,再使用应用内置的扫码功能。
### 37 个组件
涵盖表单、导航、浮层、反馈与布局。从 Button、Input、Checkbox,到 Dialog、BottomSheet、Select、Toast 与 InputOTP,所有组件都遵循复合组件模式:
```tsx
import { Dialog, Button } from "heroui-native";
Open
Confirm action
This cannot be undone.
```
### 跨平台一致的体验
只要你熟悉 Web 版的 HeroUI,大部分知识都能直接迁移过来。组件命名、点表示法与 prop 模式都尽可能保持一致。在平台差异较大的地方(布局基元、手势、导航等),API 会做出相应调整以贴近原生,但整体的心智模型保持一致:
```tsx
// React (web)
Profile updated
Your changes have been saved.
// React Native — similar API, native behavior
Profile updated
Your changes have been saved.
```
同时开发 Web 与移动端的团队可以共享同一套知识与模式。即便组件本身有所不同,跨平台的学习成本也极低。
### 共享设计 token
两个平台读取的是同一份 token 集合。`accent`、`surface`、`danger`、`success` 等颜色在 Web 与 Native 上解析结果完全一致。你不必维护两套独立的系统,品牌也能保持一致。
```tsx
import { View, Text } from "react-native";
Card Title
Consistent on web and mobile.
```
两个平台都使用 Tailwind CSS v4:Native 端通过 [Uniwind](https://uniwind.dev/),Web 端使用标准 Tailwind。
### 统一的动画 API
每一个带动画的原生组件都只暴露一个 `animation` prop。数值、时长、弹簧参数、进出场过渡都集中在这里配置。底层由 Reanimated 负责计算,但你完全不需要直接接触它:
```tsx
import { Switch } from "heroui-native";
```
可以在任意层级关闭动画——单个组件、整棵子树,或者全局:
```tsx
// Single component
// Entire subtree
...
// App-wide
```
Reduce Motion 全自动生效。当用户在系统设置中启用它时,所有动画都会停止,无需任何额外代码。
### 自适应的呈现模式
Popover、Select 与 Menu 通过一个 prop 即可在 popover、bottom-sheet 与 dialog 之间切换。同一个组件,根据上下文以不同形式呈现:
```tsx
...
...
...
```
目前还没有其他 React Native 组件库提供这一能力。
### 细粒度引入
每一个原生组件都有自己的入口路径,只引入你实际用到的部分即可:
```tsx
import { HeroUINativeProvider } from "heroui-native/provider";
import { Button } from "heroui-native/button";
import { Card } from "heroui-native/card";
```
### Native 端的 AI 工具
HeroUI Native 也配套提供了自己的 MCP 服务器、Agent Skills 与 LLMs.txt,与 Web 组件库的工具链结构完全一致:
```json
{
"mcpServers": {
"heroui-native": {
"command": "npx",
"args": ["-y", "@heroui/native-mcp@latest"]
}
}
}
```
## HeroUI Pro
与 v3 同步,[HeroUI Pro](https://heroui.pro) 的预售也已经上线。面向 React 与 React Native,提供高级组件、模板与 AI 工具。
### Pro 组件
超越核心组件库的更多组件:Command Palette、Kanban、Stats Dashboard、Filters、Agenda、DataGrid 等。无障碍、动画以及各平台的边界情况都已处理妥当,未来将同时支持 Web 与 Native。
### 模板
完整可用的响应式起步模板:Dashboard、Mail、Chat 与 Finances。布局真实、结构完整,让你从一个能直接运行的项目出发,再按需定制。
### 高级 AI 工具
Pro 许可包含高级版的 MCP 服务器与 Agent Skills,并内置 Pro 组件文档、使用模式与升级路径。
预售价格已上线。v2 Pro 用户可享受升级折扣,使用同一邮箱或联系客服即可。
[访问 heroui.pro 查看套餐与定价](https://heroui.pro)
## 快速上手
### React(Web)
```bash
npm i @heroui/styles @heroui/react
```
```bash
pnpm add @heroui/styles @heroui/react
```
```bash
yarn add @heroui/styles @heroui/react
```
```bash
bun add @heroui/styles @heroui/react
```
在你的 CSS 中加入这两行:
```css
@import "tailwindcss";
@import "@heroui/styles";
```
### React Native
```bash
npm install heroui-native
```
```bash
pnpm add heroui-native
```
```bash
yarn add heroui-native
```
```bash
bun add heroui-native
```
完整的安装指南请参阅 [React 文档](/docs/react/getting-started/quick-start) 与 [React Native 文档](/docs/native/getting-started/quick-start)(涵盖 peer dependencies、Uniwind 配置以及 Provider 设置)。
**正在从 HeroUI v2 升级?** 请按照 [迁移指南](/docs/react/migration) 一步步完成升级。
## Figma Kit v3
HeroUI v3 中的每一个组件在 Figma 中都有 1:1 的对应实现。变体、命名与结构完全一致。整套 Kit 全程采用 auto layout,使用与代码 token 直接对应的 Figma 变量(`--accent`、`--surface`、`--radius`),并借助 Figma 新推出的 [slots](https://help.figma.com/hc/en-us/articles/38231200344599-Use-slots-to-build-flexible-components-in-Figma) 来实现灵活的组件组合。设计师可以像开发者写代码一样,自由调整、替换与定制组件的各个部件。
[获取 Figma Kit](https://www.figma.com/community/file/1546526812159103429/heroui-figma-kit-v3)
## 致谢
[React Aria](https://react-aria.adobe.com/) 提供了我们自己难以做到这种水准的无障碍能力层。Tailwind CSS v4 原生的 CSS 变量方案塑造了我们整个主题系统。复合组件模式则是通过研究 [Radix](https://www.radix-ui.com/)、[Ark UI](https://ark-ui.com/) 与 [Base UI](https://base-ui.com/) 在组合性问题上的解法逐步打磨而来。
感谢每一位在 alpha 与 RC 阶段提交 issue、测试预发布版本以及反馈意见的社区成员。这套组件库因为你们而变得更好。
## 链接
* [React 文档](/docs/react/getting-started/quick-start)
* [React Native 文档](/docs/native/getting-started/quick-start)
* [主题构建器](/themes)
* [MCP 服务器](/docs/ui-for-agents/mcp-server)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [Figma Kit v3](https://www.figma.com/community/file/1546526812159103429/heroui-figma-kit-v3)
# v3.0.2
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-2
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-2.mdx
> 修复了多个 bug,Drawer 过渡更平滑,新增 --backdrop 主题变量,并优化了 trigger、arrow 与 Tag 的样式。
2026 年 4 月 3 日
补丁版本,包含若干 bug 修复、样式优化,以及新增的 `--backdrop` 主题变量。Drawer 过渡已重写为原生 CSS,动画更加平滑。浮层触发器现在以 `inline-block` 形式呈现,Tooltip 和 Popover 的默认箭头形状也已更新。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@latest @heroui/react@latest
```
```bash
pnpm add @heroui/styles@latest @heroui/react@latest
```
```bash
yarn add @heroui/styles@latest @heroui/react@latest
```
```bash
bun add @heroui/styles@latest @heroui/react@latest
```
**正在使用 AI 助手?** 只需对它说一句「Hey Cursor,把 HeroUI 升级到最新版本」,AI 助手就会自动对比版本并应用必要的变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新增功能
### `--backdrop` 主题变量
新增用于浮层背景遮罩的 `--backdrop` CSS 变量([#6375](https://github.com/heroui-inc/heroui/pull/6375))。浅色主题默认值为 `rgba(0, 0, 0, 0.5)`,深色主题为 `rgba(0, 0, 0, 0.6)`。[Modal](/docs/components/modal)、[AlertDialog](/docs/components/alert-dialog) 与 [Drawer](/docs/components/drawer) 现在都引用该变量,而不再使用硬编码的值。
可以在全局进行覆写:
```css
:root {
--backdrop: rgba(0, 0, 0, 0.7);
}
```
也可以直接使用对应的工具类 `bg-backdrop`。
## 样式改进
### Trigger 改用 `inline-block` 显示
Popover、Tooltip、Dropdown、Modal、AlertDialog、Drawer 与 Disclosure 中的触发元素现在都会应用 `inline-block`,避免触发器包裹行内内容时出现布局塌陷的问题([#6373](https://github.com/heroui-inc/heroui/pull/6373))。
### Tooltip 与 Popover 的箭头
默认箭头的 SVG 路径已从二次贝塞尔曲线改为三次贝塞尔曲线,形状更平滑、更自然([#6372](https://github.com/heroui-inc/heroui/pull/6372))。
### Tag 的间距
为提升可读性,Tag 在 `sm`(由 `px-1` 改为 `px-2`)和 `md`(由 `px-1.5` 改为 `px-2`)尺寸下增加了水平内边距([#6315](https://github.com/heroui-inc/heroui/pull/6315))。
## Bug 修复
* **Autocomplete**:popover 上的 `--trigger-width` CSS 变量现在通过 `useResizeObserver` 跟踪触发元素的宽度,修复了下拉宽度不对齐的问题([#6374](https://github.com/heroui-inc/heroui/pull/6374))
* **Drawer**:面板过渡已从 Tailwind 的 `animate-in` / `animate-out` 重写为原生的 CSS `translate` 过渡,使各种放置位置下的开关动画都更加平滑([#6393](https://github.com/heroui-inc/heroui/pull/6393))
* **InputGroup**:secondary 变体的聚焦背景现在仅在实际的 input 或 textarea 获得焦点时才会触发,不再因组内任意可聚焦的子元素被聚焦而触发([#6362](https://github.com/heroui-inc/heroui/pull/6362))
* **Tag**:Tag 内部的 `CloseButton` 现在带有显式的 `aria-label="Remove tag"`,可被屏幕阅读器正确识别([#6341](https://github.com/heroui-inc/heroui/pull/6341))
## 链接
* [组件文档](/docs/react/components)
* [Figma Kit v3](https://www.figma.com/community/file/1546526812159103429/heroui-figma-kit-v3)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #6364](https://github.com/heroui-inc/heroui/pull/6364)
## 贡献者
感谢每一位为本次发布做出贡献的开发者!
# v3.0.3
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-3
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-3.mdx
> 升级到 RAC 1.17(依赖减少 90%)、Table 支持可展开行、采用 Apache 2.0 协议、新增 useTheme Hook、DOM 多态 render-prop API,以及若干 bug 修复。
2026 年 4 月 17 日
补丁版本:升级到 React Aria Components 1.17(依赖数量减少 90%)、Table 支持可展开行、采用 Apache 2.0 协议,为 Vite 与 CRA 应用提供 `useTheme` Hook、新增可在 render prop 中替换元素的 DOM 多态工具函数,以及若干 bug 修复。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@latest @heroui/react@latest
```
```bash
pnpm add @heroui/styles@latest @heroui/react@latest
```
```bash
yarn add @heroui/styles@latest @heroui/react@latest
```
```bash
bun add @heroui/styles@latest @heroui/react@latest
```
**正在使用 AI 助手?** 只需对它说一句「Hey Cursor,把 HeroUI 升级到最新版本」,AI 助手就会自动对比版本并应用必要的变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新增功能
### React Aria Components 1.17
本次发布将 React Aria Components 升级到 [v1.17.0](https://react-aria.adobe.com/releases/v1-17-0)。最大亮点是依赖整合:**RAC 的传递依赖减少了 90%**,安装与构建都更快。详情请查看完整的 [RAC 1.17 发布说明](https://react-aria.adobe.com/releases/v1-17-0)。
### Table 可展开行
Table 现在支持以可展开行的形式呈现树形数据。设置 `treeColumn` 并在对应单元格中渲染一个 chevron 图标即可展开 / 折叠子行——非常适合用于文件浏览器、嵌套分类以及层级数据。
```tsx
"use client";
import type {Selection} from "@heroui/react";
import {Button, Table, cn} from "@heroui/react";
import {Icon} from "@iconify/react";
import {useState} from "react";
export function ExpandableRows() {
type Row = {
children: Row[];
date: string;
id: string;
title: string;
type: string;
};
const data: Row[] = [
{
children: [
{
children: [
{children: [], date: "7/10/2025", id: "3", title: "周报", type: "文件"},
{children: [], date: "8/20/2025", id: "4", title: "预算", type: "文件"},
],
date: "8/2/2025",
id: "2",
title: "项目",
type: "文件夹",
},
],
date: "10/20/2025",
id: "1",
title: "文档",
type: "文件夹",
},
{
children: [
{children: [], date: "1/23/2026", id: "6", title: "图片 1", type: "文件"},
{children: [], date: "2/3/2026", id: "7", title: "图片 2", type: "文件"},
],
date: "2/3/2026",
id: "5",
title: "照片",
type: "文件夹",
},
];
const [expandedKeys, setExpandedKeys] = useState(() => new Set(["1"]));
const renderExpandableRow = (item: Row) => {
return (
{({hasChildItems, isDisabled, isExpanded, isTreeColumn}) => (
{hasChildItems && isTreeColumn ? (
) : null}
{item.title}
)}
{item.type}
{item.date}
{renderExpandableRow}
);
};
return (
姓名
类型
修改日期
{renderExpandableRow}
);
}
```
### useTheme Hook
对于使用 Vite 或 Create React App 搭建(没有 Next.js 主题 Provider)的纯 React 应用,可以从 `@heroui/react` 中引入 `useTheme`。它接受任意主题名(`"light"`、`"dark"`、`"brutalism-light"` 等),传入 `"system"` 则会跟随操作系统偏好。`useTheme` 会将主题值持久化到 `localStorage`,并在 `` 元素上同步设置 `data-theme` 与 `class`,二者均为解析后的主题名。
```tsx
"use client";
import { Button, useTheme } from "@heroui/react";
export function ThemeSwitch() {
const { theme, setTheme } = useTheme("light");
return (
setTheme("light")}>
Light
setTheme("dark")}>
Dark
setTheme("system")}>
System
setTheme("brutalism-light")}>
Brutalism Light
Current: {theme}
);
}
```
### DOM 多态工具
DOM 多态辅助工具让那些没有基于 React Aria 基元构建的轻量级组件,也能通过 render prop 切换其宿主元素。
**示例:** 将 Card 组件渲染为 ` `
```tsx
render={(props) => } />
```
### 协议变更
HeroUI 现已采用 [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) 协议,取代此前的 MIT 协议。Apache 2.0 同样提供宽松的使用自由,并在此基础上增加了显式的专利授权,提供更进一步的法律保护。现有用户无需进行任何操作。
## Bug 修复
* **Tabs**:限定 secondary 变体样式的作用范围,嵌套的 tab 组将不再继承父级变体([#6384](https://github.com/heroui-inc/heroui/pull/6384))
## 依赖更新
* **React Aria Components**:从 `1.16.0` 升级到 [`1.17.0`](https://react-aria.adobe.com/releases/v1-17-0)
* **@react-aria/utils**:从 `3.33.1` 升级到 `3.34.0`
* **@react-types/shared**:从 `3.33.1` 升级到 `3.34.0`
* **@internationalized/date**:从 `3.12.0` 升级到 `3.12.1`
## 链接
* [组件文档](/docs/react/components)
* [Figma Kit v3](https://www.figma.com/community/file/1546526812159103429/heroui-figma-kit-v3)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #6441](https://github.com/heroui-inc/heroui/pull/6441)
## 贡献者
感谢每一位为本次发布做出贡献的开发者!
# v3.0.4
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-4
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-4.mdx
> 全新 Text 组件、文档主题选择器、采用 min() 上限约束的圆角设计令牌、Table 聚焦环重构,以及多项 bug 修复。
2026 年 5 月
补丁版本:从 HeroUI Pro 移植的全新 `Text` 复合组件;文档站新增主题选择器,可在不同主题下预览各组件;在约 45 个组件 CSS 文件中将圆角设计令牌改为使用 `min()` 上限约束;重做 Table 的聚焦环;并修复 Checkbox、Autocomplete、Tooltip 与表单字段内边距等问题。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@latest @heroui/react@latest
```
```bash
pnpm add @heroui/styles@latest @heroui/react@latest
```
```bash
yarn add @heroui/styles@latest @heroui/react@latest
```
```bash
bun add @heroui/styles@latest @heroui/react@latest
```
**正在使用 AI 助手?** 只需对它说一句「Hey Cursor,把 HeroUI 升级到最新版本」,AI 助手就会自动对比版本并应用必要的变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新增功能
### Text 组件
用于结构化排版的新复合组件,从 HeroUI Pro 移植 ([#6479](https://github.com/heroui-inc/heroui/pull/6479))。会根据子组件或 `type` prop 自动渲染正确的 HTML 元素——`` 至 ``、` ` 或 ``。
子组件:`Text.Heading`、`Text.Paragraph`、`Text.Code`、`Text.Prose`。
各子组件支持的 prop:`align`、`color`、`weight`、`truncate`。`Text.Heading` 支持 `level`(1–6)。`Text.Paragraph` 支持 `size`(`"base"`、`"sm"`、`"xs"`)。
使用 `Text.Prose` 包裹混合内容以获得自动的文章体间距:
```tsx
快速开始
安装依赖包并引入组件。
```
### 文档主题选择器
文档站现内置主题选择器,可在浅色、深色、粗野主义等多种主题下预览每个组件。你的选择会保存到 `localStorage`,在会话之间保持 ([#6471](https://github.com/heroui-inc/heroui/pull/6471))。
### 圆角设计令牌
约 45 个组件 CSS 文件中的 `rounded-full` 与硬编码 `border-radius` 现均通过 `min()` 限制计算后的半径 ([#6465](https://github.com/heroui-inc/heroui/pull/6465))。当用户设置过大的自定义圆角主题时,组件外观不再失真——半径在即将超过元素尺寸时停止增大。
### Table 聚焦环重构
表格行的聚焦指示改为在每个单元格上使用内阴影分别绘制,而非在整行使用单一 `box-shadow`。聚焦环在所有单元格之间视觉上保持连续,并在虚拟化表格包装器中正常工作。
## Bug 修复
* **Checkbox**:移除选中/半选指示态中硬编码的 `accent-hover` 背景 ([#6487](https://github.com/heroui-inc/heroui/pull/6487))
* **Autocomplete**:`isDisabled` 现通过 context 从根节点传递到 `Trigger` 与 `ClearButton` ([#6443](https://github.com/heroui-inc/heroui/pull/6443))
* **Description**:移除表单字段中说明文字的多余水平内边距(textfield、color-field、date-field、number-field、search-field、time-field) ([#6484](https://github.com/heroui-inc/heroui/pull/6484))
* **Tooltip**:内边距由 `px-2 py-1` 调整为 `p-2`,圆角改为使用设计令牌 ([#6481](https://github.com/heroui-inc/heroui/pull/6481))
* **Theme Builder**:修复 `accent-foreground` 取值被对调的问题 ([#6401](https://github.com/heroui-inc/heroui/pull/6401))
* **柔和色对比度**:浅色强调主题(Sky、Lavender、Mint)下,`accent-soft-foreground` 现使用更深一级的色阶,修复次要按钮、Chip 与 Badge 上文字几乎不可见的问题。共享主题现从 `--accent-soft-foreground` 读取,并回退到 `--accent`
## 链接
* [组件文档](/docs/react/components)
* [Figma Kit v3](https://www.figma.com/community/file/1546526812159103429/heroui-figma-kit-v3)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #6483](https://github.com/heroui-inc/heroui/pull/6483)
## 贡献者
感谢每一位为本次发布做出贡献的开发者!
# v3.0.5
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-0-5
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-0-5.mdx
> Text 重命名为 Typography(破坏性变更),颜色令牌重构为无前缀源变量,修复 Checkbox 与 Radio 边框对齐,并新增 CLI 文档页。
2026 年 5 月 15 日
补丁版本:`Text` 重命名为 `Typography`,以解决 `tailwind-merge` 冲突导致变体类名被静默丢弃的问题。派生颜色令牌(`hover`、`soft`、`border-secondary` 等)从 `theme.css` 中的 `@theme inline` 别名迁移到 `variables.css` 作为无前缀源变量,组件 CSS 可直接引用。此外还修复了 Checkbox 与 Radio 的边框对齐问题,优化了 Calendar 的 `accent-soft-foreground` 悬停样式,并新增了 CLI 文档页。
⚠️ **破坏性变更**:`Text` → `Typography`。BEM 块名由 `text` 改为 `typography`(例如 `text--body-sm` → `typography--body-sm`)。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@latest @heroui/react@latest
```
```bash
pnpm add @heroui/styles@latest @heroui/react@latest
```
```bash
yarn add @heroui/styles@latest @heroui/react@latest
```
```bash
bun add @heroui/styles@latest @heroui/react@latest
```
**正在使用 AI 助手?** 只需对它说一句「Hey Cursor,把 HeroUI 升级到最新版本」,AI 助手就会自动对比版本并应用必要的变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## ⚠️ 破坏性变更
### `Text` → `Typography`
[v3.0.4](/docs/react/releases/v3-0-4) 中发布的该组件使用了 `text-*` BEM 修饰符,与 Tailwind 的 `text-*` 工具类家族冲突。`tailwind-variants` 在每次变体组合时都会运行 `tailwind-merge`,并将 `text--body-sm`、`text--color-muted`、`text--weight-normal` 去重为单个类名——从而静默丢弃其他类名。
将块名重命名为 `typography` 可永久解决该冲突 ([#6505](https://github.com/heroui-inc/heroui/pull/6505),修复 [#6497](https://github.com/heroui-inc/heroui/issues/6497))。
**之前:**
```tsx
import {Text} from "@heroui/react";
Hello world
;
```
**之后:**
```tsx
import {Typography} from "@heroui/react";
Hello world
;
```
子组件同样重命名:
| 之前 | 之后 |
| ---------------- | ---------------------- |
| `Text` | `Typography` |
| `Text.Heading` | `Typography.Heading` |
| `Text.Paragraph` | `Typography.Paragraph` |
| `Text.Code` | `Typography.Code` |
| `Text.Prose` | `Typography.Prose` |
CSS BEM 类名也会相应变更:`.text` → `.typography`,`.text--body-sm` → `.typography--body-sm` 等。完整类名参考请参阅 [Typography 文档](/docs/components/typography)。
```tsx
import {Typography} from "@heroui/react";
const scale = [
{
label: "h1",
meta: "36px / 600 / 1.11 / tight",
sample: "打造更出色的界面",
type: "h1" as const,
},
{
label: "h2",
meta: "30px / 600 / 1.17 / tight",
sample: "为智能时代而生",
type: "h2" as const,
},
{
label: "h3",
meta: "24px / 600 / 1.25 / tight",
sample: "按您的条件定价",
type: "h3" as const,
},
{
label: "h4",
meta: "20px / 600 / 1.33 / tight",
sample: "申请创业计划",
type: "h4" as const,
},
{
label: "h5",
meta: "18px / 600 / 1.39 / tight",
sample: "卡片标题",
type: "h5" as const,
},
{
label: "h6",
meta: "16px / 600 / 1.50 / tight",
sample: "较小的功能标题",
type: "h6" as const,
},
{
label: "body",
meta: "16px / 400 / 1.75",
sample: "用于文档、营销文案与描述的主要正文。",
type: "body" as const,
},
{
label: "body-sm",
meta: "14px / 400 / 1.50",
sample: "次要正文、表格单元格、导航与侧边栏项。",
type: "body-sm" as const,
},
{
label: "body-xs",
meta: "12px / 400 / 1.25",
sample: "说明文字、徽章、辅助文本与细则。",
type: "body-xs" as const,
},
{
label: "code",
meta: "14px / mono",
sample: "pnpm add @heroui/react",
type: "code" as const,
},
] as const;
export const TypographyScale = () => {
return (
{scale.map((row) => (
{row.label}
{row.meta}
{row.sample}
))}
);
};
```
## 样式重构
### 无前缀源颜色令牌
所有派生颜色令牌——`*-hover`、`*-soft`、`*-soft-foreground`、`border-secondary` 等——从 `theme.css` 中的 `@theme inline` 别名迁移到 `variables.css` 作为无前缀源变量,24 个组件 CSS 文件现直接引用源令牌 ([#6499](https://github.com/heroui-inc/heroui/pull/6499))。
**1. `color-mix` 公式从 `theme.css` 移至 `variables.css`**
之前——计算逻辑位于 `@theme inline` 块内:
```css
/* packages/styles/themes/shared/theme.css */
--color-accent-hover: color-mix(in oklab, var(--accent) 90%, var(--accent-foreground) 10%);
--color-accent-soft: var(--accent-soft, color-mix(in oklab, var(--accent) 15%, transparent));
--color-accent-soft-foreground: var(--accent-soft-foreground, var(--accent));
--color-border-secondary: color-mix(in oklab, var(--surface) 78%, var(--surface-foreground) 22%);
```
之后——`theme.css` 仅保留别名;公式位于 `variables.css`:
```css
/* packages/styles/themes/default/variables.css */
--accent-hover: color-mix(in oklab, var(--accent) 90%, var(--accent-foreground) 10%);
--accent-soft: color-mix(in oklab, var(--accent) 15%, transparent);
--accent-soft-foreground: var(--accent);
--border-secondary: color-mix(in oklab, var(--surface) 78%, var(--surface-foreground) 22%);
/* packages/styles/themes/shared/theme.css */
--color-accent-hover: var(--accent-hover);
--color-accent-soft: var(--accent-soft);
--color-accent-soft-foreground: var(--accent-soft-foreground);
--color-border-secondary: var(--border-secondary);
```
**2. 组件 CSS 直接使用源令牌**
之前——各处使用 `var(--color-*)` 引用:
```css
/* packages/styles/components/button.css */
.button--primary {
--button-bg: var(--color-accent);
--button-bg-hover: var(--color-accent-hover);
--button-fg: var(--color-accent-foreground);
}
.button--secondary {
--button-bg: var(--color-default);
--button-bg-hover: var(--color-default-hover);
--button-fg: var(--color-accent-soft-foreground);
}
```
之后——无前缀源令牌:
```css
/* packages/styles/components/button.css */
.button--primary {
--button-bg: var(--accent);
--button-bg-hover: var(--accent-hover);
--button-fg: var(--accent-foreground);
}
.button--secondary {
--button-bg: var(--default);
--button-bg-hover: var(--default-hover);
--button-fg: var(--accent-soft-foreground);
}
```
`@theme inline` 块仍将每个 `--color-*` 暴露为 Tailwind 工具类别名,因此用户侧的类名用法(`bg-accent`、`text-accent` 等)不受影响。
**3. Theme builder 合并精简**
三个派生令牌辅助函数(`getAccentDerivedVariables`、`getSemanticDerivedVariables`、`getFieldDerivedVariables`)合并为单一的 `getDerivedColorVariables()`,输出完整的无前缀源令牌集合,并包含 `darkenForSoftForeground` 逻辑,以确保浅色强调主题下 soft-foreground 文字仍清晰可读。
## 样式修复
* **Calendar / Range Calendar**:日期单元格默认悬停样式现使用 `accent-soft-foreground` 而非 `accent`,使浅色强调主题下悬停单元格仍清晰可读。文档站搜索标签的选中状态也做了相同调整 ([#6500](https://github.com/heroui-inc/heroui/pull/6500))。
* **Checkbox**:`.checkbox__control` 现已应用与 `.radio__control` 相同的基础样式:`border`、`border-field-border` 以及 `[border-width:var(--border-width-field)]`,并将 `border-color` 加入过渡属性列表 ([#6521](https://github.com/heroui-inc/heroui/pull/6521))。
* **Radio**:`.radio__control` 默认边框现使用 `border-field-border`,而非 Tailwind 通用的 `border` 颜色,与 Input、Select、TextArea、NumberField 保持一致 ([#6522](https://github.com/heroui-inc/heroui/pull/6522))。
## 文档
### CLI 页面
新增 [CLI 文档页](/docs/react/getting-started/cli),涵盖安装、`init`、`install`、`upgrade`、`uninstall`、`list`、`doctor` 与 `env` 命令及示例输出 ([#6498](https://github.com/heroui-inc/heroui/pull/6498))。
## 依赖项
各软件包版本升级 ([#6529](https://github.com/heroui-inc/heroui/pull/6529)):
* **`react` / `react-dom`**:`19.2.3` → `19.2.6`
* **`@types/react`**:`19.2.7` → `19.2.14`
* **`next`**(文档站):`16.1.1` → `16.2.6`
* **CI actions**:`actions/checkout@v6`、`actions/setup-node@v6`、`actions/cache@v5`、`pnpm/action-setup@v6`
## 链接
* [组件文档](/docs/react/components)
* [Figma Kit V3](https://www.figma.com/community/file/1546526812159103429/heroui-figma-kit-v3)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #6503](https://github.com/heroui-inc/heroui/pull/6503)
## 贡献者
感谢所有为本次发布做出贡献的朋友!
# v3.1.0
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-1-0
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-1-0.mdx
> 中文 React 文档、可访问的 soft foreground 令牌、统一滚动条、useTheme SSR 修复、Toast 清理、Link 下划线与 RTL 布局优化。
import {HandPointUp} from "@gravity-ui/icons";
2026 年 5 月 25 日
v3.1.0 是小版本发布:新增中文 React 文档与本地化示例,soft foreground 默认达到无障碍对比度,滚动条统一由 `data-scrollbar` 和主题变量控制;同时修复 `useTheme`、Toast、Link、Fieldset、浮层和 RTL 布局问题。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@latest @heroui/react@latest
```
```bash
pnpm add @heroui/styles@latest @heroui/react@latest
```
```bash
yarn add @heroui/styles@latest @heroui/react@latest
```
```bash
bun add @heroui/styles@latest @heroui/react@latest
```
**正在使用 AI 助手?** 对它说「Hey Cursor,把 HeroUI 升级到最新版本」。它会对比版本并应用必要变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新增内容
### 中文 React 文档
React 文档、迁移指南、发布说明和示例现在都有中文版本 ([#6533](https://github.com/heroui-inc/heroui/pull/6533))。组件页、入门指南和迁移参考都可以按 locale 发布。
### 可访问的 Soft Foreground 令牌
Soft 状态不再直接套语义色,而是使用专门的 foreground token,让 Badge、Chip、Alert、Toast、Avatar 和 Calendar 范围状态的文字对比度更稳定 ([#6548](https://github.com/heroui-inc/heroui/pull/6548))。
可直接覆盖这些 token:
* `--default-soft`
* `--default-soft-foreground`
* `--default-soft-hover`
* `--accent-soft-foreground`
* `--danger-soft-foreground`
* `--warning-soft-foreground`
* `--success-soft-foreground`
默认 palette 现在使用符合无障碍对比度的 soft foreground。需要旧版更饱和、但对比度更低的颜色时,在根元素启用 vibrant palette:
```html
...
```
```tsx
import {Chip, Separator} from "@heroui/react";
const variants = ["primary", "secondary", "tertiary", "soft"] as const;
const colors = ["accent", "default", "success", "warning", "danger"] as const;
const VARIANT_LABELS: Record<(typeof variants)[number], string> = {
primary: "主要",
secondary: "次要",
soft: "柔和",
tertiary: "第三",
};
const COLOR_LABELS: Record<(typeof colors)[number], string> = {
accent: "强调",
danger: "危险",
default: "默认",
success: "成功",
warning: "警告",
};
function ChipMatrix({isVibrant, title}: {isVibrant?: boolean; title: string}) {
return (
{title}
{colors.map((color) => (
{COLOR_LABELS[color]}
))}
{variants.map((variant) => (
{VARIANT_LABELS[variant]}
{colors.map((color) => (
{COLOR_LABELS[color]}
))}
))}
);
}
export function ChipVibrantPalette() {
return (
);
}
```
### 统一滚动条系统
滚动容器现在共享同一套标准 CSS 滚动条工具:主题 token 负责颜色和宽度,`data-scrollbar` 负责模式切换 ([#6545](https://github.com/heroui-inc/heroui/pull/6545))。组件滚动区域和自定义 overflow 区域都读取同一组 `--scrollbar-*` 变量。
三种模式:
* HeroUI 纤细:不设置 `data-scrollbar`,或设置 `data-scrollbar="thin"`。
* 浏览器默认:设置 `data-scrollbar="default"`,使用操作系统 / 浏览器滚动条。
* 隐藏:设置 `data-scrollbar="none"`,隐藏滚动条但保留滚动。
```html
使用 HeroUI 主题滚动条
使用浏览器默认滚动条
隐藏后代 HeroUI 滚动条
```
垂直滚动
```tsx
import {ListBox, Surface} from "@heroui/react";
type ScrollbarMode = {
id: string;
label: string;
scrollbar?: "thin" | "default" | "none";
};
const modes: ScrollbarMode[] = [
{
id: "heroui",
label: "HeroUI 纤细",
scrollbar: "thin",
},
{
id: "browser",
label: "浏览器默认",
scrollbar: "default",
},
{
id: "hidden",
label: "隐藏",
scrollbar: "none",
},
];
const animals = [
{id: "aardvark", name: "土豚"},
{id: "alpaca", name: "羊驼"},
{id: "antelope", name: "羚羊"},
{id: "bear", name: "熊"},
{id: "cat", name: "猫"},
{id: "dog", name: "狗"},
{id: "fox", name: "狐狸"},
{id: "giraffe", name: "长颈鹿"},
{id: "kangaroo", name: "袋鼠"},
{id: "koala", name: "考拉"},
{id: "lemur", name: "狐猴"},
{id: "otter", name: "水獭"},
{id: "panda", name: "熊猫"},
{id: "penguin", name: "企鹅"},
{id: "rabbit", name: "兔子"},
{id: "snake", name: "蛇"},
{id: "turtle", name: "海龟"},
{id: "wombat", name: "袋熊"},
{id: "zebra", name: "斑马"},
];
function ScrollbarListBox({mode}: {mode: ScrollbarMode}) {
return (
{mode.label}
{animals.map((animal) => (
{animal.name}
))}
);
}
export function ScrollbarModes() {
return (
{modes.map((mode) => (
))}
);
}
```
Select、ComboBox、Autocomplete、Dropdown、DatePicker、DateRangePicker、ColorPicker、Table、Tabs、Modal、Drawer 和 ScrollShadow 已接入同一套工具。
自定义滚动插槽使用 `scrollbar`。它读取最近的 `data-scrollbar` 祖先,并自动应用对应的 `--scrollbar-width`、`--scrollbar-color` 和 `--scrollbar-gutter`。
```css
.alert-dialog__body {
@apply min-h-0 flex-1 scrollbar;
}
```
主题变量也从单个固定的 `--scrollbar` 颜色,改为一组更细的滚动条 token:
```css
/* before */
--scrollbar: oklch(70.5% 0.015 286.067);
/* after */
--scrollbar: var(--scrollbar-thumb);
--scrollbar-thumb: color-mix(in oklch, var(--foreground) 15%, transparent);
--scrollbar-track: transparent;
--scrollbar-gutter: auto;
--scrollbar-width: thin;
--scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
```
`--scrollbar` 保留为兼容别名;新的 thumb、track、gutter、width 和 color token 控制最终滚动条。
恢复浏览器默认滚动条:在 ``、`` 或任意嵌套容器上设置 `data-scrollbar="default"`。如果全局已设为默认,但某个局部仍要 HeroUI 样式,在该容器上加 `data-scrollbar="thin"`。
```html
```
## 组件与运行时修复
* **Fieldset**:`disabled` 会传给字段标签,并禁用后代 React Aria `RadioGroup` 与 `Slider` ([#6547](https://github.com/heroui-inc/heroui/pull/6547))。
* **Toast**:非前台 Toast 不再进入 Tab 顺序;卸载时清理已测量高度 ([#6510](https://github.com/heroui-inc/heroui/pull/6510), [#6512](https://github.com/heroui-inc/heroui/pull/6512))。
* **`useTheme`**:SSR 不再读取浏览器 API;`resolvedTheme` 改为派生值;系统主题订阅改用 `useSyncExternalStore` ([#6561](https://github.com/heroui-inc/heroui/pull/6561))。
* **Link**:默认无下划线;hover 使用 50% 装饰色;active / pressed 使用 100%;移除下划线装饰色过渡 ([#6570](https://github.com/heroui-inc/heroui/pull/6570), [#6571](https://github.com/heroui-inc/heroui/pull/6571))。
## 布局、浮层与 RTL 修复
* **浮层定位**:进入动画只过渡 `opacity` 和 `transform`,不再动画化 React Aria 写入的定位值 ([#6549](https://github.com/heroui-inc/heroui/pull/6549))。
* **Dialog 与 Modal 聚焦**:Modal 和 AlertDialog 内容改用裁剪处理,避免 focus 触发程序化滚动;body focus ring 不再被 overflow 裁掉 ([#6448](https://github.com/heroui-inc/heroui/pull/6448), [#6557](https://github.com/heroui-inc/heroui/pull/6557))。
* **RTL Table 圆角**:Table 改用逻辑方向的 `border-radius`,RTL 外侧圆角保持正确 ([#6568](https://github.com/heroui-inc/heroui/pull/6568))。
* **RTL Picker 与 Menu 指示器**:Select、ListBox.Item、Autocomplete、ComboBox 和 MenuItem 改用 logical inline start/end,覆盖 chevron、value、checkmark、trigger 和 submenu indicator ([#6573](https://github.com/heroui-inc/heroui/pull/6573))。
## 文档与依赖
* 主题文档同步当前 `theme.css` / `variables.css`:soft foreground 令牌和滚动条变量都已更新。
* 发布说明和迁移文档同步 Link 行为。
* 文档站新增 `@fumadocs/language`;`fumadocs-core` / `fumadocs-ui` 升级到 `16.9.0`。
* 文档和样式包的 Tailwind 工具升级到 `4.3.0`。
## 链接
* [组件文档](/docs/react/components)
* [主题文档](/docs/react/getting-started/theming)
* [Figma Kit V3](https://www.figma.com/community/file/1546526812159103429/heroui-figma-kit-v3)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #6576](https://github.com/heroui-inc/heroui/pull/6576)
## 贡献者
感谢所有为本次发布做出贡献的朋友!
# v3.2.0
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-2-0
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-2-0.mdx
> 基于 React Aria 1.18 的 Calendar 周/日视图与年份选择器,以及 Radio、Checkbox、Switch 的破坏性组合方式变更。
2026 年 6 月 15 日
Calendar 新增周视图与日视图、重做的年份选择器,以及基于 React Aria 1.18 的范围日历演示。[Autocomplete](/docs/components/autocomplete) 新增用于大型选项列表的 Virtualizer 示例。[Tooltip](/docs/components/tooltip) 新增用于全局显示与隐藏延迟的主题变量。Radio、Checkbox、Switch 迁移到 React Aria 的 `*Field` + `*Button` 组合方式。本次发布同时纳入了虚拟化列表、分组字段自动填充、Toast 与 Fieldset 行为,以及滚动与 RTL 样式方面的补丁修复。
⚠️ **破坏性变更**:`Radio`、`Checkbox`、`Switch` 改为显式的 `*.Content` 组合 —— `*.Control` 嵌套进 `*.Content`,标签变为 `*.Content` 内的纯文本(不嵌套 ``),`Description`/`FieldError` 变为 `*.Content` 的兄弟节点。详见[破坏性变更](#%EF%B8%8F-breaking-changes)。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@latest @heroui/react@latest
```
```bash
pnpm add @heroui/styles@latest @heroui/react@latest
```
```bash
yarn add @heroui/styles@latest @heroui/react@latest
```
```bash
bun add @heroui/styles@latest @heroui/react@latest
```
**正在使用 AI 助手?** 对它说「Hey Cursor,把 HeroUI 升级到最新版本」。它会对比版本并应用必要变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新增内容
### Calendar
`Calendar` 与 `RangeCalendar` 新增周视图与日视图,以及来自 React Aria 1.18 的新日历属性。
* **周视图 / 日视图**:通过 `visibleDuration` 渲染多周或单日布局
* **多选**:在单个 `Calendar` 中选择多个日期
* **React Aria 1.18 属性**:`weeksInMonth` 与用于范围选择的 `isDateUnavailable(date, anchorDate)`
* **内部实现**:月份标题使用 React Aria 的 `CalendarHeading`,年份选择器基于 React Aria calendar hooks 重建
**周视图:**
```tsx
"use client";
import {Calendar, Label, ListBox, Select} from "@heroui/react";
import {useState} from "react";
const weekOptions = [
{id: "1", name: "1 周"},
{id: "2", name: "2 周"},
{id: "3", name: "3 周"},
{id: "4", name: "4 周"},
{id: "5", name: "5 周"},
{id: "6", name: "6 周"},
{id: "8", name: "8 周"},
] as const;
export function WeekView() {
const [weeks, setWeeks] = useState(1);
return (
value && setWeeks(Number(value))}
>
可见周数
{weekOptions.map((option) => (
{option.name}
))}
{(day) => {day} }
{(date) => }
);
}
```
**日视图:**
```tsx
"use client";
import {Calendar, Label, ListBox, Select} from "@heroui/react";
import {useState} from "react";
const dayOptions = [
{id: "1", name: "1 天"},
{id: "5", name: "5 天"},
{id: "7", name: "7 天"},
{id: "8", name: "8 天"},
{id: "10", name: "10 天"},
{id: "14", name: "14 天"},
{id: "21", name: "21 天"},
] as const;
export function DayView() {
const [days, setDays] = useState(5);
return (
value && setDays(Number(value))}
>
可见天数
{dayOptions.map((option) => (
{option.name}
))}
{(day) => {day} }
{(date) => }
);
}
```
**多选:**
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {Calendar, Description} from "@heroui/react";
import {useState} from "react";
export function MultipleSelection() {
const [value, setValue] = useState([]);
return (
{(day) => {day} }
{(date) => }
{value?.length ? `已选择 ${value.length} 个日期` : "可选择多个日期"}
);
}
```
### Autocomplete
支持通过 Virtualizer 渲染大型选项列表,并补充文档、Storybook 示例,以及针对 popover 尺寸和 listbox 滚动高度的样式修复。
* **虚拟化**:在 `Autocomplete.Popover` 内用 React Aria 的 `` 包裹 `ListBox` ([#6642](https://github.com/heroui-inc/heroui/pull/6642))
* **Popover 尺寸**:listbox 高度上限为 `320px` 并支持内部滚动;搜索框固定在列表上方
**虚拟化:**
```tsx
"use client";
import type {Key} from "@heroui/react";
import {
Autocomplete,
Description,
EmptyState,
Label,
ListBox,
ListLayout,
SearchField,
Virtualizer,
useFilter,
} from "@heroui/react";
import {useMemo, useState} from "react";
interface User {
email: string;
id: number;
name: string;
}
function generateUsers(n: number): User[] {
const firstNames = [
"Emma",
"Liam",
"Olivia",
"Noah",
"Ava",
"James",
"Sophia",
"Oliver",
"Isabella",
"Lucas",
"Mia",
"Ethan",
"Charlotte",
"Mason",
"Amelia",
"Logan",
"Harper",
"Alexander",
"Ella",
"Benjamin",
];
const lastNames = [
"Smith",
"Johnson",
"Williams",
"Brown",
"Jones",
"Garcia",
"Miller",
"Davis",
"Rodriguez",
"Martinez",
"Anderson",
"Taylor",
"Thomas",
"Jackson",
"White",
"Harris",
"Clark",
"Lewis",
"Robinson",
"Walker",
];
const users: User[] = [];
for (let i = 0; i < n; i++) {
const firstName = firstNames[i % firstNames.length]!;
const lastName = lastNames[Math.floor(i / firstNames.length) % lastNames.length]!;
const name = `${firstName} ${lastName}`;
users.push({
email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@acme.com`,
id: i + 1,
name,
});
}
return users;
}
export function Virtualization() {
const [selectedKey, setSelectedKey] = useState(null);
const [searchQuery, setSearchQuery] = useState("");
const {contains} = useFilter({sensitivity: "base"});
const allUsers = useMemo(() => generateUsers(1000), []);
const filteredUsers = useMemo(() => {
if (!searchQuery) return allUsers;
return allUsers.filter(
(user) => contains(user.name, searchQuery) || contains(user.email, searchQuery),
);
}, [allUsers, contains, searchQuery]);
return (
用户
未找到结果 }
>
{(user) => (
{user.name}
{user.email}
)}
);
}
```
### Table.SortableColumnHeader
`Table.SortableColumnHeader` 用于渲染 sortable 列标题和可选的升降序指示器。放在 `Table.Column` render prop 中,并传入 `sortDirection` ([#6588](https://github.com/heroui-inc/heroui/pull/6588))。
```tsx
{({sortDirection}) => (
Name
)}
```
* **默认指示器**:存在排序方向时显示 chevron
* **自定义指示器**:传入 `indicator`,或用 `showIndicator={false}` 隐藏
* **样式插槽**:`.table__sortable-column-header` + `.table__sortable-column-indicator`
```tsx
"use client";
import type {SortDescriptor} from "@heroui/react";
import {Table} from "@heroui/react";
import {useMemo, useState} from "react";
interface User {
id: number;
name: string;
role: string;
status: string;
email: string;
}
const users: User[] = [
{email: "kate@acme.com", id: 1, name: "Kate Moore", role: "首席执行官", status: "在职"},
{email: "john@acme.com", id: 2, name: "John Smith", role: "首席技术官", status: "在职"},
{email: "sara@acme.com", id: 3, name: "Sara Johnson", role: "首席营销官", status: "休假"},
{email: "michael@acme.com", id: 4, name: "Michael Brown", role: "首席财务官", status: "在职"},
{
email: "emily@acme.com",
id: 5,
name: "Emily Davis",
role: "产品经理",
status: "未激活",
},
];
export function Sorting() {
const [sortDescriptor, setSortDescriptor] = useState({
column: "name",
direction: "ascending",
});
const sortedUsers = useMemo(() => {
return [...users].sort((a, b) => {
const col = sortDescriptor.column as keyof User;
const first = String(a[col]);
const second = String(b[col]);
let cmp = first.localeCompare(second);
if (sortDescriptor.direction === "descending") {
cmp *= -1;
}
return cmp;
});
}, [sortDescriptor]);
return (
{({sortDirection}) => (
姓名
)}
{({sortDirection}) => (
角色
)}
{({sortDirection}) => (
状态
)}
{({sortDirection}) => (
邮箱
)}
{sortedUsers.map((user) => (
{user.name}
{user.role}
{user.status}
{user.email}
))}
);
}
```
### Tooltip 延迟主题变量
[Tooltip](/docs/components/tooltip) 现在会从主题 CSS 变量读取默认的显示与隐藏延迟 ([#6617](https://github.com/heroui-inc/heroui/pull/6617)):
* `--tooltip-delay` — 显示 Tooltip 前的延迟(默认:`1500ms`)
* `--tooltip-close-delay` — 隐藏 Tooltip 前的延迟(默认:`500ms`)
全局覆盖示例:
```css
:root {
--tooltip-delay: 700ms;
--tooltip-close-delay: 0ms;
}
```
单个 Tooltip 上的 `delay` 和 `closeDelay` 属性仍会覆盖这些值。
**行为变更:** 使用默认 HeroUI 主题时,Tooltip 延迟现在默认为 `1500ms` / `500ms`,而不是之前的 React Aria 默认值 `700ms` / `0ms`。如需保留旧行为,请显式设置 CSS 变量或 props。
## 组件修复
* **Toast**:Toast 队列会串行化 ViewTransition 更新,避免在 `toast.promise()` 关闭 loading toast 并打开成功/失败反馈时出现被跳过的过渡和 AbortError ([#6511](https://github.com/heroui-inc/heroui/pull/6511))。
* **Fieldset**:`disabled` 会传递到 React Aria 的 Button、CheckboxGroup、Link、RadioGroup、Slider、ToggleButton 和 ToggleButtonGroup 上下文 ([#6596](https://github.com/heroui-inc/heroui/pull/6596))。
* **Autocomplete**:Popover 内容包裹在 React Aria 的 `Dialog` 中,打开 popover 时 listbox 不再出现多余的焦点环 ([#6627](https://github.com/heroui-inc/heroui/pull/6627))。
* **Tooltip**:Trigger 改用 `useFocusable` hook 而非 `` 包装组件,避免 Tooltip 挂载在 `inert` 子树中(例如位于已打开的 Drawer/Modal 之后)时出现误报的 “child must be focusable” 警告 ([#6628](https://github.com/heroui-inc/heroui/pull/6628))。
## 样式修复
* **Modal / AlertDialog**:`scroll-inside` 对话框通过 `max-h-full min-h-0` 限制高度,使内容区域滚动而非溢出 ([#6597](https://github.com/heroui-inc/heroui/pull/6597))。
* **ScrollShadow**:渐隐遮罩通过 `--scroll-shadow-scrollbar-size` 为可见的原生滚动条预留空间 ([#6598](https://github.com/heroui-inc/heroui/pull/6598))。
* **Table RTL**:列分隔线与拖拽手柄在 RTL 下使用逻辑属性 `end-0` 定位 ([#6606](https://github.com/heroui-inc/heroui/pull/6606))。
* **Link**:移除硬编码的 `text-sm`,让链接从父元素继承字号;`.link__icon` 改为相对单位 `size-[0.75em]`,随文本大小缩放,而不再使用固定的 `size-2` ([#6621](https://github.com/heroui-inc/heroui/pull/6621))。
* **DatePicker / DateRangePicker**:日历 popover 由 `max-w-(--trigger-width)` 改为 `min-w-(--trigger-width)`,确保 popover 至少与触发器一样宽,避免被水平裁剪 ([#6622](https://github.com/heroui-inc/heroui/pull/6622))。
* **Table**:当 Table 被 React Aria 的 `` 包裹时,secondary 表头的边框与圆角能够正确渲染 —— 列选择器不再把每个虚拟化列都同时视为 first 和 last child ([#6624](https://github.com/heroui-inc/heroui/pull/6624))。
* **Autocomplete**:Popover 限制为触发器宽度,listbox 高度上限为 `320px` 并支持内部滚动,避免虚拟化列表溢出 popover ([#6642](https://github.com/heroui-inc/heroui/pull/6642))。
* **ListBox**:将 `flex flex-col gap` 改为普通块级流 + 兄弟节点间距,避免 React Aria Virtualizer 的内容高度被 flex-shrink 压缩 —— 修复虚拟化滚动时滚动条滑块尺寸变化的问题 ([#6636](https://github.com/heroui-inc/heroui/pull/6636))。
* **InputGroup / NumberField / SearchField**:浏览器自动填充高亮提升到分组容器上,使 prefix、suffix 和增减按钮槽位共享圆角高亮 ([#6625](https://github.com/heroui-inc/heroui/pull/6625))。
* **Spinner**:改用 `inline-flex` 搭配 `shrink-0`(替代 `relative`),使旋转动画在非 flex 布局中也能正确渲染,并支持 `motion-reduce` ([#6644](https://github.com/heroui-inc/heroui/pull/6644))。
* **Toast**:关闭按钮在所有断点下统一使用 `-top-1 -right-1`,与容器内边距对齐 ([#6574](https://github.com/heroui-inc/heroui/pull/6574))。
## 依赖
* **React Aria Components**:`1.17.0` → `1.18.0` ([#6586](https://github.com/heroui-inc/heroui/pull/6586))。1.18 引入了 toggles 所采用的 `*Field` + `*Button` 组合方式、`CalendarHeading`,以及 `isDateUnavailable(date, anchorDate)`。
* **@internationalized/date**:`3.12.1` → `3.12.2`
* **React Aria / Stately 辅助包**:`@react-aria/*`、`@react-stately/*` 与 `@react-types/shared` 补丁更新
## ⚠️ Breaking Changes
### Radio、Checkbox 与 Switch:显式 `*.Content` 组合
这些组件现在在底层使用 React Aria 的 `*Field` + `*Button` 组合方式。`X.Content` 现在是**可点击的 label**(React Aria 的 `*Button`)。共有三点变化:
* **`X.Control` 移进 `X.Content`** —— 它们以前是兄弟节点。
* **标签是 `X.Content` 内部的纯文本** —— `X.Content` 渲染的是 `` 元素,所以不要嵌套 `` 组件(嵌套的 `` 是无效 HTML)。若要使用独立的 `Label`,请把它放在**外部**,并用 `htmlFor` + 组件 `id` 关联。
* **`Description`/`FieldError` 移到外部**,作为 `X.Content` 的兄弟节点,这样它们会通过 `aria-describedby` 朗读,而不会被并入无障碍名称。
**Checkbox**
```tsx
// v3.1
Accept terms
You agree to our terms
// v3.2
Accept terms
You agree to our terms
```
**Radio**
```tsx
// v3.1
Option A
// v3.2
Option A
```
**Switch**
```tsx
// v3.1
Enable notifications
// v3.2
Enable notifications
```
**迁移对照**
| v3.1 | v3.2 |
| --------------------------------------------- | ------------------------------------------------- |
| `X.Control` 与 `X.Content` 为兄弟节点 | `X.Control` 嵌套进 `X.Content` |
| `X.Content` 是包裹 `Label` + 帮助文本的布局 `` | `X.Content` 是包裹 `X.Control` + 标签文本的可点击 `
` |
| 通过 `X.Content` 内的 `` 提供标签 | 标签是 `X.Content` 内的**纯文本**(不嵌套 ``) |
| `Description` / `FieldError` 位于 `X.Content` 内 | `Description` / `FieldError` 作为 `X.Content` 的兄弟节点 |
**外部标签** —— 若要使用独立的 `Label`,请把它放在组件外部,并用 `htmlFor` + 组件 `id` 关联:
```tsx
Accept terms
```
**仅含控件的 Checkbox 和 Switch**(没有标签,例如表格行选择或图标开关)仍需用 `X.Content` 作为可点击包装。请把 `Checkbox.Control` / `Switch.Control` 放进 `X.Content`,省略标签,并在根组件上传入 `aria-label`。
各组件完整迁移指南:[Checkbox](/docs/react/migration/checkbox)、[Checkbox Group](/docs/react/migration/checkbox-group)、[Radio](/docs/react/migration/radio)、[Radio Group](/docs/react/migration/radio-group)、[Switch](/docs/react/migration/switch)。
## 链接
* [Calendar 文档](/docs/react/components/calendar)
* [Autocomplete 文档](/docs/react/components/autocomplete)
* [Tooltip 文档](/docs/react/components/tooltip)
* [Checkbox 文档](/docs/react/components/checkbox)
* [Radio Group 文档](/docs/react/components/radio-group)
* [Switch 文档](/docs/react/components/switch)
* [组件文档](/docs/react/components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #6616](https://github.com/heroui-inc/heroui/pull/6616)
## 贡献者
感谢所有为本次发布做出贡献的人!
# v3.2.1
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-2-1
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-2-1.mdx
> 补丁版本:将 react-aria 从 @heroui/react 产物中外部化,并修复 SwitchGroup 横向布局。
2026 年 6 月 17 日
补丁版本:`@heroui/react` 不再内置自己的 `react-aria` 副本。`react-aria` 的子路径现在在 Rollup 构建中被外部化,因此会解析到你项目中安装的版本 —— 避免在 `@heroui/react` 内部打包出一份重复、内联的 `react-aria` 副本。本次发布还修复了 `SwitchGroup` 横向布局,补全缺失的 `switch-group__items` 包装层。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@latest @heroui/react@latest
```
```bash
pnpm add @heroui/styles@latest @heroui/react@latest
```
```bash
yarn add @heroui/styles@latest @heroui/react@latest
```
```bash
bun add @heroui/styles@latest @heroui/react@latest
```
**正在使用 AI 助手?** 对它说「Hey Cursor,把 HeroUI 升级到最新版本」。它会自动对比版本并应用必要变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 错误修复
* **@heroui/react**:将 `react-aria` 子路径与其他 `@react-*` 和 `react-aria-components` 一起在 Rollup 构建中外部化,使 `@heroui/react` 不再内置自己的 `react-aria` 副本。消费方现在会解析到项目中安装的单一 `react-aria`,避免重复实例的问题以及不必要的产物体积膨胀 ([#6653](https://github.com/heroui-inc/heroui/pull/6653))。
* **SwitchGroup**:补全缺失的 `switch-group__items` 包装层,使 `orientation="horizontal"` 时开关横向排列,而不再垂直堆叠 ([#6655](https://github.com/heroui-inc/heroui/pull/6655))。
## 链接
* [组件文档](/docs/react/components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #6654](https://github.com/heroui-inc/heroui/pull/6654)
## 贡献者
感谢所有为本次发布做出贡献的人!
# v3.2.2
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-2-2
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-2-2.mdx
> 补丁版本:将 React Aria 升级到 1.19.0,为 Tabs.ListContainer 添加溢出滚动,并修复清除/关闭按钮意外提交表单以及视觉隐藏输入框导致溢出滚动的问题。
2026 年 6 月 19 日
补丁版本:升级到 React Aria `1.19.0`(`react-aria@3.50.0`),为 [Tabs](/docs/components/tabs) 的 `Tabs.ListContainer` 添加溢出滚动,并修复多个回归问题 —— 清除和关闭按钮不再提交其所在的表单,`Checkbox`、`Radio` 和 `Switch` 中的视觉隐藏输入框不再导致溢出滚动。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@latest @heroui/react@latest
```
```bash
pnpm add @heroui/styles@latest @heroui/react@latest
```
```bash
yarn add @heroui/styles@latest @heroui/react@latest
```
```bash
bun add @heroui/styles@latest @heroui/react@latest
```
**正在使用 AI 助手?** 对它说「Hey Cursor,把 HeroUI 升级到最新版本」。它会自动对比版本并应用必要变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新功能
### Tabs
当标签列表超出可用空间时,`Tabs.ListContainer` 会自动渲染滚动箭头和边缘渐变,以便用户浏览隐藏的标签。适用于横向和纵向布局。
* **溢出滚动**:用 `Tabs.ListContainer` 包裹 `Tabs.List`,即可获得滚动箭头和边缘渐变 ([#6696](https://github.com/heroui-inc/heroui/pull/6696))
## 错误修复
* **输入框**:为清除和关闭按钮设置 `type="button"`,使其在点击时不再提交所在的表单 ([#6656](https://github.com/heroui-inc/heroui/pull/6656))。
* **Checkbox / Radio / Switch**:避免视觉隐藏的输入框导致溢出滚动 ([#6657](https://github.com/heroui-inc/heroui/pull/6657))。
* **Button / Dropdown / Menu**:添加 `will-change-transform`,避免在变换过程中图标或文本发生偏移 ([#6661](https://github.com/heroui-inc/heroui/pull/6661))。
* **Chip**:将宽度设置为 `w-fit`,使 chip 根据内容自适应宽度,而非拉伸填满容器 ([#6664](https://github.com/heroui-inc/heroui/pull/6664))。
* **DatePicker / DateRangePicker**:使用 `w-fit` 替代 `min-w-(--trigger-width)`,避免弹出层宽度过宽 ([#6665](https://github.com/heroui-inc/heroui/pull/6665))。
* **Autocomplete**:修正虚拟化列表项的右内边距,使列表项不再溢出到弹出层边缘 ([#6672](https://github.com/heroui-inc/heroui/pull/6672))。
* **Toast**:在 toast 队列中捕获 ViewTransition 的 `ready` 拒绝,使被取代的过渡不再产生未处理的 Promise 拒绝 ([#6674](https://github.com/heroui-inc/heroui/pull/6674))。
## 重构
* **React 19 API**:使用 `use()` hook 替代 `useContext`,并将 `ref` 作为普通 prop 传递;将数组索引 key 替换为稳定 key ([#6688](https://github.com/heroui-inc/heroui/pull/6688))。
## 依赖
* **React Aria**:升级到 `react-aria-components@1.19.0` 和 `react-aria@3.50.0` ([#6658](https://github.com/heroui-inc/heroui/pull/6658))。
* **React Aria**:将 `react-aria`(`^3.50.0`)和 `react-aria-components`(`^1.19.0`)声明为 caret 范围,以便与 HeroUI Pro 去重 ([#6689](https://github.com/heroui-inc/heroui/pull/6689))。
## 链接
* [组件文档](/docs/react/components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #6660](https://github.com/heroui-inc/heroui/pull/6660)
## 贡献者
感谢所有为本次发布做出贡献的人!
# v3.2.3
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-2-3
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-2-3.mdx
> 补丁版本:为 ComboBox 添加多选支持,采用逻辑 CSS 属性改进 RTL 支持,将 tailwind-variants 升级到 3.3.0,并修复 ScrollShadow、Spinner、InputOTP、Table 以及 accent Button 的样式问题。
2026 年 7 月 30 日
补丁版本:[ComboBox](/docs/components/combo-box) 现已支持多选,样式采用逻辑 CSS 属性以更好地支持 RTL,`tailwind-variants` 升级到 `3.3.0`,并修复了 `ScrollShadow`、`Spinner`、`InputOTP`、`Table` 以及 accent `Button` 焦点样式的多个问题。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@latest @heroui/react@latest
```
```bash
pnpm add @heroui/styles@latest @heroui/react@latest
```
```bash
yarn add @heroui/styles@latest @heroui/react@latest
```
```bash
bun add @heroui/styles@latest @heroui/react@latest
```
**正在使用 AI 助手?** 对它说「Hey Cursor,把 HeroUI 升级到最新版本」。它会自动对比版本并应用必要变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新功能
### ComboBox
[ComboBox](/docs/components/combo-box) 现已支持选择多个选项。设置 `selectionMode="multiple"`,使用 `ComboBox.Value` 渲染已选项,并同样为内部 `ListBox` 传入 `selectionMode="multiple"`。选择通过 `value` / `defaultValue`(`Key[]`)属性和 `onChange` 处理函数进行控制。
* **多选**:通过 `selectionMode="multiple"` 选择多个选项,并使用 `ComboBox.Value` 展示已选项 ([#6714](https://github.com/heroui-inc/heroui/pull/6714))
## 错误修复
* **ScrollShadow**:在末端检测中兼容小数滚动位置,使底部阴影在高分辨率屏幕上能正确隐藏 ([#6710](https://github.com/heroui-inc/heroui/pull/6710))。
* **RTL**:在样式中采用逻辑 CSS 属性,以更好地支持从右到左布局 ([#6699](https://github.com/heroui-inc/heroui/pull/6699))。
* **Button**:恢复 accent 按钮的焦点轮廓间隙 ([#6724](https://github.com/heroui-inc/heroui/pull/6724))。
* **Spinner**:将无障碍名称从隐藏的 SVG 移到根元素的 `status` role 上 ([#6721](https://github.com/heroui-inc/heroui/pull/6721))。
* **InputOTP**:避免 OTP 输入格在窄容器中溢出 ([#6706](https://github.com/heroui-inc/heroui/pull/6706))。
* **Table**:将可排序列的指示图标居中 ([#6705](https://github.com/heroui-inc/heroui/pull/6705))。
* **Collections**:修复 `Tabs`、`TagGroup`、`Select`、`Autocomplete` 和 `ComboBox` 的 React Aria 集合构建器兼容性问题 ([#6727](https://github.com/heroui-inc/heroui/pull/6727))。
* **Icons**:从装饰性的 `aria-hidden` 图标中移除永远不会被朗读的 `aria-label`,使无障碍检查与审计保持整洁 ([#6741](https://github.com/heroui-inc/heroui/pull/6741))。
## 依赖
* **tailwind-variants**:升级到 `tailwind-variants@3.3.0` ([#6733](https://github.com/heroui-inc/heroui/pull/6733))。
* **React Aria**:将 `react-aria`、`react-aria-components` 以及 `@react-aria/*` 工具包移至 `peerDependencies`,使使用方解析到唯一共享副本而非内置副本 ([#6744](https://github.com/heroui-inc/heroui/pull/6744))。
* **Node.js**:要求 Node.js `>= 22.x`。
## 链接
* [组件文档](/docs/react/components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #6708](https://github.com/heroui-inc/heroui/pull/6708)
## 贡献者
感谢所有为本次发布做出贡献的人!
# v3.2.4
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-2-4
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-2-4.mdx
> 补丁版本:修复 Autocomplete 弹层裁剪末尾选项的问题,恢复外部滚动模式下 Modal 点击遮罩关闭的行为,将 Tabs.ListContainer 的箭头滚动限制在可滚动范围内,将 tailwind-variants 升级到 3.3.1 以修复重新渲染后变体类名回退的问题,将 React Aria 升级到 1.20.0,并为 @heroui/react 添加行为测试套件。
2026 年 8 月 4 日
补丁版本:[Autocomplete](/docs/components/autocomplete) 弹层不再裁剪末尾选项,`scroll="outside"` 的 [Modal](/docs/components/modal) 重新支持点击遮罩关闭,[Tabs](/docs/components/tabs) 的箭头滚动现在会精确停在边缘,`tailwind-variants` 升级到 `3.3.1` 以修复重新渲染后变体修饰符回退到错误类名的问题,React Aria 升级到 `1.20.0`(`react-aria@3.51.0`),并为 `@heroui/react` 添加了行为测试套件。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@latest @heroui/react@latest
```
```bash
pnpm add @heroui/styles@latest @heroui/react@latest
```
```bash
yarn add @heroui/styles@latest @heroui/react@latest
```
```bash
bun add @heroui/styles@latest @heroui/react@latest
```
**正在使用 AI 助手?** 对它说「Hey Cursor,把 HeroUI 升级到最新版本」。它会自动对比版本并应用必要变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 错误修复
* **Variants**:修复重新渲染后变体修饰符回退到错误类名的问题——受控的 `Checkbox` 取消选中时不再从 `checkbox--primary` 变为 `checkbox--secondary`,secondary 变体的 `Tabs` 也不再回退到 primary 变体 ([#6760](https://github.com/heroui-inc/heroui/pull/6760))。
* **Autocomplete**:将弹层改为 flex 纵向布局,并允许列表收缩到 `320px` 上限以下,使弹层高度小于内容高度时末尾选项仍可访问——最常见于触发器位于视口中部的 `Modal` 场景 ([#6766](https://github.com/heroui-inc/heroui/pull/6766))。
* **Modal**:将 `scroll="outside"` 时的滚动移交给背景遮罩,使点击遮罩仍可关闭弹窗——占满视口高度的容器不再吞掉遮罩点击并将其判定为弹窗内部 ([#6770](https://github.com/heroui-inc/heroui/pull/6770))。
* **Tooltip**:在相邻 Tooltip 之间切换时保留进入与退出动画。React Aria 的预热计时器会抑制被替换 Tooltip 上的 `data-entering` / `data-exiting`,使其在 HeroUI 的 CSS 关键帧执行前就被卸载——如需恢复 React Aria 的即时切换行为,可传入新增的 `shouldSkipAnimation` 属性 ([#6772](https://github.com/heroui-inc/heroui/pull/6772))。
* **Tabs**:将 `Tabs.ListContainer` 的箭头滚动限制在可滚动范围内,靠近边缘时点击会精确停在边缘而不会滚动过头;已经位于边缘时点击不再触发滚动 ([#6749](https://github.com/heroui-inc/heroui/pull/6749))。
* **Badge**:将背景裁剪到 padding box,使其不再溢出 `1px` 边框,从而消除 Firefox 中圆角处出现的细微颜色边缘 ([#6768](https://github.com/heroui-inc/heroui/pull/6768))。
* **Link**:在 link 根元素上暴露 `data-slot="link"` ([#6754](https://github.com/heroui-inc/heroui/pull/6754))。
* **Exports**:调整 `./styles` 的导出条件顺序,将 `style` 置于 `default` 之前,使 `style` 条件可被正确命中 ([#6754](https://github.com/heroui-inc/heroui/pull/6754))。
## 测试
`@heroui/react` 现已包含基于共享 `@heroui/testing` 测试工具的行为测试套件——提供 Vitest 配置、初始化设置以及 `render`、`setupUser`、`ssrSmoke`、定时器和滚动锁定等辅助函数。测试套件位于 `packages/react/tests/components/`,并拆分为两个 Vitest project:`react-jsdom` 负责行为测试与客户端 SSR 冒烟测试,`react-browser` 负责 Playwright 检查。CI 中的 QA 任务会运行两者,覆盖率下限仅对 jsdom 生效。
* **行为测试**:新增测试工具包、各组件测试套件、双 Vitest project 以及 QA 任务 ([#6754](https://github.com/heroui-inc/heroui/pull/6754))。
## 依赖
* **React Aria**:升级到 [React Aria 1.20.0](https://react-aria.adobe.com/releases/v1-20-0)——`react-aria-components@1.20.0`、`react-aria@3.51.0`、`@react-types/shared@3.36.1` 以及 `@internationalized/date@3.12.3` ([#6752](https://github.com/heroui-inc/heroui/pull/6752))。
* **tailwind-variants**:将 `@heroui/react` 和 `@heroui/styles` 升级到 `tailwind-variants@3.3.1` ([#6760](https://github.com/heroui-inc/heroui/pull/6760))。
## 链接
* [组件文档](/docs/react/components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #6758](https://github.com/heroui-inc/heroui/pull/6758)
## 贡献者
感谢所有为本次发布做出贡献的人!
# v3.2.5
**Category**: react
**URL**: https://heroui.com/cn/docs/react/releases/v3-2-5
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/releases/v3-2-5.mdx
> 补丁版本:Toast 支持堆叠并在悬停时展开,新增 Select.ClearButton 与 Tabs align 变体,从 @heroui/react 再导出 Pressable、Focusable、OverlayTriggerStateContext 与 DisclosureStateContext,并将 React Aria 升级到 1.21.0;同时修复嵌套 data-theme token、Shadow DOM 主题、原生 :focus-visible 焦点环、浮层层级,以及 ScrollShadow、Table、Drawer、NumberField、Accordion、Label 与 Tag 的问题。
2026 年 9 月 8 日
补丁版本:[Toast](/docs/components/toast) 支持堆叠并在悬停时展开,[Select](/docs/components/select) 新增 `ClearButton`,[Tabs](/docs/components/tabs) 新增 `align` 变体,`@heroui/react` 再导出 `Pressable`、`Focusable`、`OverlayTriggerStateContext` 与 `DisclosureStateContext`,React Aria 升级到 `1.21.0`(`react-aria@3.52.0`)。同时修复了嵌套 `data-theme` 作用域与 Shadow DOM 中的主题 token、导出变体上的原生 `:focus-visible` 焦点环、Modal 级浮层被关闭中的 Popover 遮挡等问题,以及 [ScrollShadow](/docs/components/scroll-shadow)、[Table](/docs/components/table)、[Drawer](/docs/components/drawer)、[NumberField](/docs/components/number-field)、[Accordion](/docs/components/accordion)、[Label](/docs/components/label) 与 [Tag](/docs/components/tag) 的若干问题。
## 安装
升级到最新版本:
```bash
npm i @heroui/styles@latest @heroui/react@latest
```
```bash
pnpm add @heroui/styles@latest @heroui/react@latest
```
```bash
yarn add @heroui/styles@latest @heroui/react@latest
```
```bash
bun add @heroui/styles@latest @heroui/react@latest
```
**对等依赖已变更。** 本次发布要求 `react-aria-components@^1.21.0` 与 `react-aria@^3.52.0`。若你锁定了这两个包的版本,请在同一次安装中一并升级,否则包管理器会报对等依赖冲突。
**正在使用 AI 助手?** 对它说「Hey Cursor,把 HeroUI 升级到最新版本」。它会自动对比版本并应用必要变更。了解更多请参阅 [HeroUI MCP 服务器](/docs/ui-for-agents/mcp-server)。
## 新功能
### Toast
[Toast](/docs/components/toast) 现在会折叠成堆叠布局:最新的 Toast 以完整尺寸显示在最前,较旧的会缩小并按间距错开。悬停或聚焦堆叠时会展开所有可见 Toast;离开后再次折叠。自动关闭计时器在堆叠被悬停或聚焦时暂停,页面处于后台标签页时也会暂停。
* **堆叠**:将较旧的 Toast 折叠到最前方 Toast 之后,支持悬停/聚焦展开、`isExpanded` 强制展开、`toast.update()` 原地更新内容、`exitDuration` 控制退场动画,以及 `Alt+T` / `Escape` / `F6` 键盘操作 ([#6773](https://github.com/heroui-inc/heroui/pull/6773))。
### Select
[Select](/docs/components/select) 新增清除交互,且不会在 `Select.Trigger` 内嵌套按钮。将 `Select.ClearButton` 与 Value、Indicator 一起组合,并通过根组件的 `onClear` 监听清除。该控件渲染为仅指针可用的 `span`(`aria-hidden`);键盘与读屏用户在组合了清除按钮且弹层关闭时,可用 `Backspace` 或 `Delete` 清除。
* **清除按钮**:新增 `Select.ClearButton` 与根组件 `onClear`,无需非法嵌套按钮即可清除选中项 ([#6796](https://github.com/heroui-inc/heroui/pull/6796))。
### Tabs
[Tabs](/docs/components/tabs) 可通过 `align="start" | "center" | "end"` 为整组标签设置对齐。默认仍为 `center`,现有 Tabs 外观不变。对齐使用逻辑属性(`text-start` / `justify-start`)以正确支持 RTL,并限定在标签列表上,使嵌套 Tabs 保持各自的对齐。
* **对齐**:在 `Tabs` 上设置 `align`,无需在每个标签上重复 `className` 即可控制文本与内容对齐 ([#6813](https://github.com/heroui-inc/heroui/pull/6813))。
### 导出
基于 `@heroui/react` 的库可以从 HeroUI 导入 RAC 原语,而不必直接从 `react-aria-components` 导入。这样在 Vite 下会共用同一份实例,避免 Context 分裂以及 SSR 与客户端不一致。
* **RAC 原语**:从 `@heroui/react` 再导出 `Pressable`、`Focusable`、`OverlayTriggerStateContext` 与 `DisclosureStateContext` ([#6828](https://github.com/heroui-inc/heroui/pull/6828))。
## 错误修复
* **主题**:在 Shadow DOM 中通过 `:root, :host` 声明主题 token,使样式表被 adopt 进 shadow tree 后仍能应用圆角、颜色与深色模式 ([#6841](https://github.com/heroui-inc/heroui/pull/6841))。
* **Toast**:`toast.update` 会保留未传入的 `timeout` 与 `onClose`,`reset` 会重启正在进行的倒计时,区域快捷键需精确匹配修饰键,去掉未使用的 `viewTransitionName`,并在 Toast 宽度变化时重新测量堆叠高度 ([#6829](https://github.com/heroui-inc/heroui/pull/6829)、[#6830](https://github.com/heroui-inc/heroui/pull/6830)、[#6831](https://github.com/heroui-inc/heroui/pull/6831)、[#6834](https://github.com/heroui-inc/heroui/pull/6834)、[#6832](https://github.com/heroui-inc/heroui/pull/6832))。
* **Accordion**:默认触发器悬停背景需同时满足 `:hover` 与 `data-hovered`,自定义 `hover:bg-*` 在鼠标离开时不再闪一下默认颜色 ([#6817](https://github.com/heroui-inc/heroui/pull/6817))。
* **主题**:补全嵌套 `data-theme` 作用域中缺失的 token(`--surface-*-foreground`、`--field-placeholder`),并将浮层阴影改为 `--overlay-shadow`,使局部深色/浅色区域能级联到组件 ([#6803](https://github.com/heroui-inc/heroui/pull/6803))。
* **焦点**:将无法匹配的 `:focus-visible:not(:focus)` 替换为原生 `:focus-visible`,使使用 HeroUI 变体的原生锚点与按钮也能显示键盘焦点环,同时 React Aria 仍使用 `[data-focus-visible="true"]` ([#6805](https://github.com/heroui-inc/heroui/pull/6805))。
* **Label**:在 `Checkbox.Content`、`Switch.Content` 与 `Radio.Content` 内将 `Label` 渲染为 `span`,避免嵌套 `` 或复用分组标签的 `id` ([#6807](https://github.com/heroui-inc/heroui/pull/6807))。
* **浮层**:将 `Modal`、`AlertDialog` 与 `Drawer` 提升到共享的 overlay z-index,并在 Popover 级浮层退出动画期间禁用指针事件,避免关闭中的 `Dropdown` / `Select` / `Popover` 盖住或拦截新打开 Modal 的点击 ([#6798](https://github.com/heroui-inc/heroui/pull/6798))。
* **Tag**:将移除按钮的可点击区域扩大到 24×24,同时保持 12×12 图标,使多选 `Autocomplete` 芯片上的点击更可靠 ([#6797](https://github.com/heroui-inc/heroui/pull/6797))。
* **ScrollShadow**:在支持的浏览器中通过 CSS 滚动时间线驱动淡出,使首屏绘制即正确、无需 hydration 后测量,从而避免闪烁;不支持的引擎与受控模式仍使用属性驱动,并合并消费者 `style` 以保留 `--scroll-shadow-size` / `--scroll-shadow-offset` ([#6800](https://github.com/heroui-inc/heroui/pull/6800))。
* **ScrollShadow**:在内容尺寸变化后重新测量溢出,使 `data-*-scroll` 保持同步(包括 [Tabs](/docs/components/tabs) 箭头),并且 `onVisibilityChange` 只在真实状态变化时触发,而不是每次渲染 ([#6812](https://github.com/heroui-inc/heroui/pull/6812))。
* **ScrollShadow**:通过观察内容变更来测量溢出,而不是在每次渲染时测量 ([#6833](https://github.com/heroui-inc/heroui/pull/6833))。
* **Calendar / RangeCalendar**:对默认的 `minValue` 与 `maxValue` 做 memoize,避免日历状态在每次渲染时失效 ([#6812](https://github.com/heroui-inc/heroui/pull/6812))。
* **Button、Menu 与 Dropdown**:将 `will-change` 合成器提示限制在按下和进出场动画状态,使静态文本在带有 transform 的浮层中保持清晰,包括 `Modal` 关闭后重新打开的场景 ([#6779](https://github.com/heroui-inc/heroui/pull/6779))。
* **Drawer**:将拖拽手势限制在最近的所属 `Drawer.Dialog`,使嵌套抽屉的把手只关闭自身抽屉,而父抽屉保持打开且不发生位移 ([#6780](https://github.com/heroui-inc/heroui/pull/6780))。
* **Table**:防止 typeahead 抢走嵌套可编辑控件的按键输入与焦点。`keyboardNavigationBehavior` 现已作为 prop 暴露,并默认设为 `"tab"`,同时保留非可编辑单元格中的 typeahead ([#6781](https://github.com/heroui-inc/heroui/pull/6781))。
* **NumberField**:根据实际存在的步进槽位调整输入网格,没有递增或递减按钮时不再预留空白侧栏 ([#6778](https://github.com/heroui-inc/heroui/pull/6778))。
* **Toast**:将自定义 `style` 与区域 CSS 变量及 Toast 堆叠样式合并,避免传入如 `zIndex` 等样式时丢失 `--toast-width` 导致 Toast 宽度塌缩 ([#6794](https://github.com/heroui-inc/heroui/pull/6794))。
## 依赖
* **React Aria**:升级到 [React Aria 1.21.0](https://react-aria.adobe.com/releases/v1-21-0)——`react-aria-components@1.21.0`、`react-aria@3.52.0` 以及 `@internationalized/date@3.12.4` ([#6819](https://github.com/heroui-inc/heroui/pull/6819))。
## 链接
* [组件文档](/docs/react/components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui)
* [GitHub PR #6792](https://github.com/heroui-inc/heroui/pull/6792)
## 贡献者
感谢所有为本次发布做出贡献的人!
# 介绍
**Category**: native
**URL**: https://heroui.com/cn/docs/native/getting-started
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/getting-started/index.mdx
> 开源 React Native UI 组件库,用于构建美观且易于访问的移动界面。
HeroUI Native 是基于 [Tailwind v4](https://tailwindcss.com/blog/tailwindcss-v4) 与 [Uniwind](https://uniwind.dev/) 的 React Native 组件库,并面向现代移动端技术栈。每个组件都带有流畅动画、精致细节与内置无障碍支持——开箱即用,亦可深度定制。
## 为什么选择 HeroUI Native?
**默认即美观** — 专业观感开箱即有,无需额外堆样式。
**无障碍优先** — 遵循移动端无障碍最佳实践,内置合理的焦点管理、触控可达性与读屏支持。
**高度可组合** — 每个组件由可替换的子部件构成;按需改动,其余保持不变。
**开发者友好** — 类型完备的 API、可预期的模式与出色的自动补全。
**持续维护** — 由团队负责更新、修复与新特性;你只需升级依赖。
**轻量按需** — 支持 Tree-shaking,仅打包实际使用的部分。
**面向未来** — 兼容最新 [Expo](https://expo.dev/),并通过 [Uniwind](https://uniwind.dev/) 建立在 [Tailwind v4](https://tailwindcss.com/blog/tailwindcss-v4) 之上,同时便于 AI 辅助开发。
## 一个精心打造的组件库,而非复制粘贴
复制粘贴的代码在依赖停滞时会变成维护负担。
HeroUI Native 则不同,它是与你共同演进的组件库:
* 自动更新和修复
* 无需额外工作即可获得新功能
* 组件与 React Native、Tailwind 与移动平台保持同步
* 深度定制,而非浅层主题调整
* 面向代码生成的 AI 友好 API
## HeroUI 生态
* **🌐 HeroUI v3(Web)** — 基于 Tailwind CSS v4 的 React 组件
* **📱 HeroUI Native(移动端)** — 面向 React Native 的美观组件
* **🤖 [HeroUI Chat](https://heroui.chat?ref=heroui-v3)**(自然语言生成应用)— 用对话创建应用
* **🧠 面向 LLM 的 UI** — 全新平台与 MCP 即将推出
## 常见问题
**HeroUI Native 是否免费?**\
是的,基于 Apache License 2.0 完全免费且开源。
**是否可用于生产?**\
可以。HeroUI v3 已经稳定,可放心用于生产环境。
**能否自定义组件?**\
可以。可更新默认样式与动画,或重新组合子部件;每个插槽都可定制。
**是否支持 TypeScript?**\
完整类型定义,IDE 体验与自动补全良好。
**无障碍方面如何?**\
遵循移动端无障碍最佳实践,内置焦点管理、触控可达性与读屏支持。
**是否有 Figma 资源?**\
有!欢迎访问我们的设计系统:[HeroUI Figma Kit V3](https://www.figma.com/community/file/1546526812159103429)。
## 参与其中
加入社区、分享反馈或参与贡献:
* [GitHub Discussions](https://github.com/heroui-inc/heroui-native/discussions)
* [Discord](https://discord.gg/9b6yyZKmH4)
* [X/Twitter](https://x.com/hero_ui)
* [贡献指南](https://github.com/heroui-inc/heroui-native/blob/main/CONTRIBUTING.md)
HeroUI Native 采用 [Apache License 2.0](https://github.com/heroui-inc/heroui-native/blob/main/LICENSE) 发布。
# Beta 10
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/beta-10
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/beta-10.mdx
> Bottom Sheet 组件、PressableFeedback 重构、动画 API 的 State 扩展、use-theme-color 多色选取与问题修复
2025 年 12 月 30 日
本版本新增 [Bottom Sheet](/docs/native/components/bottom-sheet) 组件;重构 [PressableFeedback](/docs/native/components/pressable-feedback) 并改进 API;为动画 API 增加 State Prop 支持;增强 `use-theme-color` 以支持一次选取多色;并包含若干问题修复与文档改进。
## 安装
升级到最新版本:
```bash
npm i heroui-native@beta
```
```bash
pnpm add heroui-native@beta
```
```bash
yarn add heroui-native@beta
```
```bash
bun add heroui-native@beta
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 更新亮点
### 新组件
#### Bottom Sheet
本版本新增 **Bottom Sheet** 组件:自屏幕底部滑入的通用遮罩层,带动画过渡与下滑关闭手势。
**特性:**
* 平滑动画过渡与手势支持
* 多档吸附高度,布局更灵活
* Detached 模式,支持自定义定位
* 可自定义遮罩与模糊效果
* 完整无障碍支持
* 基于 [@gorhom/bottom-sheet](https://gorhom.dev/react-native-bottom-sheet)
**用法:**
```tsx
import { BottomSheet, Button } from 'heroui-native';
Open Bottom Sheet
Title
Description
```
完整文档与示例见 [Bottom Sheet 组件页](/docs/native/components/bottom-sheet)。
**相关 PR:** [#174](https://github.com/heroui-inc/heroui-native/pull/174)
## 组件改进
### PressableFeedback 重构
[PressableFeedback](/docs/native/components/pressable-feedback) 已重构,API 更清晰,动画控制更好。
**改进:**
* 动画配置 API 增强
* 更好支持自定义动画状态
* 性能与流畅度提升
* 反馈定位选项更灵活
在提供更多按压反馈动画控制能力的同时,保持向后兼容。
**相关 PR:** [#182](https://github.com/heroui-inc/heroui-native/pull/182)
## API 增强
### 动画 API:State 属性扩展
动画 API 新增 `state` 属性,可在自定义属性的同时关闭动画,实现更细粒度的行为控制。
**新能力:**
```tsx
```
`state` 可取:
* `'disabled'`:关闭动画,仍允许自定义属性
* `'disable-all'`:关闭所有动画(含子级)
* `boolean`:简单开关
便于在不启用动画的情况下微调动画相关属性,利于精细调整组件行为。
**相关 PR:** [#176](https://github.com/heroui-inc/heroui-native/pull/176)
### use-theme-color 多色选取
`use-theme-color` 已重构,支持一次选取多种颜色,主题定制更灵活。
**增强:**
* 支持同时选取多种颜色
* 颜色选取逻辑改进
* 多色场景下性能更好
便于在需要多色协同应用的主题场景中组合使用。
**相关 PR:** [#170](https://github.com/heroui-inc/heroui-native/pull/170)
## 文档
### 动画样式指南注释
为动画样式指南补充注释与说明,便于开发者理解与正确使用动画能力。
**改进:**
* 示例代码附详细注释
* 动画模式说明更清晰
* 不同动画方案的选用指引更明确
**相关 PR:** [#179](https://github.com/heroui-inc/heroui-native/pull/179)
## 问题修复
本版本包含以下修复:
* **[Issue #173](https://github.com/heroui-inc/heroui-native/issues/173)**:修复 `classNames={{ container: "bg-x" }}` 无法为 TextField.Input 容器设置 `backgroundColor` 的问题。
* **[Issue #177](https://github.com/heroui-inc/heroui-native/issues/177)**:修复按钮缩放动画有时停留在 0.9 倍、松手后无法回弹的问题。
* **[Issue #178](https://github.com/heroui-inc/heroui-native/issues/178)**:修复影响组件功能的问题。
## 文档更新
以下文档页面已随本版本更新:
* [动画指南](/docs/native/getting-started/animation) — 补充动画 API State 属性说明
* [颜色指南](/docs/native/getting-started/colors) — 补充 use-theme-color 多色选取说明
* [PressableFeedback 组件](/docs/native/components/pressable-feedback) — 更新重构后的 API 文档
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# Beta 11
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/beta-11
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/beta-11.mdx
> Bottom Sheet 关闭协同增强、Dialog 侧滑关闭修复、TextField 改进,以及面向高级场景的 PortalHost 导出
2026 年 1 月 6 日
Beta 11 聚焦多块核心能力的可靠性与开发者体验:增强 Bottom Sheet 在各关闭路径下的一致性;修复 Dialog 侧滑关闭手势;解决 TextField 样式与行为问题;并新增 `PortalHost` 导出以支持高级 Portal 挂载。交互更顺滑,对组件行为的控制也更充分。
## 安装
升级到最新版本:
```bash
npm i heroui-native@beta
```
```bash
pnpm add heroui-native@beta
```
```bash
yarn add heroui-native@beta
```
```bash
bun add heroui-native@beta
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 抢先体验
通过预览应用在真机上体验 Beta 11 的改进!你可以查看增强后的 Bottom Sheet、Dialog、TextField 与 PortalHost 相关能力。
### 环境要求
请确保手机已安装最新版本的 [Expo Go](https://expo.dev/go)。
### 如何访问
**方式一:扫描二维码**
使用手机相机或 Expo Go 应用扫描:
> **Android 用户请注意:** 若使用系统相机或其他扫码应用会跳转到浏览器并出现 404,请先打开 Expo Go,使用其内置扫码功能扫描。
**方式二:点击链接**
**[📱 在 Expo Go 中打开演示应用](https://link.heroui.com/native-demo)**
若设备已安装 Expo Go,将自动在其中打开应用。
## 组件改进
### Bottom Sheet 关闭协同增强
[Bottom Sheet](/docs/native/components/bottom-sheet) 已增强各类关闭路径之间的协同。
**改进:**
* 下滑关闭、点击遮罩、关闭按钮与程序化关闭之间的同步更好
* 关闭过程中的状态管理改进,减少竞态
* 各关闭场景下 `onOpenChange` 触发更可靠
* 动画进度与关闭态切换的衔接更顺畅
Bottom Sheet 支持下滑、点遮罩、点关闭按钮或代码关闭。此前这些路径偶发冲突或表现不一致;本更新使各路径协调一致,体验更可预期。
**相关 PR:** [#201](https://github.com/heroui-inc/heroui-native/pull/201)
### Dialog 侧滑关闭手势修复
[Dialog](/docs/native/components/dialog) 已修复侧滑关闭手势的处理。
**改进:**
* 侧滑关闭的手势检测与处理修复
* 滑动过程中手势状态管理改进
* 松手时与动画的衔接增强
* 超过阈值后侧滑关闭更可靠
Dialog 支持下滑关闭。本修复解决滑动过程中手势偶发无响应或行为异常的问题。
**相关 PR:** [#193](https://github.com/heroui-inc/heroui-native/pull/193)
### TextField 样式与行为修复
[TextField](/docs/native/components/text-field) 的样式与行为问题已修复。
**改进:**
* 输入框样式不一致问题修复
* 动画状态管理问题修复
* 聚焦/失焦处理改进
* 错误态视觉反馈增强
* 占位符与选中颜色应用修复
确保 TextField 在聚焦、失焦、非法等状态下显示正确,并向用户提供一致的视觉反馈。
**相关 PR:** [#202](https://github.com/heroui-inc/heroui-native/pull/202)
## API 增强
### PortalHost 导出(高级场景)
`PortalHost` 现从主 Provider 模块导出,支持高级 Portal 宿主挂载。
**新能力:**
```tsx
import { HeroUINativeProvider, PortalHost } from "heroui-native";
export function CustomLayout() {
return (
<>
{/* 应用内容 */}
{/* 在自定义位置手动挂载 PortalHost */}
>
);
}
```
便于在自定义布局中手动挂载 Portal 宿主,例如需在 BottomSheet、Modal 或其他遮罩内指定渲染位置时。默认 `HeroUINativeProvider` 已包含标准场景的 `PortalHost`;现可额外创建具名宿主以支持多宿主架构。
**适用场景:**
* 在 Bottom Sheet 内挂载 Portal
* 在 Modal 中创建 Portal 宿主
* 自定义遮罩渲染
* 多宿主 Portal 架构
**相关 PR:** [#185](https://github.com/heroui-inc/heroui-native/pull/185)
## 问题修复
本版本包含以下修复:
* **[Issue #187](https://github.com/heroui-inc/heroui-native/issues/187)**:修复通过滑动手势关闭后,需多次点击才能再次打开 Bottom Sheet 或 Dialog 的问题。内部状态现与关闭动画正确同步,无论以何种方式关闭均可立即再次打开。
* **[Issue #189](https://github.com/heroui-inc/heroui-native/issues/189)**:修复含文本输入的 Dialog 在侧滑关闭时应用卡死的问题。
* **[Issue #196](https://github.com/heroui-inc/heroui-native/issues/196)**:修复 TextField 多行输入行为,与 React Native `TextInput` 多行语义一致。
* **[Issue #199](https://github.com/heroui-inc/heroui-native/issues/199)**:修复 TextField Input 内占位符文字位置问题。
**相关 PR:**
* [#201](https://github.com/heroui-inc/heroui-native/pull/201)
* [#202](https://github.com/heroui-inc/heroui-native/pull/202)
* [#193](https://github.com/heroui-inc/heroui-native/pull/193)
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# Beta 12
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/beta-12
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/beta-12.mdx
> InputOTP、Label、Description 组件,Popover 关闭修复,受控状态改进,圆角修复,以及变体样式属性支持
2026 年 1 月 13 日
Beta 12 新增三个核心表单组件——InputOTP、Label、Description——强化 React Native 中的表单搭建能力。另含 Popover 关闭行为、弹层受控状态、圆角配置等关键修复,并为多个表单组件增加变体样式属性支持,使表单组件更稳健、样式与行为更易控。
## 安装
升级到最新版本:
```bash
npm i heroui-native@beta
```
```bash
pnpm add heroui-native@beta
```
```bash
yarn add heroui-native@beta
```
```bash
bun add heroui-native@beta
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 抢先体验
通过预览应用在真机上体验 Beta 12!你可以探索 InputOTP、Label、Description,以及 Popover 修复、受控状态改进、圆角修复与变体样式属性支持。
### 环境要求
请确保手机已安装最新版本的 [Expo Go](https://expo.dev/go)。
### 如何访问
**方式一:扫描二维码**
使用手机相机或 Expo Go 应用扫描:
> **Android 用户请注意:** 若使用系统相机或其他扫码应用会跳转到浏览器并出现 404,请先打开 Expo Go,使用其内置扫码功能扫描。
**方式二:点击链接**
**[📱 在 Expo Go 中打开演示应用](https://link.heroui.com/native-demo)**
若设备已安装 Expo Go,将自动在其中打开应用。
## 更新亮点
### 新组件
本版本新增 **3** 个核心表单组件:
* **[InputOTP](/docs/native/components/input-otp)**:一次性密码输入,独立字符格、动画与校验支持。
* **[Label](/docs/native/components/label)**:表单与界面元素标签文本,支持必填标记与校验态。
* **[Description](/docs/native/components/description)**:无障碍说明与辅助文案,用于表单等场景。
#### InputOTP
InputOTP 为双因素认证、验证码、PIN 等场景提供完整方案:独立字符格与流畅动画、可自定义分组与分隔符、全面校验支持。
**特性:**
* 独立字符格、流畅动画与光标指示
* 灵活分组与分隔符
* 基于模式的输入限制(数字、字符或自定义正则)
* 受控/非受控值管理
* 校验态与视觉反馈
* 每位占位符可配置
* 粘贴支持与转换函数
* 完整无障碍支持
**用法:**
```tsx
import { InputOTP, Label, Description } from "heroui-native";
export function Example() {
return (
<>
Verify account
console.log(code)}>
We've sent a code to your email
>
);
}
```
完整文档与示例见 [InputOTP 组件页](/docs/native/components/input-otp)。
**相关 PR:** [#214](https://github.com/heroui-inc/heroui-native/pull/214)
#### Label
Label 为表单字段提供无障碍标签,内置必填星号、校验态与禁用态,并随字段校验状态自适应样式。
**特性:**
* 必填字段自动显示星号
* 非法态样式
* 禁用态支持
* 复合结构便于自定义布局
* 通过 nativeID 关联的完整无障碍支持
* 支持 `className`、`classNames`、`styles` 定制样式
**用法:**
```tsx
import { Label, TextField } from "heroui-native";
export function Example() {
return (
Password
);
}
```
完整文档与示例见 [Label 组件页](/docs/native/components/label)。
**相关 PR:** [#214](https://github.com/heroui-inc/heroui-native/pull/214)
#### Description
Description 为表单字段提供无障碍辅助说明,默认弱化样式,并可通过 nativeID 与字段关联以支持读屏。
**特性:**
* 适合辅助文案的弱化文本样式
* 通过 nativeID 与 `aria-describedby` 关联无障碍
* 与表单组件无缝集成
* 支持自定义样式
**用法:**
```tsx
import { Description, TextField } from "heroui-native";
export function Example() {
return (
Email address
We'll never share your email with anyone else.
);
}
```
完整文档与示例见 [Description 组件页](/docs/native/components/description)。
**相关 PR:** [#214](https://github.com/heroui-inc/heroui-native/pull/214)
## 组件改进
### Popover 通过 ref 关闭修复
[Popover](/docs/native/components/popover) 已修复通过 ref 程序化关闭时的行为。
**改进:**
* 基于 ref 的关闭方法现能正确触发关闭动画
* ref 调用与组件内部状态的同步改进
* 程序化关闭更可靠
确保调用 `popoverRef.current?.close()` 时能可靠关闭并正确管理状态与动画。
**相关 PR:** [#207](https://github.com/heroui-inc/heroui-native/pull/207)
### 弹层受控状态修复
Dialog、Bottom Sheet、Popover 等弹层组件已修复通过 `isOpen` 的受控状态。
**改进:**
* 受控状态同步修复
* 外部状态变更的处理改进
* 受控模式下行为更可预期
**相关 PR:** [#215](https://github.com/heroui-inc/heroui-native/pull/215)
### Button、Chip、Tabs 圆角修复
[Button](/docs/native/components/button)、[Chip](/docs/native/components/chip)、[Tabs](/docs/native/components/tabs) 已修复对全局圆角配置的尊重。
**改进:**
* Button 全局圆角应用修复
* Chip 圆角应用修复
* Tabs 圆角应用修复
* 使用全局主题配置的组件间一致性提升
**相关 PR:** [#218](https://github.com/heroui-inc/heroui-native/pull/218)
### TextField.Input 属性精简
[TextField](/docs/native/components/text-field) 的 Input 子组件已移除 `animation` 与 `isAnimatedStyleActive`。
**变更:**
* 自 TextField.Input 移除 `animation`
* 自 TextField.Input 移除 `isAnimatedStyleActive`
* API 简化,更易维护
动画行为现由组件内部统一处理,无需手动配置动画属性。
**相关 PR:** [#220](https://github.com/heroui-inc/heroui-native/pull/220)
## API 增强
### HeroUINativeProvider 的 devInfo 配置
`HeroUINativeProvider` 现支持 `devInfo` 配置项,便于开发与调试。
**新能力:**
```tsx
import { HeroUINativeProvider } from "heroui-native";
export function App() {
return (
{/* 应用内容 */}
);
}
```
**相关 PR:** [#217](https://github.com/heroui-inc/heroui-native/pull/217)
### 变体样式属性支持
[Checkbox](/docs/native/components/checkbox)、[Radio](/docs/native/components/radio)、[TextField](/docs/native/components/text-field)、[InputOTP](/docs/native/components/input-otp) 现支持通过 `variant` 样式属性更便捷地覆盖变体样式。
**新能力:**
```tsx
import { Checkbox, Radio, TextField, InputOTP } from "heroui-native";
Option 1
Option 2
```
除组件 `variant` 属性外,也可通过 style 中的变体信息灵活调整外观。
**相关 PR:** [#220](https://github.com/heroui-inc/heroui-native/pull/220)
## 样式修复
### 圆角配置
修复全局圆角未正确应用到部分组件的问题。
**修复:**
* Button 未尊重全局圆角
* Chip 圆角应用
* Tabs 圆角应用
### 样式优化
* **圆角一致性**:Button、Chip、Tabs 的圆角应用更一致
* **主题配置**:主题传播增强,组件更一致地尊重全局设置
## 问题修复
本版本包含以下修复:
* **[Issue #93](https://github.com/heroui-inc/heroui-native/issues/93)**:修复在 Unwind 场景下 Button 未应用全局圆角的问题,现与主题全局圆角一致。
* **[Issue #213](https://github.com/heroui-inc/heroui-native/issues/213)**:修复 Select 受控模式(`isOpen`)不生效的问题;提供 `isOpen` 时可在外部可靠管理开闭。
**相关 PR:**
* [#218](https://github.com/heroui-inc/heroui-native/pull/218)
* [#215](https://github.com/heroui-inc/heroui-native/pull/215)
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# Beta 13
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/beta-13
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/beta-13.mdx
> TextArea 组件、Button outline 变体、Tabs 改进、表单原语拆分、弹层动画重构、样式类名导出与关键问题修复
2026 年 2 月 3 日
Beta 13 引入多行输入组件 TextArea、Button outline 变体,并为所有组件导出样式类名。本版本显著改进 Tabs(动画与变体命名更清晰)、将表单相关能力拆为独立原语、重构弹层动画系统以提升一致性与 Android 兼容性,并修复中文输入、主题色计算、Uniwind Pro 兼容、Bottom Sheet 打开与摇树(tree-shaking)等关键问题,整体提升开发者体验与组件可靠性。
## 安装
升级到最新版本:
```bash
npm i heroui-native@beta
```
```bash
pnpm add heroui-native@beta
```
```bash
yarn add heroui-native@beta
```
```bash
bun add heroui-native@beta
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 抢先体验
通过预览应用在真机上体验 Beta 13!你可以探索 TextArea、CloseButton、Button outline、Tabs 改进、细粒度导出与各项修复。
### 环境要求
请确保手机已安装最新版本的 [Expo Go](https://expo.dev/go)。
### 如何访问
**方式一:扫描二维码**
使用手机相机或 Expo Go 应用扫描:
> **Android 用户请注意:** 若使用系统相机或其他扫码应用会跳转到浏览器并出现 404,请先打开 Expo Go,使用其内置扫码功能扫描。
**方式二:点击链接**
**[📱 在 Expo Go 中打开演示应用](https://link.heroui.com/native-demo)**
若设备已安装 Expo Go,将自动在其中打开应用。
## 更新亮点
### 新组件
本版本新增 **3** 个重要组件:
* **[TextArea](/docs/native/components/text-area)**:多行文本输入,带样式边框与背景,适用于较长内容。
* **[Input](/docs/native/components/input)**:单行文本输入,带样式边框与背景;现作为独立于 TextField 的组件提供(此前仅 `TextField.Input`)。
* **[CloseButton](/docs/native/components/close-button)**:可复用关闭按钮,用于 Dialog、Modal 等遮罩场景,样式在各遮罩间一致。
#### TextArea
TextArea 面向评论、消息、描述与较长表单字段等多行场景;可与 TextField 组合成完整表单结构,支持校验态与多种视觉变体。
**特性:**
* 多行输入,行数可配置
* 与 TextField 无缝组合
* 校验态与视觉反馈
* primary / secondary 等变体
* 禁用与只读
* `className` 与 `styles` 定制
* 完整无障碍支持
**用法:**
```tsx
import { Description, Label, TextArea, TextField } from "heroui-native";
export function Example() {
return (
Message
Please provide as much detail as possible.
);
}
```
完整文档与示例见 [TextArea 组件页](/docs/native/components/text-area)。
**相关 PR:** [#254](https://github.com/heroui-inc/heroui-native/pull/254)
#### Input
Input 现可作为独立组件使用,提供带边框与背景的单行输入。此前仅能通过 `TextField.Input` 使用;现可单独使用,或与 TextField、ControlField 等组合。
**特性:**
* 单行输入,带样式边框与背景
* 独立使用或与表单组件组合
* 校验态与视觉反馈
* primary / secondary 变体
* 禁用与只读
* `className` 与 `styles`
* 完整无障碍支持
**用法:**
```tsx
import { Description, Input, Label, TextField } from "heroui-native";
export function Example() {
return (
Email
We'll never share your email.
);
}
```
完整文档与示例见 [Input 组件页](/docs/native/components/input)。
**相关 PR:** [#247](https://github.com/heroui-inc/heroui-native/pull/247)
#### CloseButton
CloseButton 为关闭 Dialog、Modal、Popover 等遮罩提供统一实现:跨遮罩一致样式、可配置图标属性,并与 Dialog、Popover、Select、Bottom Sheet 等集成。
**特性:**
* 各遮罩间关闭按钮样式一致
* 图标尺寸与颜色可配置
* 支持自定义子节点替换默认图标
* 禁用态
* 与 Dialog、Popover、Select、Bottom Sheet 集成
* 默认样式针对遮罩场景优化
**用法:**
```tsx
import { CloseButton } from "heroui-native";
// 独立使用
// 作为 Dialog、Popover、Select、Bottom Sheet 的一部分
```
完整文档与示例见 [CloseButton 组件页](/docs/native/components/close-button)。
**相关 PR:** [#237](https://github.com/heroui-inc/heroui-native/pull/237)
### 新子组件
#### Tabs.Separator
Tabs 新增 `Separator` 子组件,在触发器之间提供随当前选项卡变化的显隐动画,便于做视觉分隔。
**特性:**
* 随活动选项卡变化的显隐过渡
* `betweenValues` 控制显示区间
* 动画时长与不透明度可配置
* 可设为始终可见的静态分隔
**用法:**
```tsx
import { Tabs } from "heroui-native";
General
Notifications
```
**相关 PR:** [#228](https://github.com/heroui-inc/heroui-native/pull/228)
## 组件改进
### Button outline 变体
[Button](/docs/native/components/button) 新增 `outline` 变体:透明背景 + 边框,丰富按钮视觉层次。
**改进:**
* 新增 `outline` 有边框样式
* 与其他 Button 变体风格一致
* outline 的悬停与聚焦态正确
* 与既有 Button API 无缝衔接
**用法:**
```tsx
import { Button } from "heroui-native";
Outline Button
```
**相关 PR:** [#235](https://github.com/heroui-inc/heroui-native/pull/235)
### Tabs 指示条动画重构
[Tabs](/docs/native/components/tabs) 指示条动画由宽高动画改为 `translateX` 变换,过渡更顺滑、性能更好。
**改进:**
* 指示条迁移到 `translateX`
* 动画性能与流畅度提升
* 切换时视觉更一致
* 减少动画期间的布局重算
**相关 PR:** [#227](https://github.com/heroui-inc/heroui-native/pull/227)
### Popover 箭头尺寸与视觉衔接
[Popover](/docs/native/components/popover) 改进箭头尺寸及与内容的视觉衔接。
**改进:**
* 箭头尺寸相对内容更合理
* 箭头与弹层连接更自然
* 对齐与间距优化
**相关 PR:** [#243](https://github.com/heroui-inc/heroui-native/pull/243)
### 表单组件拆分为原语
表单相关能力拆为独立原语,组合更灵活、职责更清晰。
**改进:**
* 表单能力原子化
* 复用性与组合性提升
* 关注点分离更好
* 自定义表单布局更自由
**相关 PR:** [#247](https://github.com/heroui-inc/heroui-native/pull/247)
### Input Android 阴影修复
[Input](/docs/native/components/input) 为 Android 增加平台相关阴影,跨端视觉更一致。
**改进:**
* Android 平台阴影
* iOS / Android 观感对齐
* Android 上层次(elevation)观感改善
**相关 PR:** [#248](https://github.com/heroui-inc/heroui-native/pull/248)
### 弹层动画系统重构
Popover、Select、Dialog、BottomSheet 的动画系统已重构:统一进出场逻辑、遮罩组合与内容动画,标准化各弹层行为并修复 Android 指针事件问题。
**改进:**
* Dialog 等呈现统一使用 FadeInDown / FadeOutDown 等进出场
* 遮罩动画钩子同时支持基于 progress 与进出场两类动画
* 遮罩组合更多使用 Dialog.Overlay、Popover.Overlay,减少单纯 Pressable 包裹
* 修复影响弹层交互的 Android pointer events 问题
* 示例中显式写出 `presentation`(popover、dialog、bottom-sheet)
* 动画 API 简化,更易维护、跨组件更一致
**相关 PR:** [#263](https://github.com/heroui-inc/heroui-native/pull/263)
## API 增强
### 细粒度导出以优化包体
库现为各组件提供细粒度导出路径,可按需 import 以减小包体。
**新能力:**
```tsx
// 细粒度导入——仅需少量组件时推荐
import { HeroUINativeProvider } from "heroui-native/provider";
import { Button } from "heroui-native/button";
import { Card } from "heroui-native/card";
// 总入口导入——会拉取整库,适合大量使用组件时
import { Button, Card } from "heroui-native";
```
细粒度导入适合只用少数组件的场景;从 `heroui-native` 总入口导入会包含完整库,适合全站大量使用。
**可用细粒度路径:**
* `heroui-native/provider` — Provider
* `heroui-native/[component-name]` — 各组件
* `heroui-native/portal` — Portal 工具
* `heroui-native/utils` — 工具函数
* `heroui-native/hooks` — 自定义 Hooks
**重要**:为控制包体,请在整个项目中**一致地**使用细粒度导入。只要存在一处从 `heroui-native` 总入口的导入,摇树优化策略即可能失效。
**相关 PR:** [#233](https://github.com/heroui-inc/heroui-native/pull/233)
### 样式类名导出
所有组件现导出对应样式类名,便于在代码中引用类名或搭建自定义主题方案。
**新能力:**
```tsx
import { buttonClassNames } from "heroui-native";
const customStyles = {
base: buttonClassNames.base,
variant: buttonClassNames.variant,
};
```
**相关 PR:** [#252](https://github.com/heroui-inc/heroui-native/pull/252)
## 样式修复
### 样式优化
* **移除 quaternary 变体**:删除第四级变体并打磨样式以提升一致性
* **多组件样式打磨**:视觉一致性增强
* **阴影与圆角**:跨组件阴影、圆角更统一
* **主题变量整理**:简化变量并减少冗余 `color-mix` 计算
**相关 PR:** [#246](https://github.com/heroui-inc/heroui-native/pull/246)
## ⚠️ 破坏性变更
### Tabs `variant` 重命名
Tabs 的 `variant` 由 `pill` / `line` 改为 `primary` / `secondary`,与其他组件命名更一致。
**迁移:**
```tsx
// 之前
{/* content */}
{/* content */}
// 之后
{/* content */}
{/* content */}
```
**可选项:**
* `"primary"` — 原 `"pill"`
* `"secondary"` — 原 `"line"`
**相关 PR:** [#236](https://github.com/heroui-inc/heroui-native/pull/236)
### Tabs 指示条动画实现变更
[Tabs](/docs/native/components/tabs) 指示条由 `left` 定位改为 `translateX` 变换以利用 GPU。若自定义过指示条动画,需更新配置。
**迁移:**
```tsx
// 之前
{/* content */}
// 之后
{/* content */}
```
**变更摘要:**
* `TabsIndicatorAnimation` 中由 `left` 改为 `translateX`
* 指示条定位基于 `translateX` 变换
* 指示条样式增加 `left-0` 基准类以保持初始位置
* 观感应与此前一致,仅底层实现变化
**相关 PR:** [#227](https://github.com/heroui-inc/heroui-native/pull/227)
### Divider 更名为 Separator
`Divider` 已更名为 `Separator`,命名更统一,并避免与其他「分隔线」实现混淆。
**迁移:**
```tsx
// 之前
import { Divider } from "heroui-native";
// 之后
import { Separator } from "heroui-native";
```
**相关 PR:** [#238](https://github.com/heroui-inc/heroui-native/pull/238)
### 移除 quaternary 变体
[Surface](/docs/native/components/surface) 与 [Card](/docs/native/components/card) 已移除 `quaternary` 变体,简化设计系统。
**迁移:**
```tsx
// 之前
{/* content */}
{/* content */}
// 之后:使用 default、secondary、tertiary 或自定义 className
{/* content */}
{/* content */}
{/* content */}
```
**可用变体:** `"default"`、`"secondary"`、`"tertiary"`
**相关 PR:** [#246](https://github.com/heroui-inc/heroui-native/pull/246)
### 表单原语拆分与重命名
表单拆分过程中若干组件重命名、结构调整,以获得更灵活的组合方式。
**重命名:**
* `FormField` → `ControlField`
* `ErrorView` → `FieldError`
**迁移:**
```tsx
// 之前
import { FormField, ErrorView, TextField } from "heroui-native";
Error message
// 之后
import { ControlField, FieldError, Input, TextField } from "heroui-native";
Error message
```
**移除 TextField.Input:**
请改用独立 `Input`:
```tsx
// 之前
import { TextField } from "heroui-native";
// 之后
import { Input, TextField } from "heroui-native";
```
**组合方式:**
`RadioGroup`、`TextField`、`ControlField` 现直接使用 `Label`、`Description`、`FieldError`:
```tsx
import { ControlField, Description, FieldError, Input, Label, RadioGroup, TextField } from "heroui-native";
Email
We'll never share your email.
Invalid email address
Select option
Option 1
Choose one option
Please select an option
Custom Field
Additional information
Validation error
```
**相关 PR:** [#247](https://github.com/heroui-inc/heroui-native/pull/247)
### CloseButton 与移除 Close 的 asChild
新增可复用 `CloseButton`;Dialog、Popover、Select、BottomSheet 的关闭实现统一基于该组件。各 `*.Close` 已移除 `asChild`。
**迁移:**
```tsx
// 之前
import { Button, Dialog } from "heroui-native";
Cancel
// 之后:用受控 open + 自定义按钮处理关闭
import { Button, Dialog } from "heroui-native";
const [isOpen, setIsOpen] = useState(false);
setIsOpen(false)}>Cancel
```
**变更摘要:**
* 新增 `CloseButton`,默认 `variant="tertiary"`、`size="sm"`、`isIconOnly={true}`
* `Dialog.Close`、`Popover.Close`、`Select.Close`、`BottomSheet.Close` 内部基于 `CloseButton`
* 所有 Close 组件移除 `asChild`
* Close 仍支持 Button 的 `variant`、`size`、`iconProps` 与自定义 `children`
* 使用完全自定义按钮时需自行处理关闭逻辑
**相关 PR:** [#237](https://github.com/heroui-inc/heroui-native/pull/237)
### 弹层动画系统重构(API)
弹层动画重构带来若干需改代码的 API 调整。
**迁移要点:**
* 从 `Dialog.Root` 移除 `closeDelay`、`isDismissKeyboardOnClose`
* 从 `Dialog.Root` 的 `animation` 移除自定义 `entering`/`exiting`(仅保留禁用类开关);自定义进出场请在 `Dialog.Content` 上使用 Keyframe 动画配置
* 从 `Dialog.Content` 移除 `isAnimatedStyleActive`、`onLayout`
* 从 `BottomSheet.Root` 移除 `isDismissKeyboardOnClose`
* `BottomSheet.Overlay` 的 `animation` 不再支持 `entering`/`exiting`
* 所有 `Popover.Content`、`Select.Content` 必须显式传入 `presentation`(由可选改为必填)
* `useBottomSheetAnimation()` 不再返回 `bottomSheetState`;`useDialogAnimation()` 不再返回 `dialogState`
**变更摘要:**
* `Dialog.Root`:移除 `closeDelay`、`isDismissKeyboardOnClose`;`animation` 类型由支持自定义进场的 `DialogRootAnimation` 收窄为仅禁用标志的 `AnimationRootDisableAll`
* `Dialog.Content`:移除 `isAnimatedStyleActive`、`onLayout`
* `BottomSheet.Root`:移除 `isDismissKeyboardOnClose`
* `BottomSheet.Overlay`:`animation` 不再含 `entering`/`exiting`
* `Popover.Content`、`Select.Content`:`presentation` 必填(此前可选,默认 `"popover"`)
* 上述动画钩子返回值精简
**相关 PR:** [#263](https://github.com/heroui-inc/heroui-native/pull/263)
## 问题修复
本版本包含以下修复:
* **[Issue #181](https://github.com/heroui-inc/heroui-native/issues/181)**:修复 TextField 输入中文等多字节字符报错;现正确处理多字节与国际输入,含中日韩等语言。
* **[Issue #219](https://github.com/heroui-inc/heroui-native/issues/219)**:修复 Button `childrenToString()` 在多子节点时返回 `"[object Object]"`;现正确处理 React 元素与复杂子树,避免错误字符串化。
* **[Issue #232](https://github.com/heroui-inc/heroui-native/issues/232)**:修复 HeroUINativeProvider 与新版 Uniwind Pro 不兼容;现可正常配合最新 Uniwind。
* **[Issue #259](https://github.com/heroui-inc/heroui-native/issues/259)**:修复 Bottom Sheet 在快速打开并随即进行手势操作后偶发无法再次打开等问题;进出场动画逻辑重构后已缓解。
* **[Issue #261](https://github.com/heroui-inc/heroui-native/issues/261)**:修复 `@gorhom/bottom-sheet` 无法被摇树剔除的问题;未使用依赖可被更好剔除。
**其他修复:**
* 修复主题计算色在部分场景下数值错误
* 修复 `childrenToString`,避免错误地将 React 元素转为字符串
**相关 PR:**
* [#226](https://github.com/heroui-inc/heroui-native/pull/226)
* [#239](https://github.com/heroui-inc/heroui-native/pull/239)
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# CLI v1.0.0
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/cli-v1-0-0
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/cli-v1-0-0.mdx
> 全新的命令行工具,用于一键创建预先配置好的 HeroUI Native + Expo Router 项目 —— Expo SDK 56、React Native 0.85、Uniwind,所有 peer 依赖均已就绪,并提供两套起始模板(单页面与 Tabs)。
2026 年 6 月 4 日
🎉 全新的 CLI —— [`create-heroui-native-app`](https://www.npmjs.com/package/create-heroui-native-app) —— 现已成为启动 HeroUI Native 项目最快捷的方式。一条命令即可生成一个完整的 Expo Router 应用,内置 HeroUI Native、Uniwind、Tailwind CSS、所有必需的 peer 依赖以及 Provider 包装,无需再手动配置 `global.css`、`metro.config.js` 或 `app/_layout.tsx`。
## 快速开始
```bash
npx create-heroui-native-app@latest my-app
```
```bash
pnpm create heroui-native-app@latest my-app
```
```bash
yarn create heroui-native-app my-app
```
```bash
bun create heroui-native-app@latest my-app
```
随后启动开发服务器:
```bash
cd my-app
npm run start
```
到此为止。如需完整流程,请直接阅读[快速开始指南](/docs/native/getting-started/quick-start)。
## 起始模板
CLI 自带两套模板。可在交互式选择器中选择,或通过命令行参数跳过提示:
| 参数 | 模板 | 说明 |
| ------------- | ----------- | ----------------------------------------------- |
| `--expo` | `expo` | 单页面 Expo Router 应用,含 HeroUI `Button` 演示。 |
| `--expo-tabs` | `expo-tabs` | 含两个 Tabs(`Button` + `Card` 演示)的 Expo Router 布局。 |
```bash
npx create-heroui-native-app@latest my-app --expo
npx create-heroui-native-app@latest my-app --expo-tabs --use-pnpm
```
## 你将得到什么
每个生成的项目都已预先配置:
* **Expo SDK 56** + **Expo Router**,并启用类型化路由
* **React 19.2** + **React Native 0.85.2** + Hermes v1(SDK 56 默认启用)
* **HeroUI Native**:在 `app/_layout.tsx` 中由 `HeroUINativeProvider` 与 `GestureHandlerRootView` 包裹
* **Uniwind** + **Tailwind CSS**:通过 `metro.config.js` 与 `global.css` 完成接入
* 所有 HeroUI Native **必需的 peer 依赖**已锁定到兼容版本:`react-native-reanimated`、`react-native-gesture-handler`、`react-native-worklets`、`react-native-safe-area-context`、`react-native-svg`、`tailwind-variants`、`tailwind-merge`
* 内置 `react-native-screens`,让 HeroUI 的遮罩组件(`Dialog`、`Menu`、`Popover`、`Select`、`BottomSheet`、`Toast`)开箱即用
* `@expo/metro-runtime`(SDK 56 上 Expo Router 需要的 peer 依赖)
* 仅使用 `babel-preset-expo` 的 `babel.config.js`(worklets 已由该 preset 处理)
* 启用 `strict: true` 与 `@/*` 路径别名的 **TypeScript** 配置
## CLI 参考
```text
create-heroui-native-app [project-name] [options]
```
| 选项 | 说明 |
| ------------------------------------------------------- | ---------------------------------- |
| `[project-name]` | 要创建的目录名。未提供时会进行交互提示。必须是合法的 npm 包名。 |
| `--expo` | 使用单页面 Expo 模板。 |
| `--expo-tabs` | 使用 Expo + Tabs 模板。 |
| `--template ` | 指定模板 id(`expo` 或 `expo-tabs`)。 |
| `--use-npm` / `--use-yarn` / `--use-pnpm` / `--use-bun` | 强制使用指定包管理器(默认自动检测)。 |
| `--skip-install` | 跳过依赖安装步骤。 |
| `--skip-git` | 不初始化 git 仓库。 |
| `-h`, `--help` | 打印用法并退出。 |
### 示例
```bash
# 完全交互式 —— 同时提示项目名与模板
npx create-heroui-native-app@latest
# 已指定项目名,仍展示模板选择器
npx create-heroui-native-app@latest my-app
# 完全非交互式
npx create-heroui-native-app@latest my-app --expo
# 使用 Tabs 模板,并通过 pnpm 安装依赖
npx create-heroui-native-app@latest my-app --expo-tabs --use-pnpm
# 仅生成项目,不安装依赖、不初始化 git
npx create-heroui-native-app@latest my-app --expo --skip-install --skip-git
```
## 系统要求
* **Node.js 20.19.4+**(Expo SDK 56 / React Native 0.85 的要求)
* 构建原生 iOS 时需要 **iOS 16.4+**(Expo SDK 56 的部署目标)
* macOS、Linux 或 Windows
**已经有应用了?** 本 CLI 仅用于创建新项目。若要将 HeroUI Native 添加到既有的 React Native 或 Expo 应用,请参阅[快速开始中的方案 2](/docs/native/getting-started/quick-start#option-2-add-to-an-existing-project)。
## 链接
* [快速开始指南](/docs/native/getting-started/quick-start)
* [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)
# 所有版本
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/index.mdx
> HeroUI Native 的全部更新与变更,包括新功能、问题修复与破坏性变更。
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 最新版本
### v1.0.9
**2026 年 8 月**
本补丁版本重构了字重通过 Uniwind `font-*` 工具类的解析方式,使使用自定义字体的应用在 iOS 上获得正确的字重;修复了省略可选部件时 SearchField 的内边距问题;纠正了 Toast 的 `duration: 0` 未按文档自动隐藏的行为;并恢复了 react-native-gesture-handler 3 下 Android 上 Select 与 Dialog 的滑动关闭。
[阅读完整更新说明 →](/docs/native/releases/v1-0-9)
### v1.0.8
**2026 年 7 月**
本版本为整个库带来从右到左(RTL)布局支持:组件样式迁移到 Yoga 逻辑属性,Slider、Skeleton、Switch、Tabs、InputGroup、Popover 与 Menu 中对方向敏感的行为通过全新的 `isRTL` provider 配置解析,并提供 `LayoutDirectionScope` 作为子树的应急出口。同时让 `heroui-native/styles` 自行声明 `@source`,因此类名扫描不再依赖硬编码的 `node_modules` 路径。Card.Header 与 TagGroup.List 改变了子元素的对齐方式,两者均可用一行覆盖恢复。
[阅读完整更新说明 →](/docs/native/releases/v1-0-8)
### v1.0.7
**2026 年 7 月**
本版本通过 `background` 属性以及配套的背景复合部件,使组件表面可扩展,从而可将表面后方的层替换为任意节点。同时新增 `GlassView` 层组件,以及用于 Dialog 与 Bottom Sheet 的 `blur` 遮罩变体,两者均由可选的 `expo-blur` 依赖支撑。Select 触发器被重新设计为字段外观,Toast 迁移至 overlay 主题令牌;默认主题不注册任何背景内容,因此渲染结果整体不变。
[阅读完整更新说明 →](/docs/native/releases/v1-0-7)
### v1.0.6
**2026 年 7 月**
本版本将每个组件的样式从内联 Tailwind 类名字符串迁移到专用的 BEM 命名 CSS 文件,并让 `tv()` 插槽仅作为轻量引用,从而更易于覆盖与维护。同时修复了一个 PortalHost 协调缺陷:Bottom Sheet、Dialog、Popover 与 Select 各类 Portal 在不同屏幕间会相互继承状态,产生「幽灵」状态的已打开 Sheet。
[阅读完整更新说明 →](/docs/native/releases/v1-0-6)
### v1.0.5
**2026 年 7 月**
本版本将工具链升级至 Expo 57 / React Native 0.86,并在各表单组件中以基于 outline 的聚焦、激活与无效状态优化字段边框样式。同时为 Typography 新增 iOS Dynamic Type 支持,引入 Provider 级的文本输入配置,并以更轻量、单次挂载的进入动画改进 Popover、Menu 与 Select。
[阅读完整更新说明 →](/docs/native/releases/v1-0-5)
### CLI v1.0.0
**2026 年 6 月**
🎉 全新的 CLI,用于一键创建 HeroUI Native 项目。`npx create-heroui-native-app@latest my-app` 即可生成一个完整的 Expo Router 应用,内置 HeroUI Native、Uniwind、Tailwind CSS、所有必需的 peer 依赖以及 Provider 包装 —— 还可在单页面与 Tabs 两套起始模板中任选其一。
[阅读完整更新说明 →](/docs/native/releases/create-heroui-native-app)
### v1.0.4
**2026 年 5 月**
本补丁版本将 `Text` 排版组件重命名为 `Typography`(保留 `Text` 的弃用导出以兼容旧代码),调整 `Alert`、`Avatar`、`Button`、`Chip`、`Toast` 等组件的 soft 前景色主题令牌,并新增可选的 `heroui-native/styles/vibrant` 鲜亮配色;为 `Menu`、`Popover`、`Select` 补充 iOS 原生模态偏移的处理说明;将示例应用升级至 Expo 56 / React Native 0.85,并将 `@gorhom/bottom-sheet` 对等依赖升至 `^5.2.9`。
[阅读完整更新说明 →](/docs/native/releases/v1-0-4)
### v1.0.3
**2026 年 5 月**
本补丁版本引入全新的 `Text` 排版组件,提供 `Heading`、`Paragraph`、`Code` 子组件;修复 `ScrollShadow` 对反向列表的支持以及 `Tabs` 指示器在 RTL 布局下的对齐;并在使用自定义 children 时统一 `Select.TriggerIndicator` 的动画。同时将 `Avatar` 的 `alt` 属性改为可选,微调 `Button`、`Chip`、`Input` 的样式,并修正 `TextField` 与 `SearchField` 的内部内边距行为。
[阅读完整更新说明 →](/docs/native/releases/v1-0-3)
### v1.0.2
**2026 年 4 月**
本补丁版本为 PressableFeedback 与 Surface 引入 `asChild` 插槽模式;为所有基于 Portal 的遮罩增加 VoiceOver 模态包容支持;修复 Android 上 Button outline 变体的样式问题;并微调 Input 与 Select 的视觉效果。
[阅读完整更新说明 →](/docs/native/releases/v1-0-2)
### v1.0.1
**2026 年 4 月**
本补丁版本修复 Toast 提供程序中 `total` SharedValue 与实际 Toast 数量不同步的竞态;将七个组件的禁用态样式改为使用原生 `disabled:` 修饰符;并为主题系统新增供遮罩组件使用的 `--backdrop` 变量。
[阅读完整更新说明 →](/docs/native/releases/v1-0-1)
### v1.0.0
**2026 年 3 月**
🎉 HeroUI Native 迎来首个稳定版本,从 beta 与候选发布阶段毕业。本里程碑包含全新 LinkButton 组件、子菜单冲突处理、可选的 `@gorhom/bottom-sheet` 对等依赖,以及更强的 `useThemeColor` 类型安全。
[阅读完整更新说明 →](/docs/native/releases/v1-0-0)
### RC 4
**2026 年 3 月**
本版本引入用于嵌套可展开菜单的 SubMenu 复合组件(带动画展开/收起);以基于插槽的样式与 `textProps` 透传重构 Slider Output;并修复快速连按时 PressableFeedback 水波纹动画闪烁。
[阅读完整更新说明 →](/docs/native/releases/rc-4)
### RC 3
**2026 年 2 月**
本版本新增 TagGroup、Menu、InputGroup 三个组件;为所有基于 Bottom Sheet 的遮罩增加 Android 实体返回键支持;并通过关键的 `combineStyles` 修复保留 Reanimated 动画样式绑定,实现 Expo 55 兼容。
[阅读完整更新说明 →](/docs/native/releases/rc-3)
### RC 2
**2026 年 2 月**
本版本新增 SearchField、ListGroup、Slider 三个组件;为 Select 增加由类型安全泛型支撑的多选模式;将 Button 反馈 API 重构为统一的 `feedbackVariant` + `animation`。放宽对等依赖约束以更好兼容 Expo SDK 55,并修复若干 Select 与 Avatar 问题。
[阅读完整更新说明 →](/docs/native/releases/rc-2)
### RC 1
**2026 年 2 月**
本版本引入含五种状态变体与无障碍原语的 Alert 复合组件;将 Radio 抽为可双模式运行的独立组件;新增带动画的 Select.TriggerIndicator。另提供用于精简包体的 HeroUINativeProviderRaw、用于 iOS 调试的 `disableFullWindowOverlay`、六个组件统一的 `styles` 属性,以及以各主题显式定义取代计算型的 surface 主题变量重构。
[阅读完整更新说明 →](/docs/native/releases/rc-1)
### Beta 13
**2026 年 2 月**
本版本引入多行输入组件 TextArea、Button outline 变体,为所有组件导出样式类名,并提供可复用的 CloseButton。同时重构 Tabs(动画与变体命名改进)、将表单相关能力拆为独立原语,并增加细粒度导出以优化包体。另含主题色与组件字符串化等关键修复。
[阅读完整更新说明 →](/docs/native/releases/beta-13)
### Beta 12
**2026 年 1 月**
本版本新增 InputOTP、Label、Description 三个核心表单组件,强化 React Native 中的表单搭建能力。另含 Popover 关闭行为、弹层受控状态、圆角配置等关键修复,并为多个表单组件增加变体样式属性支持。
[阅读完整更新说明 →](/docs/native/releases/beta-12)
### Beta 11
**2026 年 1 月**
本版本通过 Bottom Sheet 关闭协同改进、Dialog 侧滑关闭手势修复、TextField 样式优化,以及面向高级 Portal 挂载场景的 PortalHost 导出,提升组件可靠性与开发者体验,使交互更顺滑、自定义布局更灵活。
[阅读完整更新说明 →](/docs/native/releases/beta-11)
### Beta 10
**2025 年 12 月**
本版本引入新的 [Bottom Sheet](/docs/native/components/bottom-sheet) 组件;重构 [PressableFeedback](/docs/native/components/pressable-feedback) 并改进 API;扩展动画 API 以支持 State Prop;增强 `use-theme-color` 钩子以支持多色选取;并包含若干问题修复与文档改进。
[阅读完整更新说明 →](/docs/native/releases/beta-10)
## 发布周期
HeroUI Native 遵循常规发布周期:
* **稳定版**:v1.0.0 已于 2026 年第一季度发布
* **补丁版**:按需发布问题修复与小幅改进
## 参与贡献
发现问题或想参与贡献?请访问我们的 [GitHub 仓库](https://github.com/heroui-inc/heroui-native)。
# RC 1
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/rc-1
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/rc-1.mdx
> Alert 组件、独立 Radio 组件、Select TriggerIndicator、HeroUINativeProviderRaw、disableFullWindowOverlay、styles 属性扩展、主题 surface 重构
2026 年 2 月 12 日
RC 1 是 HeroUI Native 的首个候选发布(Release Candidate),表明库已接近生产可用。本版本引入以无障碍为先、带状态变体的 Alert 复合组件;将 Radio 抽为可双模式运行的独立组件;新增带动画的 Select.TriggerIndicator 子组件。还提供轻量 `HeroUINativeProviderRaw` 以优化包体、用于 iOS 调试的 `disableFullWindowOverlay`、六个组件统一的 `styles` 插槽式样式,以及用主题显式变量替代计算型 surface 色的主题重构。另含 BottomSheet 内 InputOTP、Toast 文字裁切与元素检查器兼容等关键修复。
## 安装
升级到最新版本:
```bash
npm i heroui-native
```
```bash
pnpm add heroui-native
```
```bash
yarn add heroui-native
```
```bash
bun add heroui-native
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 抢先体验
通过预览应用在真机上体验 RC 1 的全部改进!你可以探索新的 Alert 与 Radio、Select TriggerIndicator,以及各项修复。
### 环境要求
请确保手机已安装最新版本的 [Expo Go](https://expo.dev/go)。
### 如何访问
**方式一:扫描二维码**
使用手机相机或 Expo Go 应用扫描:
> **Android 用户请注意:** 若使用系统相机或其他扫码应用会跳转到浏览器并出现 404,请先打开 Expo Go,使用其内置扫码功能扫描。
**方式二:点击链接**
**[📱 在 Expo Go 中打开演示应用](https://link.heroui.com/native-demo)**
若设备已安装 Expo Go,将自动在其中打开应用。
## 更新亮点
### 新组件
本版本新增 **1** 个组件:
* **[Alert](/docs/native/components/alert)**:无障碍告警组件,五种状态变体,复合子组件灵活组合内容。
#### Alert
Alert 提供无障碍告警展示,内置五种状态变体:default、accent、success、warning、danger。遵循复合组件模式,含 `Alert.Indicator`、`Alert.Content`、`Alert.Title`、`Alert.Description`,便于布局与定制。原语层自动提供 `role="alert"`、`aria-labelledby` 与 `aria-describedby` 关联。
**特性:**
* 五种状态变体:default、accent、success、warning、danger
* 默认 SVG 状态图标,通过 `useStatusColor` 随主题着色
* 复合架构:Indicator、Content、Title、Description
* 支持自定义指示器(如替换为 Spinner)
* 无障碍原语:`role="alert"`、`aria-labelledby`、`aria-describedby`
* 所有子组件支持 `asChild` 插槽
* 所有部件支持 ref 转发与 `className`
**用法:**
```tsx
import { Alert } from "heroui-native";
export function Example() {
return (
Payment successful
Your payment has been processed successfully.
);
}
```
完整文档与示例见 [Alert 组件页](/docs/native/components/alert)。
**相关 PR:** [#284](https://github.com/heroui-inc/heroui-native/pull/284)
### 新子组件
#### Select.TriggerIndicator
[Select](/docs/native/components/select) 新增 `TriggerIndicator` 子组件,显示带动画的 V 形图标以表示开/关状态,开闭时以 Reanimated 弹簧物理旋转。
**特性:**
* 开闭过渡时旋转的 V 形动画
* `animation` 可配置旋转值与弹簧参数
* `iconProps` 自定义尺寸、颜色
* 支持自定义子节点替换默认 V 形
* 与 Select 开闭状态自动同步
**用法:**
```tsx
import { Select } from "heroui-native";
{/* Select items */}
```
**相关 PR:** [#274](https://github.com/heroui-inc/heroui-native/pull/274)
## 组件改进
### Toast 样式与堆叠重构
[Toast](/docs/native/components/toast) 样式由边框模拟内边距改为真实 `p-4` 与上下占位视图,改善多 Toast 堆叠时的内容可见性。
**改进:**
* 以 `p-4` 取代 `border-[16px]` 内边距变通写法
* 新增 `useVerticalPlaceholderStyles` 用于占位视图样式
* 顶部与底部绝对定位占位 View,避免堆叠时内容露出
* 阴影系统改用 `shadow-overlay` 令牌
* 统一各主题(alpha、mint、sky)的遮罩阴影,降低不透明度
确保不同高度 Toast 堆叠时内容仍被正确遮挡,样式更易维护、可预期。
**相关 PR:** [#229](https://github.com/heroui-inc/heroui-native/pull/229)
### Dialog 遮罩手势关闭动画时序
[Dialog](/docs/native/components/dialog) 在手势关闭时弹层动画时序已修复:进度值按延迟正确排队,确保关闭动画播完再重置。
**改进:**
* 手势关闭时进度在 300ms 延迟后过渡到 2
* 350ms 后进度重置为 0,保证动画完成
* 移除 `isOpen` 为 false 时立即 `progress.set(2)` 的调用
* 侧滑关闭时关闭动画可正常播放
**相关 PR:** [#277](https://github.com/heroui-inc/heroui-native/pull/277)
### 主题 Surface 变量重构
主题系统以主题文件中的显式 surface 变量取代计算色,跨主题更可控、更一致。
**改进:**
* `surface-secondary`、`surface-tertiary`(及对应前景)在各主题(alpha、lavender、mint、sky、variables.css)中显式定义
* 基础主题使用 `var(--surface-secondary)`、`var(--surface-tertiary)`,不再用 `color-mix` 计算
* 从 theme.css 移除 `on-surface`、`on-surface-secondary`、`on-surface-tertiary` 调色板
* 主题文档更新变量结构与示例
主题作者可直接控制 surface 色值,不再依赖 `color-mix`,各主题 surface 表现更可预期。
**相关 PR:** [#281](https://github.com/heroui-inc/heroui-native/pull/281)
## API 增强
### 多组件统一 `styles` 属性
六个组件现支持统一的 `styles` 插槽式样式 API。
**涉及组件:**
* **Accordion**:`container`、`separator` 插槽
* **AvatarFallback**:`container`、`text` 插槽
* **FieldError**:`container`、`text` 插槽
* **Label**:`text`、`asterisk` 插槽(并修复 `style` 处理)
* **PressableFeedback Ripple**:`container`、`ripple` 插槽(取代 `containerStyle` 与 `rippleStyle`)
* **SelectContentDialog**:`wrapper`、`content` 插槽
**新能力:**
```tsx
import { Accordion, Label } from "heroui-native";
// 对指定插槽应用样式
Username
{/* Accordion items */}
```
变更保持与既有 `style` 的向后兼容,二者同时提供时会正确合并。
**相关 PR:** [#271](https://github.com/heroui-inc/heroui-native/pull/271)
### `disableFullWindowOverlay` 属性
基于 Portal 的组件现支持 `disableFullWindowOverlay`,便于在 iOS 开发时使用 React Native 元素检查器。
**涉及组件:**
* `BottomSheet.Portal`
* `Dialog.Portal`
* `Popover.Portal`
* `Select.Portal`
* `ToastProvider`
**新能力:**
```tsx
import { Dialog } from "heroui-native";
// 在 iOS 上启用元素检查器
{/* content */}
```
iOS 上 `FullWindowOverlay` 使用独立原生窗口,会阻挡元素检查器。将 `disableFullWindowOverlay` 设为 `true` 时内容绘于主窗口,开发期可检查元素;代价是遮罩不再叠在原生模态或键盘之上。Android 上该属性无效果。
使用 `HeroUINativeProvider` 时,Toast 通过 `config.toast` 传入该属性。
**相关 PR:** [#283](https://github.com/heroui-inc/heroui-native/pull/283)
### HeroUINativeProviderRaw
新增轻量提供者变体 `HeroUINativeProviderRaw`,不包含 `ToastProvider` 与 `PortalHost`,由使用方完全控制打包依赖。
**新能力:**
```tsx
import { HeroUINativeProviderRaw } from "heroui-native/provider-raw";
// 无 Toast 与 Portal 的轻量提供者
export function App() {
return (
{/* Your app content */}
);
}
```
`react-native-screens`、`@gorhom/bottom-sheet`、`react-native-svg` 由此可作为完全可选的对等依赖。Raw 提供者仅含 `SafeAreaListener`、`GlobalAnimationSettingsProvider`、`TextComponentProvider`。需要 Toast 或 Portal 时可自行组合。
**相关 PR:** [#285](https://github.com/heroui-inc/heroui-native/pull/285)
### Select.Trigger 的 `variant` 属性
`Select.Trigger` 现支持 `variant`:`"default"` 与 `"unstyled"`,便于与 Button 等自定义触发器组合。
**新能力:**
```tsx
import { Button, Select } from "heroui-native";
// 默认变体(预置样式触发器)
// 无样式变体,用于自定义组合
```
**相关 PR:** [#274](https://github.com/heroui-inc/heroui-native/pull/274)
### ControlField 的 Radio 变体
[ControlField](/docs/native/components/control-field) 的 `ControlField.Indicator` 现支持 `"radio"` 变体,与既有 `"switch"`、`"checkbox"` 并列,渲染独立 Radio 组件。
**新能力:**
```tsx
import { ControlField } from "heroui-native";
Radio option
```
**相关 PR:** [#286](https://github.com/heroui-inc/heroui-native/pull/286)
## ⚠️ 破坏性变更
### PressableFeedback Ripple:统一 `styles` 属性
PressableFeedback Ripple 的 `containerStyle` 与 `rippleStyle` 已合并为统一 `styles`。
**迁移:**
将所有单独样式属性改为 `styles`:
```tsx
// 之前
// 之后
```
**相关 PR:** [#271](https://github.com/heroui-inc/heroui-native/pull/271)
### Select.Trigger 默认样式
`Select.Trigger` 默认 `variant="default"`,会应用容器样式(`flex-row items-center justify-between h-12 px-4 rounded-2xl bg-surface shadow-surface`)。若此前为自定义样式触发器,需加 `variant="unstyled"` 以免套用默认样式。
**迁移:**
```tsx
// 之前(自定义样式触发器)
{/* content */}
// 之后(加 variant="unstyled" 保留自定义)
{/* content */}
```
**相关 PR:** [#274](https://github.com/heroui-inc/heroui-native/pull/274)
### Surface 主题变量结构调整
基础主题已移除 `on-surface`、`on-surface-secondary`、`on-surface-tertiary` 及其 hover/focus 变体 CSS 变量。secondary/tertiary surface 色现于各主题文件中显式定义。
**迁移:**
若自定义样式引用上述变量,请改为主题中定义的对应 surface 前景变量。
```css
/* 之前 */
color: var(--on-surface);
color: var(--on-surface-secondary);
/* 之后 */
color: var(--surface-foreground);
color: var(--surface-secondary-foreground);
```
**相关 PR:** [#281](https://github.com/heroui-inc/heroui-native/pull/281)
### 移除 RadioGroup.Indicator
`RadioGroup.Indicator` 与 `RadioGroup.IndicatorThumb` 已移除,改为独立 `Radio` 组件。相关类型 `RadioGroupIndicatorProps`、`RadioGroupIndicatorThumbProps`、`RadioGroupIndicatorThumbAnimation` 亦不再导出。
**迁移:**
将所有 `RadioGroup.Indicator` / `RadioGroup.IndicatorThumb` 替换为 `Radio`:
```tsx
// 之前
import { RadioGroup } from "heroui-native";
Option 1
// 之后
import { Radio, RadioGroup } from "heroui-native";
Option 1
```
**相关 PR:** [#286](https://github.com/heroui-inc/heroui-native/pull/286)
## 问题修复
本版本包含以下修复:
* **[Issue #229](https://github.com/heroui-inc/heroui-native/issues/229)**:修复 BottomSheet 内 InputOTP 不可用。现可在 BottomSheet 遮罩内正常聚焦与输入,解决此前无法输入 OTP 的问题。
* **[Issue #265](https://github.com/heroui-inc/heroui-native/issues/265)**:修复 Toast 描述首字符被裁切。Toast 样式重构后以真实内边距与占位视图取代边框变通,任意堆叠配置下文字均可完整显示。
* **[Issue #272](https://github.com/heroui-inc/heroui-native/issues/272)**:修复 FullWindowOverlay 在 iOS 上阻挡 React Native 元素检查器。Portal 组件新增 `disableFullWindowOverlay`,开发期可将遮罩内容绘于主窗口以恢复检查器。
**相关 PR:**
* [#229](https://github.com/heroui-inc/heroui-native/pull/229)
* [#283](https://github.com/heroui-inc/heroui-native/pull/283)
## 文档更新
以下文档页面已随本版本更新:
* [Alert](/docs/native/components/alert) — 新组件:用法示例与 API 参考
* [Radio](/docs/native/components/radio) — 独立 Radio 组件文档
* [Radio Group](/docs/native/components/radio-group) — 反映移除 RadioGroup.Indicator 及与 Radio 的集成
* [Control Field](/docs/native/components/control-field) — 新增 radio 变体说明
* [Select](/docs/native/components/select) — TriggerIndicator 子组件与 Trigger variant
* [Toast](/docs/native/components/toast) — 更新样式实现说明
* [Bottom Sheet](/docs/native/components/bottom-sheet) — 补充 disableFullWindowOverlay
* [Dialog](/docs/native/components/dialog) — 补充 disableFullWindowOverlay
* [Popover](/docs/native/components/popover) — 补充 disableFullWindowOverlay
* [Provider](/docs/native/getting-started/provider) — HeroUINativeProviderRaw 与提供者层级
* [Theming](/docs/native/getting-started/theming) — 更新 surface 变量结构与示例
* [Accordion](/docs/native/components/accordion) — 补充 styles 属性
* [Avatar](/docs/native/components/avatar) — 补充 styles 属性
* [Label](/docs/native/components/label) — 补充 styles 属性
* [Field Error](/docs/native/components/field-error) — 补充 styles 属性
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# RC 2
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/rc-2
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/rc-2.mdx
> SearchField、ListGroup、Slider 组件,Select 多选模式,Button 反馈 API 重构,放宽对等依赖约束
2026 年 2 月 20 日
RC 2 继续向生产就绪推进:新增 SearchField、ListGroup、Slider 三个组件;Select 支持由类型安全泛型支撑的多选模式;Button 按压反馈 API 重构为统一的 `feedbackVariant` + `animation`;放宽对等依赖约束以更好兼容 Expo SDK 55。另含若干 Select 与 Avatar 的问题修复。
## 安装
升级到最新版本:
```bash
npm i heroui-native
```
```bash
pnpm add heroui-native
```
```bash
yarn add heroui-native
```
```bash
bun add heroui-native
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 抢先体验
通过预览应用在真机上体验 RC 2 的全部改进!你可以探索 SearchField、ListGroup、Slider、Select 多选模式、更新后的 Button 反馈 API,以及各项修复。
### 环境要求
请确保手机已安装最新版本的 [Expo Go](https://expo.dev/go)。
### 如何访问
**方式一:扫描二维码**
使用手机相机或 Expo Go 应用扫描:
> **Android 用户请注意:** 若使用系统相机或其他扫码应用会跳转到浏览器并出现 404,请先打开 Expo Go,使用其内置扫码功能扫描。
**方式二:点击链接**
**[📱 在 Expo Go 中打开演示应用](https://link.heroui.com/native-demo)**
若设备已安装 Expo Go,将自动在其中打开应用。
## 更新亮点
### 新组件
本版本新增 **3** 个组件:
* **[Slider](/docs/native/components/slider)**:支持单值与区间模式、横/纵方向、自定义数字格式与弹簧动画拇指反馈。
* **[ListGroup](/docs/native/components/list-group)**:基于 Surface 的分组列表,可按压项、前后缀槽位,默认右箭头导航指示。
* **[SearchField](/docs/native/components/search-field)**:用于筛选与查询的复合组件,内置搜索图标、可清空输入与空值时自动隐藏清除按钮。
#### Slider
Slider 支持单值与区间(双拇指)模式、横纵布局、通过 `Intl.NumberFormat` 自定义数字格式,以及弹簧动画拇指反馈。原语层独立处理手势与数值逻辑,便于换肤实现复用。
**特性:**
* 复合子组件:`Slider.Output`、`Slider.Track`、`Slider.Fill`、`Slider.Thumb`
* 区间滑块:`defaultValue`/`value` 传入数组,在 `Slider.Track` 上使用渲染函数渲染多个拇指
* `orientation="vertical"` 纵向
* `formatOptions` 接受 `Intl.NumberFormatOptions`(货币、百分比、单位等)
* 基于 gesture-handler 的拖拽与轨道点击定位
* 数值钳制、步进与多拇指支持
* 可通过 `animation` 配置弹簧缩放拇指动画
* 无障碍:每个拇指 `role="slider"`,完整 `accessibilityValue`(min、max、now、text)
* `useSlider` 暴露上下文供高级用法
**用法:**
```tsx
import { Slider } from "heroui-native";
export function BasicSlider() {
return (
);
}
export function RangeSlider() {
return (
{({ thumbs }) => (
<>
{thumbs.map((_, i) => (
))}
>
)}
);
}
```
完整文档与示例见 [Slider 组件页](/docs/native/components/slider)。
**相关 PR:** [#305](https://github.com/heroui-inc/heroui-native/pull/305)
#### ListGroup
ListGroup 在 Surface 容器内渲染分组列表项,适用于设置页、菜单与内容浏览等导航列表模式。每项支持前缀、内容(标题 + 描述)与后缀槽位,默认带右箭头导航指示。
**特性:**
* 基于 Surface 的圆角容器与一致间距
* 复合子组件:`ListGroup.Item`、`ListGroup.ItemPrefix`、`ListGroup.ItemContent`、`ListGroup.ItemTitle`、`ListGroup.ItemDescription`、`ListGroup.ItemSuffix`
* `ItemSuffix` 默认内置 `ChevronRightIcon`
* 可按压项,集成 PressableFeedback
* 槽位可完全自定义图标、徽标等
**用法:**
```tsx
import { ListGroup } from "heroui-native";
export function Example() {
return (
console.log("Profile")}>
Profile
Manage your account
console.log("Settings")}>
Settings
App preferences
);
}
```
完整文档与示例见 [ListGroup 组件页](/docs/native/components/list-group)。
**相关 PR:** [#302](https://github.com/heroui-inc/heroui-native/pull/302)
#### SearchField
SearchField 为搜索与筛选场景提供专用输入,采用与 TextField 相同的复合组件模式:搜索图标、可清空输入、值为空时自动隐藏清除按钮。
**特性:**
* 复合子组件:`SearchField.Group`、`SearchField.SearchIcon`、`SearchField.Input`、`SearchField.ClearButton`
* `ClearButton` 在值为空时自动隐藏,按压清除搜索文本
* `SearchIcon` 支持自定义子节点替换默认放大镜 SVG
* 校验态视觉反馈
* 禁用态支持
* 与 Label、Description、FieldError 无缝集成
**用法:**
```tsx
import { Label, SearchField } from "heroui-native";
export function Example() {
return (
Search
);
}
```
完整文档与示例见 [SearchField 组件页](/docs/native/components/search-field)。
**相关 PR:** [#299](https://github.com/heroui-inc/heroui-native/pull/299)
### Select 多选模式
[Select](/docs/native/components/select) 现通过 `selectionMode` 支持多选。`RootProps` 对 `SelectionMode` 泛型化,TypeScript 按模式解析 `value` 与 `onValueChange`——单选为 `SelectOption`,多选为 `SelectOption[]`。
**特性:**
* `selectionMode="multiple"` 可多选切换;多选模式下 `closeOnPress` 默认 `false`
* 类型安全泛型:`RootProps` 通过 `SelectValueType` 解析 `value`/`onValueChange`
* `Select.Value` 使用 `formatSelectedLabels` 将多标签格式化为「Apple, Banana and Cherry」
* 单选模式完全向后兼容(默认)
**用法:**
```tsx
import { Select } from "heroui-native";
export function MultiSelect() {
return (
);
}
```
**相关 PR:** [#298](https://github.com/heroui-inc/heroui-native/pull/298)
### 新子组件
#### PressableFeedback.Scale
新增复合子组件,用于可选的缩放按压动画组合。`PressableFeedback.Scale` 可为任意可按压元素(如 `ListGroup.Item`)增加缩放反馈,而无需根级 `PressableFeedback` 管理缩放。
**用法:**
```tsx
import { PressableFeedback } from "heroui-native";
{/* item content */}
```
**相关 PR:** [#302](https://github.com/heroui-inc/heroui-native/pull/302)
## 组件改进
### Select 触发器与状态修复
[Select](/docs/native/components/select) 针对触发器与受控状态有多项修复。
**改进:**
* 自定义 `className` 现正确参与触发器样式计算,修复用户类名被静默丢弃的情况
* `useControllableState` 在从受控切到非受控时重置内部状态,避免陈旧选中残留
* 触发器通过 `onLayout` 测量位置,正确支持 `isDefaultOpen`
* 触发器样式更新为 `gap-3`、`py-3.5`,值文本使用 `flex-1` 改善布局
**相关 PR:** [#298](https://github.com/heroui-inc/heroui-native/pull/298)
### Avatar asChild 图片修复
[Avatar](/docs/native/components/avatar) 的 `AvatarImage` 在向底层原语转发时正确分离 `source`、`style` 与 `asChild` 及其余属性,修复使用 `asChild` 时错误将全部属性展开到图片组件的问题。
**相关 PR:** [#298](https://github.com/heroui-inc/heroui-native/pull/298)
## API 增强
### Button 反馈 API 重构
[Button](/docs/native/components/button) 的按压反馈 API 重构为统一的类型安全 `feedbackVariant` + `animation`,取代此前多属性拼写。
**新能力:**
```tsx
import { Button } from "heroui-native";
// 缩放 + 高亮(默认)
Press me
// 缩放 + 水波纹
Press me
// 仅缩放
Press me
// 自定义动画配置
Press me
```
`animation` 为按变体区分的联合类型,各反馈配置均有完整类型推导。
`button.utils.ts` 中新增 `resolveAnimationObject` 与 `isAnimationDisabled`,集中解析动画属性。
**相关 PR:** [#302](https://github.com/heroui-inc/heroui-native/pull/302)
## 依赖
### 放宽对等依赖约束
对等依赖版本约束已放宽为 caret(`^`)与范围(`>=`),替代偏紧的 tilde(`~`)或固定版本,便于使用方在较新依赖版本上解析,尤其 Expo SDK 55。
**变更:**
* `react-native-reanimated`:`~4.1.1` → `^4.1.1`(允许次版本更新)
* `react-native-safe-area-context`:`~5.6.0` → `^5.6.0`
* `react-native-svg`:`15.12.1` → `^15.12.1`
* `react-native-worklets`:`0.5.1` → `>=0.5.1`
无运行时逻辑变更——此前已满足约束的项目无需修改即可继续工作。
**相关 PR:** [#306](https://github.com/heroui-inc/heroui-native/pull/306)
## ⚠️ 破坏性变更
### Button 反馈 API
已移除 Button 上的 `pressableFeedbackVariant`、`pressableFeedbackHighlightProps`、`pressableFeedbackRippleProps`。请迁移到 `feedbackVariant` 与统一的 `animation`。
**迁移:**
更新所有 Button 反馈相关属性:
```tsx
// 之前
Press me
// 之后
Press me
```
**变体映射:**
* `"highlight"` → `"scale-highlight"`(默认)
* `"ripple"` → `"scale-ripple"`
* `"none"` → `"scale"` 或 `"none"`
**可选项:**
* `"scale-highlight"` — 缩小 + 高亮遮罩(默认)
* `"scale-ripple"` — 缩小 + 水波纹
* `"scale"` — 仅缩小
* `"none"` — 无反馈动画
**相关 PR:** [#302](https://github.com/heroui-inc/heroui-native/pull/302)
## 问题修复
本版本包含以下修复:
* **[Issue #291](https://github.com/heroui-inc/heroui-native/issues/291)**:修复 `Select.Trigger` 的 `variant` 被 `className` 覆盖的问题。传入触发器的自定义类名现正确参与样式计算,不再被静默丢弃。
* **[Issue #294](https://github.com/heroui-inc/heroui-native/issues/294)**:兼容 `react-native-worklets` 0.7.x 与 `react-native-reanimated` 4.2.x(Expo SDK 55)。放宽对等依赖约束,接受上述新版本而不产生解析告警。
**相关 PR:**
* [#298](https://github.com/heroui-inc/heroui-native/pull/298)
* [#306](https://github.com/heroui-inc/heroui-native/pull/306)
## 文档更新
以下文档页面已随本版本更新:
* [SearchField](/docs/native/components/search-field) — 新组件文档:用法示例与 API 参考
* [ListGroup](/docs/native/components/list-group) — 新组件文档:用法示例与 API 参考
* [Slider](/docs/native/components/slider) — 新组件文档:用法示例与 API 参考
* [Select](/docs/native/components/select) — 多选模式、触发器 className 修复与受控状态改进
* [Button](/docs/native/components/button) — 更新反馈 API 文档:`feedbackVariant` 与 `animation`
* [Avatar](/docs/native/components/avatar) — 修复 `asChild` 图片属性展开说明
* [PressableFeedback](/docs/native/components/pressable-feedback) — 新增 `PressableFeedback.Scale` 子组件文档
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# RC 3
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/rc-3
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/rc-3.mdx
> TagGroup、Menu、InputGroup 组件,Bottom Sheet Android 返回键修复,Expo 55 兼容
2026 年 2 月 26 日
RC 3 带来三个新组件:用于可选标签管理的 TagGroup、基于 Popover/Bottom Sheet 的下拉菜单 Menu,以及带自动测量前后缀槽位的装饰性输入 InputGroup。本版本还为所有基于 Bottom Sheet 的遮罩增加 Android 实体返回键支持;通过关键的 `combineStyles` 修复保留 Reanimated 动画样式绑定,实现 Expo 55 兼容;并包含若干依赖升级。
## 安装
升级到最新版本:
```bash
npm i heroui-native
```
```bash
pnpm add heroui-native
```
```bash
yarn add heroui-native
```
```bash
bun add heroui-native
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 抢先体验
通过预览应用在真机上体验 RC 3 的全部改进!你可以探索 TagGroup、Menu、InputGroup,以及 Bottom Sheet 的 Android 返回键支持与各项修复。
### 环境要求
请确保手机已安装最新版本的 [Expo Go](https://expo.dev/go)。
### 如何访问
**方式一:扫描二维码**
使用手机相机或 Expo Go 应用扫描:
> **Android 用户请注意:** 若使用系统相机或其他扫码应用会跳转到浏览器并出现 404,请先打开 Expo Go,使用其内置扫码功能扫描。
**方式二:点击链接**
**[📱 在 Expo Go 中打开演示应用](https://link.heroui.com/native-demo)**
若设备已安装 Expo Go,将自动在其中打开应用。
## 更新亮点
### 新组件
本版本新增 **3** 个组件:
* **[TagGroup](/docs/native/components/tag-group)**:用于展示与管理可选标签的复合组件,支持可选移除、单选/多选及表单字段集成。
* **[Menu](/docs/native/components/menu)**:下拉菜单系统,支持 Popover 与 Bottom Sheet 呈现、单选/多选、菜单项变体与按压动画反馈。
* **[InputGroup](/docs/native/components/input-group)**:装饰性文本输入,前后缀槽位绝对定位并自动测量宽度,为输入区应用匹配内边距。
#### TagGroup
TagGroup 以复合组件模式渲染可选标签组,并支持可选移除。支持单选与多选、受控/非受控 API、两种视觉变体(default 与 surface)、三种尺寸、禁用态,以及与 Label、Description、FieldError 的完整表单集成。
**特性:**
* 复合子组件:`TagGroup.List`、`TagGroup.Item`、`TagGroup.ItemLabel`、`TagGroup.ItemRemoveButton`
* 单选/多选模式,受控/非受控 API
* 两种视觉变体:`default` 与 `surface`
* 三种尺寸:`sm`、`md`、`lg`
* 单项禁用与 `disabledKeys`
* 通过 `onRemove` 与 `TagGroup.ItemRemoveButton` 实现移除
* `TagGroup.List` 上 `renderEmptyState` 渲染空状态
* 与 Label、Description、FieldError、`isInvalid`、`isRequired` 的表单集成
* `useTagGroup` 与 `useTagGroupItem` 供高级用法
**用法:**
```tsx
import { TagGroup } from "heroui-native";
export function BasicTagGroup() {
return (
React
Vue
Svelte
);
}
export function RemovableTagGroup() {
const [items, setItems] = useState(["React", "Vue", "Svelte"]);
return (
setItems((prev) => prev.filter((i) => !keys.has(i)))}>
{items.map((item) => (
{item}
))}
);
}
```
完整文档与示例见 [TagGroup 组件页](/docs/native/components/tag-group)。
**相关 PR:** [#309](https://github.com/heroui-inc/heroui-native/pull/309)
#### Menu
Menu 提供基于复合组件的下拉菜单,支持 Popover 与 Bottom Sheet 两种呈现。包含基于 Reanimated 的按压动画、单选/多选、菜单项变体(default 与 danger)、指示器样式及可配置 placement。
**特性:**
* 复合子组件:`Menu.Trigger`、`Menu.Portal`、`Menu.Overlay`、`Menu.Content`、`Menu.Label`、`Menu.Group`、`Menu.Item`、`Menu.ItemTitle`、`Menu.ItemDescription`、`Menu.ItemIndicator`
* 两种呈现:`popover` 与 `bottom-sheet`,placement 可配置(`top`、`bottom`、`left`、`right`)
* `Menu.Group` 上通过 `selectedKeys`/`onSelectionChange` 实现单选/多选
* 菜单项按压动画(缩放 + 背景色),Reanimated 实现,可通过 `animation` 自定义
* 菜单项变体:`default` 与 `danger`
* 指示器变体:`checkmark`、`dot` 或自定义内容
* `Menu.Label` 用于分区标题
* 分组级 `shouldCloseOnSelect` 控制
**用法:**
```tsx
import { Menu } from "heroui-native";
export function BasicMenu() {
return (
Open Menu
Edit
Duplicate
Delete
);
}
export function MenuWithSections() {
return (
Actions
View
List View
Grid View
);
}
```
完整文档与示例见 [Menu 组件页](/docs/native/components/menu)。
**相关 PR:** [#312](https://github.com/heroui-inc/heroui-native/pull/312)
#### InputGroup
InputGroup 提供装饰性文本输入,`Prefix` 与 `Suffix` 子组件绝对定位,通过 `onLayout` 自动测量宽度并为 Input 应用匹配的水平内边距。`isDecorative` 布尔值可一次性处理装饰性附加内容的无障碍与指针事件样板;根级 `isDisabled` 通过上下文级联到所有子节点。
**特性:**
* 复合子组件:`InputGroup.Prefix`、`InputGroup.Suffix`、`InputGroup.Input`
* 自动内边距:通过 `onLayout` 测量 Prefix/Suffix 宽度,自动作为 Input 的 `paddingLeft`/`paddingRight`
* Prefix/Suffix 上 `isDecorative` 统一设置 `pointerEvents="none"`、`accessibilityElementsHidden` 与 `importantForAccessibility`
* 根级 `isDisabled` 通过上下文级联(Prefix/Suffix 透明度与 pointer-events、Input 可编辑性)
* `InputGroup.Input` 为直接透传——由使用方在 Input 上管理 `value`/`onChangeText`
**用法:**
```tsx
import { InputGroup } from "heroui-native";
export function SearchInput() {
return (
);
}
export function DisabledInput() {
return (
);
}
```
完整文档与示例见 [InputGroup 组件页](/docs/native/components/input-group)。
**相关 PR:** [#313](https://github.com/heroui-inc/heroui-native/pull/313)
## 组件改进
### Bottom Sheet Android 返回键支持
[Bottom Sheet](/docs/native/components/bottom-sheet) 共享容器现处理 Android 实体返回键:按下时关闭当前打开的 Bottom Sheet。`BackHandler` 仅在 Bottom Sheet 打开时注册,避免已关闭实例抢占事件。该修复全局作用于所有基于 Bottom Sheet 的组件。
**涉及组件:**
* [Bottom Sheet](/docs/native/components/bottom-sheet)
* [Popover](/docs/native/components/popover)
* [Select](/docs/native/components/select)
实现使用 React Native 的 `BackHandler` API,在 iOS 上为空操作,无需分平台分支。
**相关 PR:** [#308](https://github.com/heroui-inc/heroui-native/pull/308)
### Slot 的 `combineStyles` 修复
Slot 原语的 `combineStyles` 现返回样式数组,而不再使用 `StyleSheet.flatten`——后者会通过深拷贝样式对象破坏 Reanimated 的 `SharedValue` 与 `useAnimatedStyle` 绑定。
**改进:**
* `combineStyles` 通过返回数组保留 Reanimated 动画样式绑定
* React Native 原生支持嵌套样式数组,对使用方行为无影响
* 修复通过 Slot 原语组合的组件上的动画断裂问题
**相关 PR:** [#314](https://github.com/heroui-inc/heroui-native/pull/314)
## 依赖
### Expo 55 兼容
依赖版本已更新以兼容 Expo SDK 55:
* `uniwind`:1.2.7 → 1.3.2
* `@gorhom/bottom-sheet`:^5 → ^5.2.8
上述 `combineStyles` 修复是支持 Expo 55 的主要代码变更:此前 `StyleSheet.flatten` 会在新 SDK 下破坏 Reanimated 样式绑定。
**相关 PR:** [#314](https://github.com/heroui-inc/heroui-native/pull/314)
## 问题修复
本版本包含以下修复:
* **[Issue #272](https://github.com/heroui-inc/heroui-native/issues/272)**:解决 `FullWindowOverlay` 干扰 React Native 元素检查器的问题。
* **[Issue #280](https://github.com/heroui-inc/heroui-native/issues/280)**:修复 Expo 55 下 Avatar 等依赖 Reanimated 的组件失效。`combineStyles` 曾通过 `StyleSheet.flatten` 破坏动画绑定;现改为返回样式数组以保留 `SharedValue` 与 `useAnimatedStyle`。
**相关 PR:**
* [#308](https://github.com/heroui-inc/heroui-native/pull/308)
* [#314](https://github.com/heroui-inc/heroui-native/pull/314)
## 文档更新
以下文档页面已随本版本更新:
* [TagGroup](/docs/native/components/tag-group) — 新组件文档:用法示例与 API 参考
* [Menu](/docs/native/components/menu) — 新组件文档:用法示例与 API 参考
* [InputGroup](/docs/native/components/input-group) — 新组件文档:用法示例与 API 参考
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# RC 4
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/rc-4
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/rc-4.mdx
> SubMenu 组件、Slider Output 组合重构、PressableFeedback 水波纹修复、Bottom Sheet 返回键处理修复
2026 年 3 月 6 日
RC 4 引入用于嵌套可展开菜单的 SubMenu 复合组件,配套弹簧动画展开/收起;重构 Slider Output,采用基于插槽的样式并支持 `textProps` 透传;为 `Menu.Group` 增加 `disallowEmptySelection`,实现类单选框行为。本版本还通过双层缓冲修复快速连按时 PressableFeedback 水波纹闪烁,并修复 Bottom Sheet 在 Android 上未尊重 `enablePanDownToClose` 的返回键处理。
## 安装
升级到最新版本:
```bash
npm i heroui-native
```
```bash
pnpm add heroui-native
```
```bash
yarn add heroui-native
```
```bash
bun add heroui-native
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 抢先体验
通过预览应用在真机上体验 RC 4 的全部改进!你可以探索全新的 SubMenu 组件、改进后的 Slider Output,以及各项修复。
### 环境要求
请确保手机已安装最新版本的 [Expo Go](https://expo.dev/go)。
### 如何访问
**方式一:扫描二维码**
使用手机相机或 Expo Go 应用扫描:
> **Android 用户请注意:** 若使用系统相机或其他扫码应用会跳转到浏览器并出现 404,请先打开 Expo Go,使用其内置扫码功能扫描。
**方式二:点击链接**
**[📱 在 Expo Go 中打开演示应用](https://link.heroui.com/native-demo)**
若设备已安装 Expo Go,将自动在其中打开应用。
## 更新亮点
### SubMenu 组件
[Menu](/docs/native/components/menu) 现通过新的 `SubMenu` 复合组件支持嵌套可展开子菜单。SubMenu 嵌套在 `Menu.Content` 内,按压后以弹簧动画展开/收起额外项,并带动指示器旋转。
**特性:**
* 复合子组件:`SubMenu`、`SubMenu.Trigger`、`SubMenu.TriggerIndicator`、`SubMenu.Content`
* 弹簧动画展开/收起与指示器旋转
* 无头原语层:上下文、受控/非受控打开状态,以及无障碍属性(`role`、`aria-expanded`、`aria-disabled`)
* 父级菜单协同:打开 SubMenu 时 popover 缩至 0.98、移除阴影,非 SubMenu 项淡出至 40% 不透明度并 `pointer-events-none`
* 打开 SubMenu 时菜单内容切换为 `FadeOut` 退出动画,避免与缩放动画冲突
* `useSubMenu` 钩子供高级场景使用
**用法:**
```tsx
import { Menu, SubMenu } from "heroui-native";
export function MenuWithSubMenu() {
return (
Open Menu
Edit
More Options
Import
Export
);
}
```
完整文档与示例见 [Menu 组件页](/docs/native/components/menu)。
**相关 PR:** [#331](https://github.com/heroui-inc/heroui-native/pull/331)
## 组件改进
### Slider Output 组合重构
[Slider](/docs/native/components/slider) 的 Output 已重构为基于插槽的架构,包含 `container` 与 `text` 插槽,并新增 `textProps` 用于向内层文本元素透传属性。
**改进:**
* 基于插槽的样式:将 `output` 类拆为 `container` 与 `text`,新增 `classNames`(`classNames={{ container, text }}`)以便精细覆盖样式
* 组合修复:仅在默认内容时渲染 `HeroText`;自定义子节点直接渲染,无额外文本包装
* `Slider.Output` 新增 `textProps`,可向内部文本传递任意属性(如 `maxFontSizeMultiplier`)
* 从样式模块导出 `OutputSlots` 类型供外部使用
**相关 PR:** [#328](https://github.com/heroui-inc/heroui-native/pull/328)
### Menu.Group 的 `disallowEmptySelection`
[Menu](/docs/native/components/menu) 的 `Menu.Group` 现支持 `disallowEmptySelection`,在 `single` 选择模式下禁止取消最后一项选中,实现类单选框行为。
**用法:**
```tsx
List View
Grid View
```
**相关 PR:** [#331](https://github.com/heroui-inc/heroui-native/pull/331)
### Bottom Sheet 与 `enablePanDownToClose` 一致
[Bottom Sheet](/docs/native/components/bottom-sheet) 现会在 Android 硬件返回键行为上正确尊重 `enablePanDownToClose`。此前即使 `enablePanDownToClose` 为 `false`,返回键仍会关闭 Bottom Sheet。
**改进:**
* `enablePanDownToClose` 透传至 `BottomSheetContentContainer`(默认 `true`)
* 仅在 `isOpen` 与 `enablePanDownToClose` 均为 `true` 时注册 `BackHandler` 监听
* `enablePanDownToClose={false}` 时不再可通过 Android 返回键关闭
**相关 PR:** [#327](https://github.com/heroui-inc/heroui-native/pull/327)
## ⚠️ 破坏性变更
### Chip 组件尺寸
[Chip](/docs/native/components/chip) 的尺寸变体已由固定高度改为基于内边距,以在较大无障碍字号下适配动态文字缩放。
**迁移:**
若自定义样式依赖此前的 `h-5`/`h-6`/`h-7` 高度,请改为新的内边距方案:
```tsx
// 之前 — 固定高度
// Chip 使用 h-5(sm)、h-6(md)、h-7(lg)
// 之后 — 基于内边距
// Chip 使用 py-0.5(sm)、py-[3px](md)、py-1(lg)
// 圆角更新:rounded-xl → rounded-2xl / rounded-3xl
```
## 文档更新
以下文档页面已随本版本更新:
* [Menu](/docs/native/components/menu) — SubMenu 文档:结构分解、用法示例、完整 API 参考及 `useSubMenu` 钩子说明
* [Slider](/docs/native/components/slider) — 更新 Output 文档:基于插槽的样式与 `textProps`
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# v1.0.0
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/v1-0-0
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/v1-0-0.mdx
> LinkButton 组件、子菜单冲突处理、可选的 @gorhom/bottom-sheet 对等依赖、ThemeColorValue 品牌类型
2026 年 3 月 19 日
🎉 HeroUI Native 正式发布 v1.0.0——这是首个稳定版本,标志着库已从 beta 与候选发布阶段毕业,成为可用于生产环境的 React Native 应用基础。伴随这一里程碑,本版本还包含全新的 LinkButton 组件、子菜单冲突处理、可选的 `@gorhom/bottom-sheet` 对等依赖,以及针对 `useThemeColor` 的更强类型安全。
## 安装
升级到最新版本:
```bash
npm i heroui-native
```
```bash
pnpm add heroui-native
```
```bash
yarn add heroui-native
```
```bash
bun add heroui-native
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 抢先体验
通过我们的预览应用,在真机上体验 v1.0.0 的全部改进!你可以探索全新的 LinkButton 组件、改进后的子菜单行为,以及各项修复。
### 环境要求
请确保手机已安装最新版本的 [Expo Go](https://expo.dev/go)。
### 如何访问
**方式一:扫描二维码**
使用手机相机或 Expo Go 应用扫描:
> **Android 用户请注意:** 若使用系统相机或其他扫码应用会跳转到浏览器并出现 404,请先打开 Expo Go,使用其内置扫码功能扫描。
**方式二:点击链接**
**[📱 在 Expo Go 中打开演示应用](https://link.heroui.com/native-demo)**
若设备已安装 Expo Go,将自动在其中打开应用。
## 更新亮点
### LinkButton 组件
全新的 [LinkButton](/docs/native/components/button) 复合组件会渲染 ghost 变体按钮,且无高亮反馈,适用于「服务条款」「隐私政策」等行内链接式交互。它完全复用现有 Button 基础设施,并在内部强制 ghost 变体且关闭高亮反馈。
**特性:**
* 复合子组件:`LinkButton.Label`,用于样式化文本内容
* 内部强制 ghost 变体——不对外暴露 `variant` 属性
* 通过 `resolveAnimationObject` 默认关闭高亮反馈
* `h-auto p-0` 基础类移除默认按钮高度与内边距,便于行内使用
* 合并使用方动画配置时仍保持 `highlight: false`
**用法:**
```tsx
import { LinkButton } from "heroui-native";
export function TermsLink() {
return (
openURL("https://example.com/terms")}>
Terms of Service
);
}
```
**相关 PR:** [#341](https://github.com/heroui-inc/heroui-native/pull/341)
## 组件改进
### 子菜单单开约束与点击背景关闭
[Menu](/docs/native/components/menu) 子菜单系统已重构为按 ID 跟踪当前子菜单,而非简单布尔值,从而在同级子菜单之间强制「同时仅开一个」。子菜单打开时,会在菜单内容区域上方渲染可点击的背景层,用户点击外部即可关闭。
**改进:**
* `openSubMenuId` 取代布尔标记——同一时间只能有一个子菜单处于打开状态;打开新的会自动关闭上一个
* 子菜单打开时,在菜单内容上渲染 `Pressable` 遮罩,支持点击关闭
* 非当前打开的子菜单触发器通过新的 `isOtherSubMenuOpen` 样式变体获得 `opacity-40` 与 `pointer-events-none`
* 打开的子菜单内容使用 `z-50`,关闭的为 `z-40`,避免层叠问题
* 演示应用新增「两个子菜单」示例,展示同一菜单中的多个子菜单
**相关 PR:** [#343](https://github.com/heroui-inc/heroui-native/pull/343)
### Button Label 的 ref 类型修复
`ButtonLabel` 的 ref 类型已从 `View` 更正为 `TextRef`,并从 `button.tsx` 中移除了未使用的 `View` 导入,使 ref 类型与实际渲染元素一致。
**相关 PR:** [#341](https://github.com/heroui-inc/heroui-native/pull/341)
## API 增强
### 用于 `useThemeColor` 的 `ThemeColorValue` 品牌类型
`useThemeColor` 在单次取色调用时现返回 `ThemeColorValue` 品牌类型,误用数组解构时 IDE 会立即将类型标为 `never`。非空断言运算符(`!`)也已替换为安全的空值合并回退。
**新行为:**
```tsx
import { useThemeColor } from "heroui-native";
// 正确 — 直接赋值
const mutedColor = useThemeColor("muted");
// 错误 — IDE 会立即标出 `never` 类型
const [color] = useThemeColor("muted"); // color: never
```
`ThemeColorValue` 继承自 `string`,因此凡可接受 `string` 处均可赋值。现有调用点在运行时不受影响。`_colorValueBrand` 符号以 `declare const` 声明,无运行时体积。
**相关 PR:** [#337](https://github.com/heroui-inc/heroui-native/pull/337)
### 公开钩子 `useBottomSheetAwareHandlers`
`useBottomSheetAwareHandlers` 现已作为公开 API 导出,便于在 Bottom Sheet 内显式控制键盘避让与 `Input`、`InputOTP` 的衔接。此前在 `Input` 与 `InputOTP` 上可用的隐式 `isBottomSheetAware` 属性已被取代。
**用法:**
```tsx
import { useBottomSheetAwareHandlers, Input } from "heroui-native";
export function BottomSheetInput() {
const { onFocus, onBlur } = useBottomSheetAwareHandlers();
return ;
}
```
**相关 PR:** [#347](https://github.com/heroui-inc/heroui-native/pull/347)
## ⚠️ 破坏性变更
### Bottom Sheet 内的 `Input` 与 `InputOTP`
已从 `Input` 与 `InputOTP` 移除 `isBottomSheetAware` 属性。此前 Bottom Sheet 内的键盘避让在底层自动处理;现在必须显式使用 `useBottomSheetAwareHandlers` 并自行传入处理器。这样可减轻 Input 组件负担,去掉隐式 `@gorhom/bottom-sheet` 导入,使该包对不使用 Bottom Sheet 的项目成为可选对等依赖。
**迁移:**
```tsx
// 之前
// 之后
import { useBottomSheetAwareHandlers } from "heroui-native";
const { onFocus, onBlur } = useBottomSheetAwareHandlers();
```
凡在 `BottomSheet` 内渲染的 `Input` 或 `InputOTP` 均需按此调整;在 Bottom Sheet 外使用的组件不受影响。
**相关 PR:** [#347](https://github.com/heroui-inc/heroui-native/pull/347)
## 问题修复
本版本包含以下修复:
* **[Issue #330](https://github.com/heroui-inc/heroui-native/issues/330)**:修复 `Input` 在模块顶层无条件导入 `@gorhom/bottom-sheet` 的问题,即使 `isBottomSheetAware` 为 `false`。现通过可选的 `try/catch` 包装懒加载该包,不使用 Bottom Sheet 的项目无需再安装它。
* **[Issue #340](https://github.com/heroui-inc/heroui-native/issues/340)**:修复子菜单内容出现在同级子菜单触发器后方的问题。子菜单系统现按 ID 跟踪活动子菜单、强制单开,并应用正确的 z-index 分层(打开 `z-50`,关闭 `z-40`)。
**相关 PR:**
* [#347](https://github.com/heroui-inc/heroui-native/pull/347)
* [#343](https://github.com/heroui-inc/heroui-native/pull/343)
## 文档更新
以下文档页面已随本版本更新:
* [LinkButton](/docs/native/components/link-button) — LinkButton 复合组件文档:结构分解、用法示例与 API 参考
* [Menu](/docs/native/components/menu) — 更新子菜单文档:单开约束与点击背景关闭行为
* [Input](/docs/native/components/input) — 更新 Bottom Sheet 用法示例,采用 `useBottomSheetAwareHandlers` 模式
* [InputOTP](/docs/native/components/input-otp) — 同上,Bottom Sheet 示例采用 `useBottomSheetAwareHandlers`
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# v1.0.1
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/v1-0-1
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/v1-0-1.mdx
> Toast 竞态修复、使用 disabled 修饰符的禁用态样式、背景层样式变量 backdrop
2026 年 4 月 1 日
HeroUI Native v1.0.1 是一次侧重可靠性与开发者体验的补丁版本。它修复了 Toast 提供程序中导致动画值过期的竞态条件,将七个组件的禁用态样式改为使用原生 `disabled:` 修饰符,并为主题系统新增 `--backdrop` 变量,供遮罩类组件使用。
## 安装
升级到最新版本:
```bash
npm i heroui-native
```
```bash
pnpm add heroui-native
```
```bash
yarn add heroui-native
```
```bash
bun add heroui-native
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 抢先体验
通过预览应用在真机上体验 v1.0.1 的全部改进!你可以查看 Toast 修复、改进后的禁用态样式以及新的背景层变量。
### 环境要求
请确保手机已安装最新版本的 [Expo Go](https://expo.dev/go)。
### 如何访问
**方式一:扫描二维码**
使用手机相机或 Expo Go 应用扫描:
> **Android 用户请注意:** 若使用系统相机或其他扫码应用会跳转到浏览器并出现 404,请先打开 Expo Go,使用其内置扫码功能扫描。
**方式二:点击链接**
**[📱 在 Expo Go 中打开演示应用](https://link.heroui.com/native-demo)**
若设备已安装 Expo Go,将自动在其中打开应用。
## API 增强
### `--backdrop` 主题变量
主题系统新增顶层样式变量 `--backdrop`,为 Dialog、Bottom Sheet 等遮罩组件背后的变暗层提供专用色令牌。默认值为 `oklch(0% 0 0 / 20%)`,呈现轻微但可见的背景变暗效果。
**新能力:**
```tsx
import { Dialog } from "heroui-native";
// Dialog 与 Bottom Sheet 遮罩现自动使用 bg-backdrop
{/* 内容绘制在主题化背景层之上 */}
```
`--backdrop` 已纳入所有内置主题的浅色与深色模式,对应的 Tailwind 工具类 `bg-backdrop` 也可用于自定义组件样式。
**相关 PR:** [#366](https://github.com/heroui-inc/heroui-native/pull/366)
## 样式修复
### 禁用态修饰符
七个组件的禁用态样式已改为使用 `disabled:` 前缀修饰符,而非无条件应用样式。这样可确保 `opacity-disabled`、`pointer-events-none` 等仅在组件真实处于禁用态时生效,并尊重来自 Uniwind 的原生 `disabled` 修饰符。
**涉及组件:**
* [Button](/docs/native/components/button)
* [Checkbox](/docs/native/components/checkbox)
* [Input](/docs/native/components/input)
* [Menu](/docs/native/components/menu)
* [Switch](/docs/native/components/switch)
* [Tabs](/docs/native/components/tabs)
* [TagGroup](/docs/native/components/tag-group)
所有 `isDisabled` 变体类现均使用 `disabled:` 前缀(例如 `disabled:opacity-disabled disabled:pointer-events-none`),正确限定在禁用伪状态,并在禁用态动态切换时消除样式冲突。
**相关 PR:** [#361](https://github.com/heroui-inc/heroui-native/pull/361)
## 问题修复
本版本包含以下修复:
* **[Issue #359](https://github.com/heroui-inc/heroui-native/issues/359)**:修复 Toast 提供程序中 `total` SharedValue 与实际 Toast 数量可能不同步的竞态。原先手动增减在 `hide` 与 `show` 同一帧执行、或自动消失与手动隐藏竞速时,易出现闭包陈旧导致不一致。`total` 现通过 `useEffect` 由 `toasts.length` 派生,使透明度、缩放、translateY 等插值始终反映真实数量。
* **[Issue #356](https://github.com/heroui-inc/heroui-native/issues/356)**:修复在 `isDisabled` 为 true 时禁用样式被无条件应用、阻碍开发者主题化或自定义禁用外观的问题。上述七个组件均已改为 `disabled:` 前缀,将样式正确限定在禁用伪状态。
**相关 PR:**
* [#360](https://github.com/heroui-inc/heroui-native/pull/360)
* [#361](https://github.com/heroui-inc/heroui-native/pull/361)
## 文档更新
以下文档页面已随本版本更新:
* [Colors](/docs/native/getting-started/colors) — 在颜色参考中补充新的 `--backdrop` 变量
* [Theming](/docs/native/getting-started/theming) — 主题指南中增加 `--backdrop` 变量说明
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# v1.0.2
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/v1-0-2
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/v1-0-2.mdx
> PressableFeedback 与 Surface 的 asChild 插槽模式、Portal 无障碍 modal 属性、Button Android 变体修复、Input 与 Select 样式微调
2026 年 4 月 15 日
HeroUI Native v1.0.2 为 PressableFeedback 与 Surface 引入 `asChild` 插槽模式,为所有基于 Portal 的遮罩组件增加 VoiceOver 模态包容支持,并修复 Android 上 Button 某变体的样式问题。本版本还微调了 Input 与 Select 的视觉效果,并在 RadioGroup 文档中内嵌 API 参考表。
## 安装
升级到最新版本:
```bash
npm i heroui-native
```
```bash
pnpm add heroui-native
```
```bash
yarn add heroui-native
```
```bash
bun add heroui-native
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 抢先体验
通过预览应用在真机上体验 v1.0.2 的全部改进!你可以探索新的 `asChild` 插槽模式、Portal 无障碍改进、Android 上更可靠的 Button 行为,以及优化后的 Input 与 Select 样式。
### 环境要求
请确保手机已安装最新版本的 [Expo Go](https://expo.dev/go)。
### 如何访问
**方式一:扫描二维码**
使用手机相机或 Expo Go 应用扫描:
> **Android 用户请注意:** 若使用系统相机或其他扫码应用会跳转到浏览器并出现 404,请先打开 Expo Go,使用其内置扫码功能扫描。
**方式二:点击链接**
**[📱 在 Expo Go 中打开演示应用](https://link.heroui.com/native-demo)**
若设备已安装 Expo Go,将自动在其中打开应用。
## API 增强
### PressableFeedback 与 Surface 的 `asChild` 插槽模式
[PressableFeedback](/docs/native/components/pressable-feedback) 与 [Surface](/docs/native/components/surface) 现支持 `asChild` 属性,采用 Slot 模式实现多态渲染。当 `asChild` 为 `true` 时,组件会把自身行为与样式合并到单个子元素上,而不再额外包一层节点。
**PressableFeedback** 使用 `Animated.createAnimatedComponent(Slot.Pressable)`,将按压处理与动画样式合并到子元素。**Surface** 使用 `Slot.View`,将表面样式(海拔、背景、`className`)合并到子元素。
**新能力:**
```tsx
import { PressableFeedback, Surface } from "heroui-native";
// PressableFeedback 将按压处理合并到子元素
console.log("pressed")}>
// Surface 将表面样式合并到子元素
```
`asChild` 默认为 `false`,保持既有行为,无需迁移。启用 `asChild` 时子节点须为单个 React 元素。两处实现均遵循代码库中已有的 Slot 原语模式。
**相关 PR:** [#380](https://github.com/heroui-inc/heroui-native/pull/380)
### Portal 组件的 `unstable_accessibilityContainerViewIsModal`
所有基于 Portal 的遮罩组件新增 `unstable_accessibilityContainerViewIsModal` 属性,用于控制 iOS VoiceOver 是否将遮罩窗口视为模态容器。启用后,VoiceOver 焦点限制在遮罩内,无法导航到背后内容。
**支持的组件:**
* [BottomSheet](/docs/native/components/bottom-sheet)(`BottomSheet.Portal`)
* [Dialog](/docs/native/components/dialog)(`Dialog.Portal`)
* [Menu](/docs/native/components/menu)(`Menu.Portal`)
* [Popover](/docs/native/components/popover)(`Popover.Portal`)
* [Select](/docs/native/components/select)(`Select.Portal`)
* [Toast](/docs/native/components/toast)(`ToastProvider`)
**新能力:**
```tsx
import { Dialog } from "heroui-native";
{/* 在 iOS 上 VoiceOver 焦点限制在此遮罩内 */}
```
该属性默认为 `false`,保持既有行为。标记为 `unstable` 是因为它直接映射到 `react-native-screens` 中 `FullWindowOverlay` 的原生 `accessibilityViewIsModal`,未来可能随该库版本变化。
**相关 PR:** [#383](https://github.com/heroui-inc/heroui-native/pull/383)
## 样式修复
### Input 与 Select 视觉微调
优化了 [Input](/docs/native/components/input) 与 [Select](/docs/native/components/select) 的视觉样式,使外观更干净、比例更协调。
**调整:**
* **Input**:边框宽度由 `border-2`(2px)改为 `border-[1.5px]`,边框更轻、不抢眼
* **Select**:触发器垂直内边距由 `py-3.5` 改为 `py-3`,布局更紧凑
以上均为纯视觉调整,无 API 或行为变更。建议在 iOS 与 Android 上做视觉回归确认。
**相关 PR:** [#381](https://github.com/heroui-inc/heroui-native/pull/381)
## 问题修复
本版本包含以下修复:
* **[Issue #363](https://github.com/heroui-inc/heroui-native/issues/363)**:修复 Android 上 Button 的 outline 变体在通过条件属性切换到其他变体时边框仍残留的问题。Android 上的 React Native 在变体切换时有时会保留 `borderWidth`。除 `outline` 外的所有按钮变体现均包含显式 `border-0` 类,确保变体切换时将 `borderWidth` 重置为 `0`。
* **[Issue #357](https://github.com/heroui-inc/heroui-native/issues/357)**:响应在 Card 上支持 `asChild` 以实现可按压卡片模式的诉求。PressableFeedback 与 Surface 上的新 `asChild` 插槽模式,使开发者可将按压与表面样式合并到单个子元素,无需额外包装节点。
**相关 PR:**
* [#370](https://github.com/heroui-inc/heroui-native/pull/370)
* [#380](https://github.com/heroui-inc/heroui-native/pull/380)
## 文档
### RadioGroup 内联 API 参考
[RadioGroup](/docs/native/components/radio-group) 文档现于页面内嵌 `Radio`、`Radio.Indicator`、`Radio.IndicatorThumb` 的完整 API 表,读者无需再跳转到单独的 Radio 文档即可了解在 `RadioGroup.Item` 中组合时的可用属性。
**改进:**
* `Radio`、`Radio.Indicator`、`Radio.IndicatorThumb` 的完整属性表内嵌展示
* 补充 `RadioRenderProps`、`RadioRootAnimation`、`RadioIndicatorThumbAnimation` 类型说明
* 将外链式 Markdown 链接统一为内联代码格式以保持一致性
**相关 PR:** [#384](https://github.com/heroui-inc/heroui-native/pull/384)
## 文档更新
以下文档页面已随本版本更新:
* [RadioGroup](/docs/native/components/radio-group) — 内联 API 表:`Radio`、`Radio.Indicator`、`Radio.IndicatorThumb`
* [PressableFeedback](/docs/native/components/pressable-feedback) — 补充 `asChild` 属性说明
* [Surface](/docs/native/components/surface) — 补充 `asChild` 属性说明
* [BottomSheet](/docs/native/components/bottom-sheet) — 补充 `unstable_accessibilityContainerViewIsModal` 说明
* [Dialog](/docs/native/components/dialog) — 同上
* [Menu](/docs/native/components/menu) — 同上
* [Popover](/docs/native/components/popover) — 同上
* [Select](/docs/native/components/select) — 同上
* [Toast](/docs/native/components/toast) — 同上
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# v1.0.3
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/v1-0-3
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/v1-0-3.mdx
> 全新 Text 排版组件、ScrollShadow 反向列表支持、Tabs RTL 指示器修复、Avatar alt 属性可选化、Select 指示器统一、表单字段样式微调
2026 年 5 月 11 日
HeroUI Native v1.0.3 引入全新的 `Text` 排版基元,提供面向标题、段落与内联代码的复合 API;同时为 `ScrollShadow` 在反向列表下的渲染、`Tabs` 指示器在 RTL 布局下的对齐、以及自定义 `Select.TriggerIndicator` `children` 时的动画问题带来重要修复。本版本还对 `Button`、`Chip`、`Input` 的视觉样式进行了微调,将 `Avatar` 的 `alt` 属性改为可选,并修正 `TextField` 与 `SearchField` 的内部内边距行为。
## 安装
升级到最新版本:
```bash
npm i heroui-native
```
```bash
pnpm add heroui-native
```
```bash
yarn add heroui-native
```
```bash
bun add heroui-native
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 真机体验
## 新增
### 新组件
本版本新增 **1 个** 排版组件:
* **[Text](/docs/native/components/text)**:带语义 `type` 变体的排版基元组件,附带 `Heading`、`Paragraph`、`Code` 子组件。([文档](/docs/native/components/text))
#### Text
`Text` 组件是一个排版基元,通过语义化预设渲染样式化文本。它提供 `Text.Heading`、`Text.Paragraph`、`Text.Code` 等子组件构成的复合 API,并在 `tailwind-variants` 基础上叠加互不耦合的 `align`、`color`、`weight`、`truncate` 属性,使排版可以组合复用,无需在每个调用点重复定义样式。
**特性:**
* 语义化 `type` 变体:`h1`–`h6`、`body`、`body-sm`、`body-xs`、`code`
* `Text.Heading` 自动设置 `accessibilityRole="header"`,并将 `type` 收窄为标题级别
* `Text.Paragraph` 将 `type` 收窄为正文变体,适合长文本可读性
* `Text.Code` 渲染为 chip 样式的内联等宽文本,采用平台合适的 `fontFamily`(iOS 为 Menlo,其他平台为 `monospace`)
* RTL 感知的 `align` 属性,支持 `start`、`center`、`end`、`justify`(justify 仅 iOS 生效)
* 语义化 `color` 预设(`default`、`muted`),其他主题色可通过 `className` 外挂
* `weight` 覆盖:借助 `tailwind-merge` 始终优先于 `type` 暗含的字重
* `truncate` 布尔属性:等价于 `numberOfLines={1}`;显式 `numberOfLines` 始终优先
**用法:**
```tsx
import { Text } from "heroui-native";
import { View } from "react-native";
export function Example() {
return (
Welcome
Getting Started
This is a body paragraph rendered with the Text component.
Smaller supporting text for captions or footnotes.
npm install heroui-native
);
}
```
完整文档与示例见 [Text 组件页面](/docs/native/components/text)。
**相关 PR:** [#400](https://github.com/heroui-inc/heroui-native/pull/400)
## 组件改进
### ScrollShadow 反向子列表支持
[ScrollShadow](/docs/native/components/scroll-shadow) 现已正确处理反向的可滚动子组件,如 `` 或 ``。
**改进点:**
* `ScrollShadowRoot` 现会读取可滚动子组件上的 `inverted` 属性,沿用既有的 `childHorizontal` 自动检测模式
* 内部交换驱动各视觉边缘的动画样式,使阴影渲染到正确的一侧
* 公共 API 无变化——仅当子组件设置 `inverted={true}` 时启用该修复,此前在此情况下渐变会出现在错误的边缘
此前,包裹反向列表时渐变阴影会渲染在顶部,而可滚动内容位于其下;即便仍有更多内容也不会出现底部阴影。修复后,反向 feed、聊天列表等反向滚动表面上的指示器方向已正确。
**相关 PR:** [#398](https://github.com/heroui-inc/heroui-native/pull/398)
### Tabs RTL 指示器对齐
[Tabs](/docs/native/components/tabs) 的指示器在 React Native 处于 RTL 模式时定位现已正确。
**改进点:**
* 通过 tabs 测量上下文跟踪标签条的宽度
* 固定布局使用 `Tabs.List` 的布局宽度
* 滚动布局使用 `Tabs.ScrollView` 的内容宽度
* 仅当 `I18nManager.isRTL` 启用时,对指示器的 `translateX` 进行镜像
指示器使用绝对定位 `left` 锚点配合测量得到的 `translateX`。在 RTL 模式下,React Native 会自动翻转绝对锚点,但所测量的 transform 仍需手动镜像——本次修复内部完成了这一处理。固定与滚动两类标签列表均已修复,且公共 API 未变。
**相关 PR:** [#396](https://github.com/heroui-inc/heroui-native/pull/396)
### Select 触发器指示器渲染统一
[Select](/docs/native/components/select) 的 `Select.TriggerIndicator` 现无论使用默认图标还是自定义 `children`,都会一致地应用展开/收起的旋转动画。
**改进点:**
* 自定义 `children` 现可获得与默认图标相同的动画容器样式
* 通过 `children ?? ` 将 `ChevronDownIcon` 作为回退渲染
* 将此前分散的渲染分支合并为统一的渲染路径
此前,向 `Select.TriggerIndicator` 传入自定义 `children` 会绕过旋转动画,导致开合时指示器保持静止。统一分支确保旋转动画始终生效,且公共 API 未变。
**相关 PR:** [#409](https://github.com/heroui-inc/heroui-native/pull/409)
## API 增强
### Avatar 的 `alt` 属性变为可选
[Avatar](/docs/native/components/avatar) 的 `alt` 属性现已可选,默认为 `'Avatar'`,在保留无障碍支持的同时,减少装饰性或语境明确场景下的样板代码。
**新能力:**
```tsx
import { Avatar } from "heroui-native";
JD
;
```
显式传入 `alt` 的既有代码继续正常工作——该属性仅在缺省时获得一个合理的默认值。`RootProps` 类型现已反映为 `alt?: string`,并通过 JSDoc 标注 `@default 'Avatar'`,组件文档同步更新。
**相关 PR:** [#404](https://github.com/heroui-inc/heroui-native/pull/404)
## 样式修复
### Button、Chip、Input 样式微调
对 [Button](/docs/native/components/button)、[Chip](/docs/native/components/chip)、[Input](/docs/native/components/input) 的尺寸与色彩样式进行了微调,统一改用 Tailwind 工具类与语义化的 soft 颜色令牌。
**修复:**
* **Button**:尺寸改用 Tailwind 高度工具类(`h-10`、`h-12`、`h-14`),不再使用任意像素值;`sm` 高度由 36px 调整为 40px,提升触控目标的人体工学
* **Chip**:`md`/`lg` 的垂直内边距微调(`py-[3px]` → `py-1`,`py-1` → `py-1.5`),间距更协调
* **Chip**:soft 变体改用语义化 `bg-{color}-soft` 令牌,取代基于不透明度的 `bg-{color}/15` 背景
* **Input**:由 `py-3.5` 改为 `min-h-12`,无论内容如何字段都保持稳定高度
* **Input**:primary 变体的边框现正确使用 `border-field-border` 令牌,而非 `border-field`
Button `sm` 尺寸(+4px)与 Chip `md`/`lg` 内边距上的像素级差异建议进行视觉回归确认。无 API 变更——仅更新了 `button.styles.ts`、`chip.styles.ts`、`input.styles.ts` 中的样式令牌。
**相关 PR:** [#406](https://github.com/heroui-inc/heroui-native/pull/406)
### TextField 与 SearchField 内部内边距修复
[TextField](/docs/native/components/text-field) 与 [SearchField](/docs/native/components/search-field) 不再对嵌套的 `Label`、`Description`、`FieldError` 施加额外的水平内边距。
**修复:**
* `TextField` 现在向其 `FormFieldContext` 提供 `hasFieldPadding: false`
* `SearchField` 现在向其 `FormFieldContext` 提供 `hasFieldPadding: false`
* 渲染在上述字段内的 `Label`、`Description`、`FieldError` 不再继承额外的 `px-1.5` 侧边距
* 所有表单字段容器(`ControlField`、`RadioGroup`、`TagGroup` 已采用 `hasFieldPadding: false`)的视觉对齐现已统一
此次变更仅涉及两处为 `FormFieldContext` 提供值的 `useMemo`。如果你此前依赖这一非预期的内部内边距,可通过为受影响的子组件添加 `className="px-1.5"` 恢复原有间距。
**相关 PR:** [#407](https://github.com/heroui-inc/heroui-native/pull/407)
## 问题修复
本版本包含以下修复:
* **[Issue #334](https://github.com/heroui-inc/heroui-native/issues/334)**:修复 RTL 布局下 `Tabs.Indicator` 的定位错乱。指示器以绝对定位 `left` 锚点配合测量的 `translateX` 实现位移;在 RTL 模式下 React Native 会自动翻转锚点,但测量得到的 transform 仍需手动镜像。tabs 测量上下文现会跟踪标签条宽度,仅当 `I18nManager.isRTL` 启用时镜像 `translateX`,固定与滚动两类标签列表均已修复。
* **[Issue #393](https://github.com/heroui-inc/heroui-native/issues/393)**:修复 `ScrollShadow` 忽略子组件 `inverted` 属性的问题。`ScrollShadowRoot` 现会读取可滚动子组件上的 `inverted`(沿用既有的 `childHorizontal` 自动检测),并交换驱动各视觉边缘的动画样式,使反向 feed 与聊天式列表上的渐变出现在正确的一侧。
**相关 PR:**
* [#396](https://github.com/heroui-inc/heroui-native/pull/396)
* [#398](https://github.com/heroui-inc/heroui-native/pull/398)
## 文档更新
以下文档页面已随本版本更新:
* [Text](/docs/native/components/text) — 新组件文档,含结构、用法与完整 API 参考
* [Avatar](/docs/native/components/avatar) — `alt` 属性记为可选,默认值 `'Avatar'`
* [组件总览](/docs/native/components) — 在既有分类外新增 Typography 分类
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# v1.0.4
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/v1-0-4
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/v1-0-4.mdx
> Typography 组件替代 Text、调整后的柔和前景色主题令牌与可选鲜亮配色、iOS 原生模态偏移说明、示例应用升级至 Expo 56 / React Native 0.85
2026 年 5 月 26 日
HeroUI Native v1.0.4 将排版基元 `Text` 重命名为 `Typography`,让出 React Native 自身的 `Text` 名称,同时更贴近语义化排版用法;既有的 `Text` 导出保留为弃用别名,可平滑升级。本版本还在 Alert、Avatar、Button、Chip、Toast 中调整了 soft 前景色令牌,使其在 soft 背景上具备更好的对比度;新增可选的 `heroui-native/styles/vibrant` 配色;为 Menu、Popover、Select 补充 iOS 原生模态偏移的处理说明;并将示例应用升级到 Expo 56 / React Native 0.85。
## 安装
升级到最新版本:
```bash
npm i heroui-native
```
```bash
pnpm add heroui-native
```
```bash
yarn add heroui-native
```
```bash
bun add heroui-native
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 真机体验
## 新增
### Typography 组件(由 `Text` 重命名而来)
库内的排版基元已从 `Text` 重命名为 `Typography`,避免与 React Native 内建的 `Text` 重名,并更准确地体现其作为语义化排版系统的定位。组件的 API、变体与行为保持不变——只是公开名称发生变化。
```tsx
import { Typography } from "heroui-native";
import { View } from "react-native";
export function Example() {
return (
Welcome
Getting Started
This is a body paragraph rendered with the Typography component.
Smaller supporting text for captions or footnotes.
npm install heroui-native
);
}
```
**变更要点:**
* 主导出改为 `Typography`,子组件为 `Typography.Heading`、`Typography.Paragraph`、`Typography.Code`
* 新增 `typographyClassNames` 样式 API 与 `Typography*` 类型别名,取代原先的 `Text*` 命名
* 既有的 `Text`、`textClassNames` 与 `Text*` 类型作为**弃用**的重导出保留以兼容旧代码
* 组件目录中的示例页由 `text` 重命名为 `typography`
* JSDoc 与组件文档更新为引用 Typography 以及新的文档 URL
**无需迁移。** 既有的 `import { Text } from "heroui-native"` 通过弃用重导出仍然可用。请在未来某个大版本移除弃用别名之前,按你的节奏迁移到 `Typography`。
**相关 PR:** [#417](https://github.com/heroui-inc/heroui-native/pull/417)
### 鲜亮主题配色(可选)
新增可选的 `heroui-native/styles/vibrant` 样式表,适合希望在 soft 变体上保持更饱和品牌色的应用。它在保留调整后的柔和前景令牌带来的可读性改进的同时,仍为 soft 背景上的图标与文字保留较高的色彩饱和度。
**用法:**
```ts
// 默认调整后的柔和前景配色
import "heroui-native/styles";
// 或者,启用鲜亮配色
import "heroui-native/styles";
import "heroui-native/styles/vibrant";
```
在引入基础样式之后再引入 `heroui-native/styles/vibrant`,即可用更饱和的取值覆盖柔和前景令牌。无需修改任何组件代码即可启用。
**相关 PR:** [#420](https://github.com/heroui-inc/heroui-native/pull/420)
## 组件改进
### 多组件柔和前景色调整
[Alert](/docs/native/components/alert)、[Avatar](/docs/native/components/avatar)、[Button](/docs/native/components/button)、[Chip](/docs/native/components/chip)、[Toast](/docs/native/components/toast) 现使用新的 `*-soft-foreground` 主题令牌渲染 soft 背景上的标签与图标,呈现更好的对比度,并在亮色与暗色主题下保持更统一的视觉效果。
**改进点:**
* `theme.css` 中通过 `color-mix` 计算柔和前景令牌(`accent-soft-foreground`、`success-soft-foreground`、`warning-soft-foreground`、`danger-soft-foreground`、`default-soft-foreground`),提升 soft 背景上的可读性
* Alert、Avatar、Button、Chip、Toast 的样式(及其内部 hooks)改为使用新的柔和前景令牌,不再直接使用 `text-accent`、`text-success` 等原始语义色
* 新增可选的 `heroui-native/styles/vibrant` 导出,为希望保留饱和品牌色的应用保留更鲜亮的 soft 变体外观
* 示例应用中 Alert、Avatar、Button、Chip、Toast 的演示同步更新以匹配新的取色方式
组件属性与公开 API 均无变化——仅 soft 变体的取色发生变化。沿用默认主题的应用将开箱获得 soft 变体上更柔和、可读性更佳的图标与标签颜色。
**相关 PR:** [#420](https://github.com/heroui-inc/heroui-native/pull/420)
### TextArea 垂直内边距修复
[TextArea](/docs/native/components/text-area) 现已应用合适的内部垂直内边距,多行内容不再紧贴输入区上边缘。
**改进点:**
* `TextArea` 现使用 `h-32 py-2`,提供一致的内部间距
* 无 API 变更——仅为组件内的样式调整
**相关 PR:** [#421](https://github.com/heroui-inc/heroui-native/pull/421)
## API 增强
### `useThemeColor` 令牌更新
[`useThemeColor`](/docs/native/hooks/use-theme-color) hook 新增表面色与柔和色相关令牌,并对遮罩背景令牌进行了重命名以更清晰表达语义。
**新能力:**
```tsx
import { useThemeColor } from "heroui-native";
const colors = useThemeColor([
"default-soft",
"default-soft-foreground",
"surface-foreground",
"backdrop",
]);
```
**变更:**
* 新增 `default-soft` 与 `default-soft-foreground` 令牌
* 新增表面前景色令牌(如 `surface-foreground`),可显式取用表面文字颜色
* 将 `overlay-backdrop` 重命名为 `backdrop`,与底层 CSS 变量命名保持一致
如果你使用了已移除的 `useThemeColor` 键(`on-surface-*`)或旧的 `overlay-backdrop` 键,请改用更新后的令牌名。组件属性与视觉默认值保持不变。
**相关 PR:** [#420](https://github.com/heroui-inc/heroui-native/pull/420)
## 依赖
### `@gorhom/bottom-sheet` 对等依赖范围更新
`@gorhom/bottom-sheet` 的对等依赖范围由 `^5.2.8` 升级到 `^5.2.9`。如果你的应用使用 HeroUI Native 的 [BottomSheet](/docs/native/components/bottom-sheet)(或 `Menu` / `Popover` / `Select` 配合 `presentation="bottom-sheet"`),请确保安装兼容版本:
```bash
npm i @gorhom/bottom-sheet@^5.2.9
```
这是本版本对消费者唯一的对等依赖变更。库的 `react`(`>=19.0.0`)与 `react-native`(`>=0.81.0`)对等依赖范围保持不变。
**相关 PR:** [#421](https://github.com/heroui-inc/heroui-native/pull/421)
### 示例应用升级至 Expo 56 / React Native 0.85
仓库内的示例应用升级到了最新的 Expo 与 React Native 工具链。这不会直接影响库的消费者,但为运行示例的贡献者带来收益:
* Expo `56`
* React Native `0.85.3`
* React `19.2.3`
* React Native Reanimated `4.3.1`
* `react-native-worklets` `0.8.3`
* Uniwind `^1.6.3`
本次升级还包含以下整理:
* 重写 `metro.config.js`,将对等依赖解析锁定到示例的 `node_modules`,修复当 `uniwind` 或 `react` 从 workspace 根解析出两份副本时 Hermes 抛出的「Maximum call stack size exceeded」崩溃
* 在 input-otp 与展示页中以 `StyleSheet.absoluteFill` 替换已弃用的 `StyleSheet.absoluteFillObject`
* 将 `useFocusEffect` / `useHeaderHeight` 的导入迁移至 `expo-router`
* 移除未使用的 `example/src/components/safe-area-view.tsx`、`eas.json` 以及陈旧的 `newArchEnabled` / `edgeToEdgeEnabled` 标记
* 示例应用的 slug/bundle 重命名为 `heroui-native-oss`;调整 Android 上 `WithStateToggle` 的内边距
**相关 PR:** [#421](https://github.com/heroui-inc/heroui-native/pull/421)
## 文档
### Menu、Popover、Select 的 iOS 原生模态偏移说明
[Menu](/docs/native/components/menu)、[Popover](/docs/native/components/popover)、[Select](/docs/native/components/select) 文档新增\*\*原生模态(iOS)\*\*章节,解释当触发器位于以原生模态(`presentation: "modal" | "formSheet" | "pageSheet"`)呈现的页面内时,遮罩内容为何会向上偏移渲染,以及如何补偿。
**改进点:**
* 各组件文档说明了 Fabric / `FullWindowOverlay` 的坐标不一致:触发器坐标相对于模态原点,而遮罩锚定在窗口
* 文档化了配合 `react-native-safe-area-context` 中 `useSafeAreaInsets` 使用的 `offset={insets.top}` 推荐方案
* 提供示例应用中相关文件(`popover-native-modal.tsx`、`select-native-modal.tsx`)的链接,便于查阅完整用法
**用法示例:**
```tsx
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { Popover } from "heroui-native";
const insets = useSafeAreaInsets();
{/* ... */}
;
```
这是纯文档变更,未改动任何 API 或运行时行为。
**相关 PR:** [#419](https://github.com/heroui-inc/heroui-native/pull/419)
## 问题修复
本版本包含以下修复:
* **[Issue #405](https://github.com/heroui-inc/heroui-native/issues/405)**:补充了在 React Navigation 原生模态中 `Menu` 渲染错位的处理方案。Menu 文档新增\*\*原生模态(iOS)\*\*章节,解释 Fabric / `FullWindowOverlay` 的坐标不一致,并演示如何用 `useSafeAreaInsets` 配合 `offset={insets.top}` 补偿。
* **[Issue #418](https://github.com/heroui-inc/heroui-native/issues/418)**:修复将示例应用升级到 Expo 56 后出现的 Hermes 崩溃(「Maximum call stack size exceeded」)及 `BottomSheet` 内容不可见的问题。示例的 `metro.config.js` 现已将对等依赖解析(`react`、`react-native`、`uniwind` 等)锁定到示例的本地 `node_modules`,防止从 workspace 根加载到重复副本。
**相关 PR:**
* [#419](https://github.com/heroui-inc/heroui-native/pull/419)
* [#421](https://github.com/heroui-inc/heroui-native/pull/421)
## 弃用
### `Text` 排版导出
`Text` 组件与相关导出现已**弃用**,推荐使用 `Typography`。既有导入仍可继续工作,不会产生运行时错误——仅会在 TypeScript / IDE 中提示弃用。请在未来某个大版本移除弃用别名之前完成迁移。
**弃用 → 推荐:**
```tsx
// 弃用(仍可用)
import { Text, textClassNames, type TextProps } from "heroui-native";
Welcome ;
// 推荐
import {
Typography,
typographyClassNames,
type TypographyProps,
} from "heroui-native";
Welcome ;
```
**相关 PR:** [#417](https://github.com/heroui-inc/heroui-native/pull/417)
## 文档更新
以下文档页面已随本版本更新:
* [Typography](/docs/native/components/typography) — 组件由 Text 重命名而来;完整 API、Anatomy 与用法已更新
* [Menu](/docs/native/components/menu) — 新增\*\*原生模态(iOS)\*\*章节,含 `offset={insets.top}` 方案
* [Popover](/docs/native/components/popover) — 新增\*\*原生模态(iOS)\*\*章节,含 `offset={insets.top}` 方案
* [Select](/docs/native/components/select) — 新增\*\*原生模态(iOS)\*\*章节,含 `offset={insets.top}` 方案
* [快速开始](/docs/native/getting-started/quick-start) — 可选对等依赖 `@gorhom/bottom-sheet` 更新到 `^5.2.9`
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# v1.0.5
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/v1-0-5
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/v1-0-5.mdx
> 拆分 border-field 令牌以修复宽度/颜色合并冲突、Typography 支持 Dynamic Type、Provider 级文本输入配置、单次挂载的弹层动画、Select 图标颜色修复、升级至 Expo 57 / RN 0.86
2026 年 7 月 2 日
HeroUI Native v1.0.5 通过将字段边框拆分为独立的宽度与颜色令牌,并全局配置 `tailwind-variants`,解决了长期存在的 `border-field` 合并冲突,同时将 Input、InputOTP、Radio、Checkbox 迁移到基于 outline 的聚焦、激活与无效状态。本版本还为 Typography 带来 iOS Dynamic Type 支持,新增 Provider 级的文本输入配置,重构 Popover、Menu、Select 的进入动画以让内容仅挂载一次,将 Select 勾选图标与 `accent-soft-foreground` 令牌对齐,并将工具链升级至 Expo 57 / React Native 0.86。
## 安装
升级到最新版本:
```bash
npm i heroui-native
```
```bash
pnpm add heroui-native
```
```bash
yarn add heroui-native
```
```bash
bun add heroui-native
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 真机体验
## 性能
### 单次挂载的 Popover、Menu、Select 动画
[Popover](/docs/native/components/popover)、[Menu](/docs/native/components/menu)、[Select](/docs/native/components/select) 的内容现在只挂载一次,并在完成测量与定位后通过共享值播放进入动画。此前,内容子树会被挂载两次——先用一个隐藏探针测量尺寸,再挂载可见节点——以便进入 Keyframe 能在正确位置于挂载时触发。
**改进点:**
* 默认的进入动画由一个共享值(`rEnteringStyle`)驱动,在内容完成定位(`isReady`)后播放,使子树仅挂载一次
* `usePopupPopoverContentAnimation` 现返回 `isDrivenEntering` 与 `rEnteringStyle`,其位移、缩放与不透明度均由一个进度值插值得出
* 内容在就绪之前对指针事件保持隐藏;禁用动画时直接解析为显示状态
* 自定义的进入 Keyframe 仍保留原先的「探针 + 挂载」回退路径
组件的公开 API 未变——单次挂载路径完全是内部实现,自定义进入动画的行为与之前完全一致。建议在全部四个放置方向、子菜单过渡以及禁用动画的情形下,验证进入与退出动画。
**相关 PR:** [#438](https://github.com/heroui-inc/heroui-native/pull/438)
## 组件改进
### Typography Dynamic Type 支持(iOS)
[Typography](/docs/native/components/text) 组件现在会按语义类型应用默认的 `dynamicTypeRamp`,使文本在 iOS 上以符合 Apple 设计意图的方式缩放。较大的类型(如标题)比正文缩放得更慢,与 iOS 系统的 Dynamic Type 行为一致。此前,所有 Typography 组件中的文本都以相同的系数缩放。
**改进点:**
* 每个 Typography 类型都映射到合适的 iOS Dynamic Type ramp(例如标题映射到 `title` ramp,段落映射到 `body`)
* 在 iOS 上提升无障碍与文本缩放的保真度,对 Android 无影响
* 在需要不同 ramp 的场景下,可按实例覆盖 `dynamicTypeRamp` 默认值
此变更仅针对 iOS,不改动 Typography 的 API。已直接传入 `dynamicTypeRamp` 的应用仍会显式控制缩放行为。
**相关 PR:** [#435](https://github.com/heroui-inc/heroui-native/pull/435)
### Select 勾选图标颜色
[Select](/docs/native/components/select) 组件的 `Select.ItemIndicator` 现在将其勾选图标颜色默认为 `accent-soft-foreground` 主题令牌,而非 `accent`,使选中项指示器与预期的语义前景色对齐,从而获得更好的对比度与视觉一致性。
**改进点:**
* 默认勾选图标颜色改用 `accent-soft-foreground`,提升选中列表项的对比度
* JSDoc 与组件文档已同步更新以反映新的默认值
仅在省略 `iconProps.color` 时默认图标颜色会发生变化——API 未变,自定义颜色仍然有效。建议在亮色与暗色主题下进行手动验证,以确认指示器对比度。
**相关 PR:** [#436](https://github.com/heroui-inc/heroui-native/pull/436)
## API 增强
### Provider 文本输入配置
[HeroUINativeProvider](/docs/native/getting-started/provider)(以及 `HeroUINativeProviderRaw`)现可通过新的 `textInputProps` 配置在全局配置一部分 `TextInput` 属性,首批支持 `allowFontScaling` 与 `maxFontSizeMultiplier`。这与既有的全局 `textProps` 模式保持一致,使整个应用的输入字体缩放行为保持统一。
**新能力:**
```tsx
import { HeroUINativeProvider } from "heroui-native";
export function App() {
return (
{/* Your app */}
);
}
```
**包含内容:**
* 在 `HeroUINativeConfig` 与 `HeroUINativeConfigRaw` 上新增 `textInputProps` 配置(`allowFontScaling`、`maxFontSizeMultiplier`)
* 新增 `TextInputComponentProvider` / `useTextInputComponent` 以及一个 `HeroTextInput` 辅助组件,将全局属性作为可覆盖的默认值应用
* 已应用于 `Input`(因此涵盖 `TextArea`、`SearchField`、`InputGroup`)以及 `InputOTP` 基元
全局属性作为默认值应用,因此任何直接传给组件的属性仍会覆盖它们。
**相关 PR:** [#437](https://github.com/heroui-inc/heroui-native/pull/437)
## 依赖
### 升级至 Expo 57 / React Native 0.86
项目已升级到 Expo 57 / React Native 0.86 工具链。本次升级还通过包裹内容节点来修复遮罩退出动画,使布局动画不再与动画样式共享 transform,恢复 Android 输入聚焦环,并强化了 Pressable 样式回调的类型。
**修复:**
* 将 Popover、Menu、Select 的 `entering` / `exiting` 布局动画移到包裹用的 `Animated.View` 上,以修复退出动画并消除 Reanimated 的布局动画覆盖警告
* 在 Android 上使用边框显示输入聚焦环,iOS 仍保留 outline 方案
* 通过移除 `scale` transform 简化默认的退出 keyframe
* 为 button 与子菜单的样式回调添加显式的 `PressableStateCallbackType` 类型
**依赖升级:**
* Expo `57`
* React Native `0.86`
* React Native Reanimated `4.5`
* `react-native-worklets` `0.10`
* Tailwind CSS `4.3`
* Uniwind `1.10`
公开 API 未变,但消费者应将其对等依赖版本与 Expo 57 / React Native 0.86 对齐。建议在 iOS 与 Android 上手动测试遮罩的打开/关闭动画以及输入聚焦状态。
**相关 PR:** [#439](https://github.com/heroui-inc/heroui-native/pull/439)
## ⚠️ 破坏性变更
### 将 `border-field` 拆分为独立的宽度与颜色令牌
此前,`border-field` 会以同一名称同时生成宽度与颜色两个工具类,导致 `tailwind-merge` 丢弃宽度。字段组件硬编码了边框宽度(`border`、`border-[1.5px]`),并使用 border-color 表示聚焦与无效状态。v1.0.5 将字段边框拆分为两个互不冲突的工具类,并全局配置 `tailwind-variants`,使宽度与颜色在合并时不再相互覆盖。
**变更内容:**
* `border-field-width`(宽度)与 `border-field-border`(颜色)现在是独立、互不冲突的工具类
* `tv` / `cn` 使用一个共享的 `twMergeConfig`(`border-w` 分组)进行配置并全局注册;所有 `*.styles.ts` 均从 lib 导入 `tv`
* Input、InputOTP、Radio、Checkbox 使用 `border-field-width` 与 `outline-*` 表示聚焦、激活与无效状态;无效 outline 现在在静止状态下即显示
* `--field-radius` 系数由 `1.5` 改为 `1.75`
组件的公开 API 未变,但视觉与行为上的变化需要验证。请在你的应用中确认以下事项:
**迁移:**
仅通过 `--field-border` 颜色设置的边框将不再显示——`--field-border-width` 现在默认为 `0px`,因此需要同时设置宽度:
```tsx
// 之前——仅设置颜色即可渲染出可见边框
// --field-border: ;
// 之后——还需设置宽度,因为 --field-border-width 默认为 0px
// --field-border: ;
// --field-border-width: 1.5px;
```
直接使用字段边框宽度工具类时,请重命名:
```tsx
// 之前
// 之后
```
**同时请验证:**
* 聚焦、激活与无效状态现在使用 `outline-*` 而非 border-color
* 对 `--border-width-field` 主题键的覆盖必须改用 `--border-width-field-width`(或 `--field-border-width` 基元)
* 字段圆角略有变化(`--field-radius` 系数由 `1.5` → `1.75`)
如果你依赖 `--field-border` 颜色来产生静止状态的边框,请设置一个非零的 `--field-border-width` 默认值以恢复该外观。
**相关 PR:** [#434](https://github.com/heroui-inc/heroui-native/pull/434)
## 文档更新
以下文档页面已随本版本更新以反映相关变更:
* [Typography](/docs/native/components/text) — 记录了 iOS 上默认的 `dynamicTypeRamp` 行为
* [Select](/docs/native/components/select) — 更新了 `Select.ItemIndicator` 默认勾选图标颜色
* [Provider](/docs/native/getting-started/provider) — 新增 `textInputProps` 章节、示例与 Provider 层级说明
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# v1.0.6
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/v1-0-6
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/v1-0-6.mdx
> 将组件样式迁移到专用的 BEM 命名 CSS 文件,并通过按名称为 Portal 子树设置 key 修复 PortalHost 幽灵弹层问题
2026 年 7 月 21 日
HeroUI Native v1.0.6 通过将每个组件从内联 Tailwind 类名字符串迁移到 `src/styles/components` 下专用的 BEM 命名 CSS 文件来集中管理样式,同时让 `tv()` 插槽仅作为对这些类的轻量引用,从而更易于覆盖与维护。本版本还修复了一个 `PortalHost` 协调(reconciliation)缺陷:在不同屏幕间,Sheet、Dialog 与 Popover 可能会相互继承彼此的状态——产生「幽灵」状态的已打开 Sheet——现在通过按唯一名称为每个 Portal 子树设置 key 来解决该问题。
## 安装
升级到最新版本:
```bash
npm i heroui-native
```
```bash
pnpm add heroui-native
```
```bash
yarn add heroui-native
```
```bash
bun add heroui-native
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 真机体验
## 样式
### 组件样式迁移到专用的 CSS 类
每个组件的样式已从各个 `*.styles.ts` 文件中冗长的内联 Tailwind 类名字符串,迁移到 `src/styles/components` 下专用的 BEM 命名 CSS 文件,并通过 `src/styles/index.css` 接入。`tv()` 插槽现在仅作为对这些 CSS 类的轻量引用,从而集中管理样式,使组件更易于覆盖与维护。
**改进点:**
* 将全部约 40 个组件的样式抽取为 BEM 结构的 `.css` 文件,并通过 `src/styles/index.css` 接入
* 让 `tv()` 插槽仅作为对新 CSS 类的轻量引用,而非内联 Tailwind 字符串
* 新增 `element-disabled` 工具类
* 清理相关的工具类与依赖
组件的公开 API 未变,因此无需修改代码。消费者需确保已加载 `src/styles/index.css`,组件才能正确渲染。
**相关 PR:** [#452](https://github.com/heroui-inc/heroui-native/pull/452)
## 问题修复
### PortalHost 幽灵 Sheet
`PortalHost` 此前将所有已注册的 Portal 渲染为一个未设置 key 的数组,因此 React 会按索引进行协调。当某个 Portal 在列表中途注册或注销时——例如某个屏幕卸载时——相邻的 Portal 索引会发生偏移,导致 React 把一个 Portal 的实时组件状态嫁接到另一个 Portal 的内容上。对于底部 Sheet 而言,这会让其继承内部 Sheet 实例及其动画位置,于是一个已关闭的 Sheet 可能显示为完全打开(「幽灵」Sheet),而一个已打开的 Sheet 则可能继承到已关闭的实例而始终无法显示。
现在每个 Portal 子树都按其唯一的 Portal 名称设置 key,因此 React 会按身份而非数组位置来追踪 Portal。这修复了 `BottomSheet`、`Dialog`、`Popover` 与 `Select` 各类 Portal 上的幽灵 Sheet 行为,也很可能是底部 Sheet 间歇性无法显示的根因。
本版本包含针对以下问题的修复:
* **[Issue #441](https://github.com/heroui-inc/heroui-native/issues/441)**:修复 `PortalHost` 将 Portal 渲染为未设置 key 的数组的问题——当某个屏幕卸载时,会导致 Sheet 与 Dialog 相互继承状态,从而出现显示无关内容的「幽灵」已打开 Sheet。现在 Portal 按名称设置 key,使每个子树都按身份被追踪。
**相关 PR:** [#442](https://github.com/heroui-inc/heroui-native/pull/442)
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# v1.0.7
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/v1-0-7
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/v1-0-7.mdx
> 通过全新的 background 属性实现可替换的背景层,新增 GlassView 层组件,为 Dialog 与 Bottom Sheet 提供 blur 遮罩变体,Select 触发器改为字段样式,Toast 迁移至 overlay 令牌
2026 年 7 月 28 日
HeroUI Native v1.0.7 让组件表面变得可扩展:组件现在接受 `background` 属性,并暴露配套的背景复合部件,从而可将表面后方的层替换为任意节点。本版本还新增 `GlassView` 层组件、用于 Dialog 与 Bottom Sheet 的 `blur` 遮罩变体,并将 `expo-blur` 作为可选的对等依赖。这些都是扩展点——默认主题不注册任何背景内容,因此渲染结果不变。
## 安装
升级到最新版本:
```bash
npm i heroui-native
```
```bash
pnpm add heroui-native
```
```bash
yarn add heroui-native
```
```bash
bun add heroui-native
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 真机体验
## 新特性
### 可替换的背景层
组件此前会直接依据主题令牌渲染固定的不透明表面。在 v1.0.7 中,拥有表面的部件接受 `background` 属性,并暴露以其所背衬元素命名的背景复合部件。传入节点即可替换该层,或传入 `null` 将其移除。
```tsx
import { Button, GlassView } from "heroui-native";
}
>
Save changes
// 完全移除该层
Save changes
```
属性与部件配对规律清晰——`background` 位于 Button、Avatar、Switch、Chip、Checkbox、Input 与 SubMenu 的根组件上,位于 `Radio.Indicator`、`Slider.Track`、`Tabs.List`、`TagGroup.Item`、`InputOTP.Slot` 与 `Popover.Content` 的子部件上,其对应部件分别为 `Radio.IndicatorBackground`、`Slider.TrackBackground`、`Tabs.ListBackground`、`TagGroup.ItemBackground`、`InputOTP.SlotBackground` 与 `Popover.ContentBackground`。每个背景容器都是绝对填充视图,继承宿主元素的定位与裁剪,并接受 `fallbackColor` 主题令牌用于不支持原生模糊的平台。
是否挂载默认层由 `--theme` CSS 变量决定,可使用 `useIsGlassTheme` 与 `useHasDefaultThemeBackground` 检测这一情况。HeroUI Native 附带的主题不注册任何背景内容,因此除非你自行注入,否则不会渲染任何内容;用于激活这些层的 `glass` 主题由 `heroui-native-pro/themes/glass` 提供。
**相关 PR:** [#457](https://github.com/heroui-inc/heroui-native/pull/457)
## ⚠️ 破坏性变更
### Select 触发器改为字段外观
`.select__trigger--variant-default` 在**所有**主题上从表面外观改为字段外观——此变更不受 `--theme` 限制。如果你依赖 Select 触发器与周围的 `Surface` 元素保持一致,它现在会转而与你的表单字段保持一致。
**变更内容:**
* `--radius-2xl` → `--radius-field`
* `--color-surface` → `--color-field`
* `--shadow-surface` → `--shadow-field`
* 新增 `--color-field-border` 边框
**迁移:**
无需修改 API。若要恢复此前的表面外观,请覆盖 [Select](/docs/native/components/select) 触发器的样式:
```tsx
// 之前——触发器默认使用 surface 令牌渲染
// 之后——显式恢复表面外观
```
**相关 PR:** [#457](https://github.com/heroui-inc/heroui-native/pull/457)
### Toast 遮罩令牌切换
`.toast__root` 从 `--color-surface` 改为 `--color-overlay`,其默认标签颜色从 `--color-foreground` 改为 `--color-overlay-foreground`。
在附带的主题中,这些令牌在亮色(`--white`)与暗色(`oklch(0.2103 0.0059 285.89)`)模式下都解析为相同的值,因此开箱即用**没有可见变化**。只有当你将 `--surface` 与 `--overlay`——或 `--foreground` 与 `--overlay-foreground`——覆盖为不同的值时才会有影响,此时 [Toast](/docs/native/components/toast) 会转而采用你的 overlay 值而非 surface 值。
**迁移:**
如果你曾为 Toast 自定义 `--surface`,请将该自定义移至 `--overlay`,或直接覆盖 Toast 类:
```tsx
// 之前——Toast 跟随 --surface / --foreground
// 之后——Toast 跟随 --overlay / --overlay-foreground
```
**相关 PR:** [#457](https://github.com/heroui-inc/heroui-native/pull/457)
## 更新的文档
以下文档页面已更新,以反映本版本的变更:
* [Dialog](/docs/native/components/dialog) - 记录 `blur` 遮罩变体与 `blurViewProps`
* [Bottom Sheet](/docs/native/components/bottom-sheet) - 记录 `blur` 遮罩变体与 `blurViewProps`
* 为 [Button](/docs/native/components/button)、[Avatar](/docs/native/components/avatar)、[Checkbox](/docs/native/components/checkbox)、[Chip](/docs/native/components/chip)、[Input](/docs/native/components/input)、[InputOTP](/docs/native/components/input-otp)、[Menu](/docs/native/components/menu)、[Radio Group](/docs/native/components/radio-group)、[Slider](/docs/native/components/slider)、[Switch](/docs/native/components/switch)、[Tabs](/docs/native/components/tabs) 与 [TagGroup](/docs/native/components/tag-group) 新增背景层文档
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# v1.0.8
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/v1-0-8
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/v1-0-8.mdx
> 通过 provider 的 isRTL 配置与 LayoutDirectionScope 为各组件提供从右到左(RTL)布局支持,随包发布的样式表自行声明 @source,并调整 Card.Header 与 TagGroup.List 的布局
2026 年 7 月 31 日
HeroUI Native v1.0.8 为整个库带来从右到左(RTL)布局支持。组件样式从物理的 `left`/`right` 迁移到 Yoga 的逻辑属性,而 Yoga 无法覆盖的 JS 驱动逻辑——手势位移、动画偏移、弹层对齐——现在通过全新的 `isRTL` provider 配置解析方向,并提供 `LayoutDirectionScope` 作为子树的应急出口。本版本还让 `heroui-native/styles` 自行声明 `@source`,因此类名扫描不再依赖于应用中硬编码的 `node_modules` 路径。
## 安装
升级到最新版本:
```bash
npm i heroui-native
```
```bash
pnpm add heroui-native
```
```bash
yarn add heroui-native
```
```bash
bun add heroui-native
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 真机体验
## 新特性
### RTL 布局支持
当你的应用在从右到左的区域设置下运行时,组件现在会正确镜像。组件 CSS 全面采用逻辑属性(`inset-inline-*`、`padding-inline-*`、`start`/`end`),因此 Yoga 可在两个方向上处理定位;而 Yoga 无法表达的行为——手势位移、动画偏移、遮罩对齐——则从 provider 读取有效方向。
**告诉组件它们渲染在哪个方向:**
`HeroUINativeProvider` 接受 `config.isRTL`,默认为 `I18nManager.isRTL`:
```tsx
import { HeroUINativeProvider } from 'heroui-native';
import type { HeroUINativeConfig } from 'heroui-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
const config: HeroUINativeConfig = {
// 默认为 I18nManager.isRTL
isRTL: true,
};
export default function App() {
return (
{/* 你的应用内容 */}
);
}
```
由于默认值已跟随 `I18nManager.isRTL`,依赖原生 RTL 标志的应用无需任何修改。当方向来自其他来源时才需显式设置——例如无需重载即可切换方向的运行时区域切换器。
**将子树限定为不同方向:**
新导出的 `LayoutDirectionScope` 会覆盖其下方组件的方向,这正是你在从右到左应用中希望某个演示或预览区域保持从左到右时所需要的。它只覆盖 JavaScript 一侧,因此需搭配 Uniwind 的 `LayoutDirection`(用于 `rtl:` 变体)以及 `direction` 样式(用于 Yoga 布局):
```tsx
import { LayoutDirectionScope, PortalHost } from 'heroui-native';
import { LayoutDirection } from 'uniwind';
import { View } from 'react-native';
;
```
该作用域驱动发生在 JavaScript 中的方向读取:[Slider](/docs/native/components/slider) 的手势反转、[Skeleton](/docs/native/components/skeleton) 与 `SubMenu` 的动画偏移,以及 [Popover](/docs/native/components/popover) 与 [Menu](/docs/native/components/menu) 的 `start`/`end` 对齐。你自己的组件也可以通过新导出的 `useIsRTL` 钩子读取同一个值。
**Portal 会逃离作用域。** 通过 `Portal` 渲染的内容会挂载到应用根部,因此遮罩会回退到应用级方向。若要让它们保持在作用域内,请在作用域内渲染一个带自定义 `name` 的 [PortalHost](/docs/native/getting-started/portal)——如上所示——并将匹配的 `hostName` 传给遮罩。
**方向感知行为:**
* **[Slider](/docs/native/components/slider)**:点按与拖拽的位移会被反转,填充与滑块锚定到逻辑边缘
* **[Skeleton](/docs/native/components/skeleton)**:微光沿阅读方向扫过
* **[Switch](/docs/native/components/switch)**:滑块行程锚定在 `start`
* **[Tabs](/docs/native/components/tabs)**:指示器的重新定基以实际锚点交换为准,而非假定为左侧锚点
* **[Popover](/docs/native/components/popover) 与 [Menu](/docs/native/components/menu)**:`start`/`end` 对齐按方向解析
* **[InputGroup](/docs/native/components/input-group)**:测量得到的附加元素宽度以 `paddingStart`/`paddingEnd` 应用
* **[SearchField](/docs/native/components/search-field)、[ListGroup](/docs/native/components/list-group) 与 `SubMenu`**:默认的箭头与放大镜图标会镜像
**文本对齐:**
[Card](/docs/native/components/card)、[Dialog](/docs/native/components/dialog)、[Menu](/docs/native/components/menu)、[Select](/docs/native/components/select)、[Toast](/docs/native/components/toast)、[Label](/docs/native/components/label)、[Description](/docs/native/components/description)、[FieldError](/docs/native/components/field-error) 等组件中基于 `Text` 的部件在两个方向上都会对齐到起始边。`TextInput` 部件则获得显式的 `rtl:text-right`,因为 React Native 对 `TextInput` 的对齐是按物理方向而非逻辑方向解析的。
示例应用现在通过 Lingui 附带 `en`、`ar`、`he` 三套语言目录并配有运行时区域切换器,还加入了 `eslint-plugin-lingui` 以防止出现未翻译的字符串。本版本已在 iOS 与 Android 上针对全部三种区域设置进行手动验证,包括在从右到左的应用外壳内部限定为从左到右的预览。
**相关 PR:** [#459](https://github.com/heroui-inc/heroui-native/pull/459)
## 样式
### 随包发布的样式表自行声明 `@source`
`heroui-native/styles` 现在会将 Tailwind 指向它自身的文件:
```css
@source "..";
```
Tailwind v4 会相对于包含 `@source` 的 CSS 文件来解析它,因此在已发布的包中,`lib/module/styles/index.css` 会将扫描路径解析为 `lib/module`——无论包管理器将其安装在何处。
此前,每个应用都必须把一个指向 `node_modules` 的文件系统路径硬编码进来:
```css
/* 之前——应用必须知道包所在的位置 */
@import 'heroui-native/styles';
@source './node_modules/heroui-native/lib';
/* 之后——包自行声明其扫描路径 */
@import 'heroui-native/styles';
```
这两条指令的行为从来就不一致。`@import` 会经由包的 exports 解析,能在任何位置找到包;而 `@source` 是一个文件系统 glob,只有当包位于该字面路径时才有效。二者在单包应用中一致,但在工作区中会产生分歧——因为决定包落在哪个 `node_modules` 的是安装器,而非项目布局。Bun 的隔离链接器会把它放进应用中,其提升(hoisted)链接器会放到工作区根部,而 pnpm 与 yarn 也会因是否提升而各自分裂。
这种失败还是静默的:缺失的 `@source` 目录在 Tailwind 中是无操作,不会有任何警告或错误。应用级类名照常工作,而仅在 HeroUI 随包组件内部使用的类名却消失了,于是 Avatar 失去了尺寸、Switch 渲染为不可见、Popover 背景变为透明。
现有的应用级 `@source` 行仍可继续工作——它们只是变得多余,可以移除。
**相关 PR:** [#455](https://github.com/heroui-inc/heroui-native/pull/455)
## ⚠️ 破坏性变更
### Card.Header 将子元素对齐到起始边
`.card__header` 现在设置 `align-items: flex-start`,而不再继承默认的 `stretch`。交叉轴上的 `flex-start` 会跟随布局方向,这正是让头部内容在 RTL 下位于起始边的原因——但它也改变了 LTR 渲染:此前拉伸到整个头部宽度的头部子元素,现在会收缩包裹其内容。
**迁移:**
该变更位于 CSS 中,因此 `items-stretch` 可恢复此前的行为:
```tsx
// 之前——子元素拉伸到整个头部宽度
// 之后——显式恢复拉伸
```
**相关 PR:** [#459](https://github.com/heroui-inc/heroui-native/pull/459)
### TagGroup.List 应用内联布局样式
`TagGroup.List` 现在会接收一段内联样式(`width: '100%'`、`alignItems: 'flex-start'`),并在你传入的 `style` 之前合并,以规避 Yoga 的换行测量问题。内联样式优先于类名解析出的样式,因此对该部件在 `width` 或 `alignItems` 上的 `className` 覆盖将不再生效。
**迁移:**
将这两个属性从 `className` 移到 `style`,由于 `style` 在内部值之后合并,因此仍会胜出:
```tsx
// 之前——className 覆盖生效
// 之后——使用 style 设置 width 与 alignItems
```
对 [TagGroup](/docs/native/components/tag-group) 的其他 `className` 覆盖不受影响。
**相关 PR:** [#459](https://github.com/heroui-inc/heroui-native/pull/459)
## 问题修复
本版本包含以下问题的修复:
* **[Issue #454](https://github.com/heroui-inc/heroui-native/issues/454)**:修复了在 monorepo 布局下类名扫描失效的问题。`heroui-native/styles` 未为其自身文件声明 `@source`,因此应用必须把一个指向 `node_modules` 的路径硬编码进来,而该路径只在部分包管理器布局下才能解析——一旦出错,Tailwind 便什么都不扫描且静默失败,导致 HeroUI 组件在没有样式的情况下渲染。随包发布的样式表现在会声明相对于自身的扫描路径。
**相关 PR:**
* [#455](https://github.com/heroui-inc/heroui-native/pull/455)
## 内部变更
本版本还移除了循环模块依赖:`Surface` 上下文被拆分为一个叶子模块,共享的 `Toast` 配置被提取到 `toast.base-types`。仅内部导入路径发生变化——不影响任何公共 API。
**相关 PR:** [#459](https://github.com/heroui-inc/heroui-native/pull/459)
## 更新的文档
以下文档页面已更新,以反映本版本的变更:
* [Quick Start](/docs/native/getting-started/quick-start) - `global.css` 的配置不再包含 `@source` 行,基于路径的说明保留给 v1.0.7 及更早版本
* [Provider](/docs/native/getting-started/provider) - 记录 `isRTL` 配置项、`LayoutDirectionScope` 覆盖以及 `useIsRTL` 钩子
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# v1.0.9
**Category**: native
**URL**: https://heroui.com/cn/docs/native/releases/v1-0-9
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/native/releases/v1-0-9.mdx
> 字重通过 Uniwind 的 font-* 工具类解析,SearchField 仅为已组合的部件预留内边距,Toast 的 duration 0 会自动隐藏,修复 RNGH 3 下 Android 上 Select 与 Dialog 的滑动关闭
2026 年 8 月 31 日
HeroUI Native v1.0.9 重构了组件样式中字重的解析方式,修复了省略可选部件时 SearchField 的内边距问题,纠正了时长为零的 Toast 未自动关闭的行为,并恢复了 react-native-gesture-handler 3 下 Android 上 Select 与 Dialog 的滑动关闭。
## 安装
升级到最新版本:
```bash
npm i heroui-native
```
```bash
pnpm add heroui-native
```
```bash
yarn add heroui-native
```
```bash
bun add heroui-native
```
**使用 AI 助手?** 直接提示「Hey Cursor,把 HeroUI Native 升级到最新版本」,助手会自动比对版本并完成必要修改。了解更多请参见 [HeroUI Native MCP 服务器](/docs/native/getting-started/mcp-server)。
## 真机体验
## ⚠️ 破坏性变更
### Toast 的 `duration: 0` 现在会自动隐藏
`duration` 的类型为 `number | 'persistent'`,但由于自动关闭的判断要求 `duration > 0`,`0` 被静默地当作持久显示处理。时长为零的 Toast 现在与其他数值时长走同一条 `setTimeout` 路径,会在下一个 tick 关闭。
**之前:**
```tsx
toast.show({ label: 'Quick flash', duration: 0 });
// Toast 会一直停留在屏幕上——与 'persistent' 相同
```
**之后:**
```tsx
toast.show({ label: 'Quick flash', duration: 0 });
// Toast 会在下一个 tick 自动隐藏
// 若要让 Toast 一直停留在屏幕上,请使用 'persistent':
toast.show({ label: 'Sticky', duration: 'persistent' });
```
**迁移:** 如果你依赖旧行为,请将 `duration: 0` 替换为 `duration: 'persistent'`。
**相关 PR:** [#471](https://github.com/heroui-inc/heroui-native/pull/471)
### 使用自定义字体的应用必须定义 `--font-bold`
组件样式现在通过 Uniwind 的 `font-normal`、`font-medium`、`font-semibold` 与 `font-bold` 工具类应用字重。当定义了 `--font-*` 变量时,每个工具类会选择对应的字体族,而不再应用数值化的 `font-weight`。这修复了 iOS 会在自定义字体族中选中最粗字面的问题,但也意味着**只要定义了其中任意一个变量,就必须定义全部四个**。
**之前:**
```css
@theme {
--font-normal: 'YourFont-400Regular';
--font-medium: 'YourFont-500Medium';
--font-semibold: 'YourFont-600SemiBold';
}
```
**之后:**
```css
@theme {
--font-normal: 'YourFont-400Regular';
--font-medium: 'YourFont-500Medium';
--font-semibold: 'YourFont-600SemiBold';
--font-bold: 'YourFont-700Bold';
}
```
**迁移:** 补上缺失的 `--font-bold` 变量,指向该字体族的 bold 字面。使用系统字体的应用无需任何修改——未定义任何 `--font-*` 变量时会自动恢复数值化字重。
**相关 PR:** [#473](https://github.com/heroui-inc/heroui-native/pull/473)
## 问题修复
本版本包含以下问题的修复:
* **[Issue #465](https://github.com/heroui-inc/heroui-native/issues/465)**:即使省略了 SearchIcon 与 ClearButton,`SearchField.Input` 仍会为它们预留左右内边距。现在只有在组合了对应复合部件时才会应用内边距。
* **[Issue #444](https://github.com/heroui-inc/heroui-native/issues/444)**:在 react-native-gesture-handler 3 下的 Android 上,打开带滑动关闭的 Select 或 Dialog 会抛出异常,因为 Portal 内容在其原生祖先链中没有手势根节点。新增的内部 `PortalGestureRoot` 现在会包裹 Portal 对话框内容,使滑动关闭在 RNGH 3 的 Android 上正常工作。
* **LinkButton** 不再应用默认圆角(`rounded-none`),此前该圆角会在边缘裁切文本。
* **[Issue #476](https://github.com/heroui-inc/heroui-native/issues/476)**:嵌套了 `Radio` 的 `RadioGroup.Item` 会向辅助技术暴露两个 `role="radio"` 节点。位于分组项内部时,嵌套的触发器现在会对辅助技术隐藏,因此每个选项只呈现单个 radio 节点。
* **[Issue #467](https://github.com/heroui-inc/heroui-native/issues/467)**:使用 `content-fit` 或紧凑尺寸时,Select 触发器与选项的文本会被压缩。默认的 flex 样式改为 `flex-shrink: 1`,使文本既能贡献其固有宽度,又能在空间受限时收缩。
* **[Issue #461](https://github.com/heroui-inc/heroui-native/issues/461)**:自定义字体解析重构后,使用系统字体的应用丢失了数值化字重。未定义任何 `--font-*` 变量时,字重现在会回退到数值化的 `font-weight`。
**相关 PR:**
* [#481](https://github.com/heroui-inc/heroui-native/pull/481)
* [#480](https://github.com/heroui-inc/heroui-native/pull/480)
* [#474](https://github.com/heroui-inc/heroui-native/pull/474)
* [#477](https://github.com/heroui-inc/heroui-native/pull/477)
* [#468](https://github.com/heroui-inc/heroui-native/pull/468)
* [#473](https://github.com/heroui-inc/heroui-native/pull/473)
## 更新的文档
以下文档页面已更新,以反映本版本的变更:
* [Theming](/docs/native/getting-started/theming) - 记录 `--font-bold` 变量的必要性,并说明在使用与不使用自定义字体时字重如何解析
* [Typography](/docs/native/components/text) - 说明自定义 `--font-*` 字体族会改变字重的解析方式,并链接到主题定制指南
* [SearchField](/docs/native/components/search-field) - 明确 SearchIcon 与 ClearButton 为可选部件,并补充「不带搜索图标」的组合方式
* [Toast](/docs/native/components/toast) - 明确 `duration: 0` 与 `'persistent'` 的区别
## 链接
* [组件文档](../components)
* [GitHub 仓库](https://github.com/heroui-inc/heroui-native)
## 贡献者
感谢所有为本版本做出贡献的朋友!
# ButtonGroup 按钮组
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/button-group
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(buttons)/button-group.mdx
> 将相关按钮组合在一起,保持一致的样式与间距
## 用法
```tsx
import { ButtonGroup, Button } from '@heroui/react';
```
```tsx
import {
ChevronDown,
ChevronLeft,
ChevronRight,
CodeFork,
Ellipsis,
Picture,
Pin,
QrCode,
Star,
TextAlignCenter,
TextAlignJustify,
TextAlignLeft,
TextAlignRight,
ThumbsDown,
ThumbsUp,
Video,
} from "@gravity-ui/icons";
import {Button, ButtonGroup, Chip, Description, Dropdown, Label} from "@heroui/react";
export function Basic() {
return (
{/* 单个按钮与下拉菜单 */}
合并拉取请求
创建合并提交
此分支上的所有提交都将加入基础分支
压缩并合并
此分支上的 14 个提交将合并为一次提交并加入基础分支
变基并合并
此分支上的 14 个提交将变基后加入基础分支
{/* 独立按钮 */}
复刻
24
扫码支付
2.4K
星标
104
已置顶
{/* 上一页 / 下一页 */}
上一页
下一页
{/* 内容类型选择 */}
{/* 文本对齐 */}
左对齐
居中
右对齐
{/* 仅图标:对齐 */}
);
}
```
## 组件结构
```tsx
import { ButtonGroup, Button } from '@heroui/react';
export default () => (
First
Second
Third
);
```
> **ButtonGroup** 将多个 Button 组合在一起,应用一致的样式、间距与自动圆角处理。它通过 React Context 向所有子按钮传递 `size`、`variant` 与 `isDisabled` 属性。
## 示例
### 变体
```tsx
import {Button, ButtonGroup} from "@heroui/react";
export function Variants() {
return (
);
}
```
### 尺寸
```tsx
import {Button, ButtonGroup} from "@heroui/react";
export function Sizes() {
return (
);
}
```
### 方向
使用 `orientation` 属性可水平或垂直排列按钮。
```tsx
import {TextAlignCenter, TextAlignJustify, TextAlignLeft, TextAlignRight} from "@gravity-ui/icons";
import {Button, ButtonGroup} from "@heroui/react";
export function Orientation() {
return (
);
}
```
### 带图标
```tsx
import {Globe, Plus, TrashBin} from "@gravity-ui/icons";
import {Button, ButtonGroup} from "@heroui/react";
export function WithIcons() {
return (
);
}
```
### 宽度充满
```tsx
import {TextAlignCenter, TextAlignLeft, TextAlignRight} from "@gravity-ui/icons";
import {Button, ButtonGroup} from "@heroui/react";
export function FullWidth() {
return (
第一项
第二项
第三项
);
}
```
### 禁用状态
```tsx
import {Button, ButtonGroup} from "@heroui/react";
export function Disabled() {
return (
组已禁用,但单个按钮可覆盖
第一项
第二项
第三项(可用)
);
}
```
### 无分隔线
省略按钮中的 ` ` 组件即可。
```tsx
import {Button, ButtonGroup} from "@heroui/react";
export function WithoutSeparator() {
return (
第一项
第二项
第三项
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {ChevronDown} from "@gravity-ui/icons";
import {Button, ButtonGroup, Description, Dropdown, Label} from "@heroui/react";
export function CustomStyles() {
return (
合并拉取请求
创建合并提交
此分支的所有提交将添加到基础分支
压缩并合并
此分支的 14 个提交将在基础分支中合并为一个提交
变基并合并
此分支的 14 个提交将变基后添加到基础分支
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 ButtonGroup 组件类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.button-group {
@apply gap-2 rounded-lg;
}
.button-group__separator {
@apply opacity-25;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
ButtonGroup 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/button-group.css)):
#### 基础类 \[!toc]
* `.button-group` - 按钮组根容器
* `.button-group--full-width` - 全宽修饰符
* `.button-group__separator` - 按钮之间的分隔元素
ButtonGroup 组件自动为按钮应用圆角:
* 第一个按钮圆角左/起始边
* 最后一个按钮圆角右/结束边
* 中间按钮无圆角
* 单个按钮四边全圆角
在每个 Button 内(第一个除外)添加 ` ` 以显示分隔线。
## API 参考
### ButtonGroup
| Prop | 类型 | 默认值 | 描述 |
| ------------- | --------------------------------------------------------------- | -------------- | ------------------- |
| `variant` | `'primary' \| 'secondary' \| 'tertiary' \| 'ghost' \| 'danger'` | - | 应用于组内所有按钮的视觉变体 |
| `size` | `'sm' \| 'md' \| 'lg'` | - | 应用于组内所有按钮的尺寸 |
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | 按钮组方向 |
| `fullWidth` | `boolean` | `false` | 是否占满容器宽度 |
| `isDisabled` | `boolean` | `false` | 是否禁用组内所有按钮(单个按钮可覆盖) |
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `React.ReactNode` | - | 要组合的 Button 组件 |
### ButtonGroup.Separator
| Prop | 类型 | 默认值 | 描述 |
| ----------- | -------- | --- | -------- |
| `className` | `string` | - | 附加 CSS 类 |
## 说明
* ButtonGroup 通过 React Context 向所有子 Button 传递 `size`、`variant` 与 `isDisabled` 属性
* **仅直接子按钮接收 ButtonGroup 属性** - 嵌套在其他组件(如 Modal、Dropdown 等)内的 Button 即使位于 ButtonGroup 后代也不会继承组属性
* 单个 Button 可通过 `isDisabled={false}` 覆盖组的 `isDisabled` 属性
* 组件自动处理按钮之间的圆角
* 在每个 Button 内(第一个除外)添加 ` ` 以显示分隔线
* 组内按钮移除 active/pressed 缩放变换,外观更统一
## 相关组件
## Related Components
* **Button**: Allows a user to perform an action
* **Dropdown**: Context menu with actions and options
* **Chip**: Compact elements for tags and filters
# Button 按钮
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/button
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(buttons)/button.mdx
> 可点击的按钮组件,支持多种变体与状态
## 用法
```tsx
import { Button } from '@heroui/react';
```
```tsx
"use client";
import {Button} from "@heroui/react";
export function Basic() {
return console.log("按钮已按下")}>点我 ;
}
```
## 示例
### 变体
```tsx
import {Button} from "@heroui/react";
export function Variants() {
return (
主要
次要
第三
线框
幽灵
危险
柔和危险
);
}
```
### 尺寸
```tsx
import {Button} from "@heroui/react";
export function Sizes() {
return (
小
中
大
);
}
```
### 带图标
```tsx
import {Envelope, Globe, Plus, TrashBin} from "@gravity-ui/icons";
import {Button} from "@heroui/react";
export function WithIcons() {
return (
);
}
```
### 仅图标
```tsx
import {Ellipsis, Gear, TrashBin} from "@gravity-ui/icons";
import {Button} from "@heroui/react";
export function IconOnly() {
return (
);
}
```
### 加载中
```tsx
"use client";
import {Button, Spinner} from "@heroui/react";
import React from "react";
export function Loading() {
return (
{({isPending}) => (
<>
{isPending ? : null}
上传中…
>
)}
);
}
```
### 加载中(点击触发)
```tsx
"use client";
import {Paperclip} from "@gravity-ui/icons";
import {Button, Spinner} from "@heroui/react";
import React, {useState} from "react";
export function LoadingState() {
const [isLoading, setLoading] = useState(false);
const handlePress = () => {
setLoading(true);
setTimeout(() => setLoading(false), 2000);
};
return (
{({isPending}) => (
<>
{isPending ? : }
{isPending ? "上传中…" : "上传文件"}
>
)}
);
}
```
### 宽度充满
```tsx
import {Plus} from "@gravity-ui/icons";
import {Button} from "@heroui/react";
export function FullWidth() {
return (
);
}
```
### 禁用状态
```tsx
import {Button} from "@heroui/react";
export function Disabled() {
return (
主要
次要
第三
线框
幽灵
危险
);
}
```
### 社交媒体按钮
```tsx
import {Button} from "@heroui/react";
import {Icon} from "@iconify/react";
export function Social() {
return (
使用 Google 登录
使用 GitHub 登录
使用 Apple 登录
);
}
```
### 渲染函数
```tsx
"use client";
import {Button} from "@heroui/react";
export function RenderFunction() {
return (
(
)}
>
点按
);
}
```
### 添加自定义变体
可通过包装组件并添加自定义变体来扩展 HeroUI 组件。
```tsx
import type {ButtonProps} from "@heroui/react";
import type {VariantProps} from "tailwind-variants";
import {Button, buttonVariants} from "@heroui/react";
import {tv} from "tailwind-variants";
const myButtonVariants = tv({
base: "text-md font-semibold shadow-md text-shadow-lg data-[pending=true]:opacity-40",
defaultVariants: {
radius: "full",
variant: "primary",
},
extend: buttonVariants,
variants: {
radius: {
full: "rounded-full",
lg: "rounded-lg",
md: "rounded-md",
sm: "rounded-sm",
},
size: {
lg: "h-12 px-8",
md: "h-11 px-6",
sm: "h-10 px-4",
xl: "h-13 px-10",
},
variant: {
primary: "text-white dark:bg-white/10 dark:text-white dark:hover:bg-white/15",
},
},
});
type MyButtonVariants = VariantProps;
export type MyButtonProps = Omit &
MyButtonVariants & {className?: string};
function CustomButton({className, radius, variant, ...props}: MyButtonProps) {
return ;
}
export function CustomVariants() {
return 自定义按钮 ;
}
```
### 添加涟漪效果
Button 组件通过组合支持 ripple 效果,可将 ripple 组件作为子节点嵌套。本示例使用 [m3-ripple](https://github.com/saltyaom/m3-ripple)。
```tsx
"use client";
import {Button} from "@heroui/react";
import {Ripple} from "m3-ripple";
import "m3-ripple/ripple.css";
export function RippleEffect() {
return (
点我
);
}
```
## 自定义样式
### Tailwind CSS
````tsx
"use client";
import {Button} from "@heroui/react";
/**
* 下面的 `gradient-border` 类依赖全局 utility。
* 使用前请将其添加到全局 CSS(例如 `src/app/globals.css`):
*
* ```css
* @utility gradient-border {
* &::before {
* content: "";
* position: absolute;
* inset: 0;
* z-index: 0;
* border-radius: inherit;
* padding: var(--gradient-border-width, 1px);
* background: var(--gradient-border);
* pointer-events: none;
* -webkit-mask:
* linear-gradient(#fff 0 0) content-box,
* linear-gradient(#fff 0 0);
* -webkit-mask-composite: xor;
* mask:
* linear-gradient(#fff 0 0) content-box,
* linear-gradient(#fff 0 0);
* mask-composite: exclude;
* }
* }
* ```
*
* 在组件上通过 Tailwind 任意属性或内联样式设置
* `--gradient-border`(渐变)以及可选的 `--gradient-border-width`(默认 `1px`)。
*/
export function CustomStyles() {
return (
升级
);
}
````
### 全局 CSS
可使用 `@layer components` 指令自定义 Button 组件类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.button {
@apply bg-purple-500 text-white hover:bg-purple-600;
}
.button--icon-only {
@apply rounded-lg bg-blue-500;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Button 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/button.css)):
#### 基础与尺寸类 \[!toc]
* `.button` - 基础按钮样式
* `.button--sm` - 小尺寸变体
* `.button--md` - 中尺寸变体
* `.button--lg` - 大尺寸变体
#### 变体类 \[!toc]
* `.button--primary`
* `.button--secondary`
* `.button--tertiary`
* `.button--outline`
* `.button--ghost`
* `.button--danger`
#### 修饰符类 \[!toc]
* `.button--icon-only`
* `.button--icon-only.button--sm`
* `.button--icon-only.button--lg`
### 交互状态
按钮同时支持 CSS 伪类与 data 属性:
* **Hover**:`:hover` 或 `[data-hovered="true"]`
* **Active/Pressed**:`:active` 或 `[data-pressed="true"]`(含缩放变换)
* **Focus**:`:focus-visible` 或 `[data-focus-visible="true"]`(显示焦点环)
* **Disabled**:`:disabled` 或 `[aria-disabled="true"]`(降低透明度,禁用指针事件)
* **Pending**:`[data-pending]`(加载期间禁用指针事件)
## API 参考
### Button
| Prop | 类型 | 默认值 | 描述 |
| ------------ | ---------------------------------------------------------------------------- | ----------- | -------------------------- |
| `variant` | `'primary' \| 'secondary' \| 'tertiary' \| 'outline' \| 'ghost' \| 'danger'` | `'primary'` | 视觉样式变体 |
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | 按钮尺寸 |
| `fullWidth` | `boolean` | `false` | 是否占满容器宽度 |
| `isDisabled` | `boolean` | `false` | 是否禁用 |
| `isPending` | `boolean` | `false` | 是否处于加载状态 |
| `isIconOnly` | `boolean` | `false` | 是否仅包含图标 |
| `onPress` | `(e: PressEvent) => void` | - | 按下时的回调 |
| `children` | `React.ReactNode \| (values: ButtonRenderProps) => React.ReactNode` | - | 按钮内容或 render prop |
| `render` | `DOMRenderFunction` | - | 使用自定义 render 函数覆盖默认 DOM 元素 |
### Render Props
使用 render prop 模式时,提供以下值:
| Prop | 类型 | 描述 |
| ---------------- | --------- | --------- |
| `isPending` | `boolean` | 是否处于加载状态 |
| `isPressed` | `boolean` | 是否正在按下 |
| `isHovered` | `boolean` | 是否悬停 |
| `isFocused` | `boolean` | 是否聚焦 |
| `isFocusVisible` | `boolean` | 是否显示焦点指示器 |
| `isDisabled` | `boolean` | 是否禁用 |
## 相关案例
## 相关组件
## Related Components
* **Popover**: Displays content in context with a trigger
* **Tooltip**: Contextual information on hover or focus
* **Form**: Form validation and submission handling
# CloseButton 关闭按钮
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/close-button
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(buttons)/close-button.mdx
> 用于关闭对话框、模态框或 dismiss 内容的按钮组件
## 用法
```tsx
import { CloseButton } from "@heroui/react";
```
```tsx
import {CloseButton} from "@heroui/react";
export function Default() {
return ;
}
```
## 示例
### 交互
```tsx
"use client";
import {CloseButton} from "@heroui/react";
import {useState} from "react";
export function Interactive() {
const [count, setCount] = useState(0);
return (
setCount(count + 1)} />
已点击:{count} 次
);
}
```
### 自定义图标
```tsx
import {CircleXmark, Xmark} from "@gravity-ui/icons";
import {CloseButton} from "@heroui/react";
export function WithCustomIcon() {
return (
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {CloseButton} from "@heroui/react";
export function CustomStyles() {
return (
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 CloseButton 组件类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.close-button {
@apply bg-red-100 text-red-800 hover:bg-red-200;
}
.close-button--custom {
@apply rounded-full border-2 border-red-300;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
CloseButton 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/close-button.css)):
#### 基础类 \[!toc]
* `.close-button` - 基础组件样式
#### 变体类 \[!toc]
* `.close-button--default` - 默认变体
### 交互状态
组件同时支持 CSS 伪类与 data 属性:
* **Hover**:`:hover` 或 `[data-hovered="true"]`
* **Active/Pressed**:`:active` 或 `[data-pressed="true"]`
* **Focus**:`:focus-visible` 或 `[data-focus-visible="true"]`
* **Disabled**:`:disabled` 或 `[aria-disabled="true"]`
## API 参考
### CloseButton
| Prop | 类型 | 默认值 | 描述 |
| ------------ | ----------------------- | --------------- | ------------- |
| `variant` | `"default"` | `"default"` | 按钮视觉变体 |
| `children` | `ReactNode \| function` | ` ` | 显示内容(默认为关闭图标) |
| `onPress` | `() => void` | - | 按下时的回调 |
| `isDisabled` | `boolean` | `false` | 是否禁用 |
### React Aria Button Props
CloseButton 继承所有 React Aria Button 属性。常用属性包括:
| Prop | 类型 | 描述 |
| ------------------ | -------- | ----------- |
| `aria-label` | `string` | 屏幕阅读器的无障碍标签 |
| `aria-labelledby` | `string` | 标注按钮的元素 ID |
| `aria-describedby` | `string` | 描述按钮的元素 ID |
### Render Props
使用 render prop 模式时,提供以下值:
| Prop | 类型 | 描述 |
| ------------ | --------- | ---- |
| `isHovered` | `boolean` | 是否悬停 |
| `isPressed` | `boolean` | 是否按下 |
| `isFocused` | `boolean` | 是否聚焦 |
| `isDisabled` | `boolean` | 是否禁用 |
## 相关组件
## Related Components
* **Alert**: Display important messages and notifications
* **AlertDialog**: Critical confirmations requiring user attention
* **Chip**: Compact elements for tags and filters
# ToggleButtonGroup 切换按钮组
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/toggle-button-group
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(buttons)/toggle-button-group.mdx
> 将多个 ToggleButton 组合为统一控件,允许用户选择单个或多个选项。
## 用法
```tsx
import { ToggleButtonGroup, ToggleButton } from '@heroui/react';
```
```tsx
import {Bold, Italic, Strikethrough, Underline} from "@gravity-ui/icons";
import {ToggleButton, ToggleButtonGroup} from "@heroui/react";
export function Basic() {
return (
);
}
```
## 组件结构
导入 ToggleButtonGroup 组件,并通过点语法访问所有子部分。
```tsx
import { ToggleButtonGroup, ToggleButton } from '@heroui/react';
export default () => (
First
Second
Third
);
```
## 示例
### 尺寸
```tsx
import {Bold, Italic, Strikethrough, Underline} from "@gravity-ui/icons";
import {ToggleButton, ToggleButtonGroup} from "@heroui/react";
export function Sizes() {
return (
);
}
```
### 方向
```tsx
import {Bold, Italic, Underline} from "@gravity-ui/icons";
import {ToggleButton, ToggleButtonGroup} from "@heroui/react";
export function Orientation() {
return (
);
}
```
### 宽度充满
```tsx
import {
Bold,
Italic,
Strikethrough,
TextAlignCenter,
TextAlignLeft,
TextAlignRight,
Underline,
} from "@gravity-ui/icons";
import {ToggleButton, ToggleButtonGroup} from "@heroui/react";
export function FullWidth() {
return (
左对齐
居中
右对齐
);
}
```
### 禁用
```tsx
import {Bold, Italic, Underline} from "@gravity-ui/icons";
import {ToggleButton, ToggleButtonGroup} from "@heroui/react";
export function Disabled() {
return (
);
}
```
### 无分隔线
省略按钮中的 ` ` 组件即可。
```tsx
import {Bold, Italic, Strikethrough, Underline} from "@gravity-ui/icons";
import {ToggleButton, ToggleButtonGroup} from "@heroui/react";
export function WithoutSeparator() {
return (
);
}
```
### 分离模式
使用 `isDetached` 让按钮之间留出间隔,而不是彼此连接。
```tsx
import {Bold, Italic, Strikethrough, Underline} from "@gravity-ui/icons";
import {ToggleButton, ToggleButtonGroup} from "@heroui/react";
export function Attached() {
return (
);
}
```
### 选择模式
使用 `selectionMode="single"` 实现互斥选择,或使用 `selectionMode="multiple"` 实现独立切换。
```tsx
import {
Bold,
Italic,
Strikethrough,
TextAlignCenter,
TextAlignLeft,
TextAlignRight,
Underline,
} from "@gravity-ui/icons";
import {ToggleButton, ToggleButtonGroup} from "@heroui/react";
export function SelectionMode() {
return (
);
}
```
### 受控组件
```tsx
"use client";
import type {Key} from "@heroui/react";
import {Bold, Italic, Strikethrough, Underline} from "@gravity-ui/icons";
import {ToggleButton, ToggleButtonGroup} from "@heroui/react";
import {useState} from "react";
export function Controlled() {
const [selectedKeys, setSelectedKeys] = useState(new Set(["bold"]));
return (
已选:
{selectedKeys.size > 0 ? [...selectedKeys].join(", ") : "无"}
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Bold, Italic, Underline} from "@gravity-ui/icons";
import {ToggleButton, ToggleButtonGroup} from "@heroui/react";
const toggleClass =
"rounded-lg text-muted data-[selected=true]:bg-accent-soft data-[selected=true]:text-accent-soft-foreground";
export function CustomStyles() {
return (
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.toggle-button-group {
@apply rounded-lg;
}
.toggle-button-group__separator {
@apply opacity-25;
}
.toggle-button-group--full-width {
@apply w-full;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
ToggleButtonGroup 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/toggle-button-group.css)):
#### 基础与布局类 \[!toc]
* `.toggle-button-group` - 容器基础样式
* `.toggle-button-group--horizontal` - 水平方向
* `.toggle-button-group--vertical` - 垂直方向
* `.toggle-button-group--full-width` - 全宽修饰符
* `.toggle-button-group__separator` - 按钮之间的分隔线元素
#### 修饰符类 \[!toc]
* `.toggle-button-group--detached` - 分离模式(按钮间有间隔)
## API 参考
### ToggleButtonGroup
继承自 [React Aria ToggleButtonGroup](https://react-aria.adobe.com/ToggleButtonGroup)。
| Prop | 类型 | 默认值 | 描述 |
| ------------------------ | ---------------------------- | -------------- | --------------------- |
| `selectionMode` | `"single" \| "multiple"` | `"single"` | 是否允许选中一个或多个按钮 |
| `selectedKeys` | `Iterable` | - | 受控的选中状态 |
| `defaultSelectedKeys` | `Iterable` | - | 默认选中 key(非受控) |
| `onSelectionChange` | `(keys: Set) => void` | - | 选中变化时调用 |
| `disallowEmptySelection` | `boolean` | `false` | 是否禁止清空所有选中 |
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | 布局方向 |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | 传递给子 ToggleButton 的尺寸 |
| `isDetached` | `boolean` | `false` | 按钮是否以间隔分离显示 |
| `fullWidth` | `boolean` | `false` | 按钮组是否占满可用宽度 |
| `isDisabled` | `boolean` | `false` | 是否禁用组内全部按钮 |
| `className` | `string` | - | 额外的 CSS 类 |
### ToggleButtonGroup.Separator
| Prop | 类型 | 默认值 | 描述 |
| ----------- | -------- | --- | --------- |
| `className` | `string` | - | 额外的 CSS 类 |
## 说明
* ToggleButtonGroup 使用 React Context 将 `size` 传递给所有子 ToggleButton 组件
* 每个 ToggleButton 都必须有唯一 `id` prop,并与 `selectedKeys` / `defaultSelectedKeys` 中使用的 key 对应
* `isDisabled` prop 由 React Aria 原生处理,会禁用所有子 ToggleButton;单个按钮可通过设置 `isDisabled={false}` 覆盖
* 组件会自动处理按钮之间的圆角
* 在每个 ToggleButton(第一个除外)内添加 ` `,可在按钮之间显示分隔线
* 将 `disallowEmptySelection` 与 `selectionMode="single"` 一起使用,可确保始终有一个选项被选中
## 相关组件
## Related Components
* **ToggleButton**: Interactive toggle control for on/off states
* **ButtonGroup**: Group related buttons together
* **Button**: Allows a user to perform an action
# ToggleButton 切换按钮
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/toggle-button
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(buttons)/toggle-button.mdx
> 用于在开启/关闭或已选中/未选中状态之间切换的交互式切换控件。
## 用法
```tsx
import { ToggleButton } from '@heroui/react';
```
```tsx
import {Heart} from "@gravity-ui/icons";
import {ToggleButton} from "@heroui/react";
export function Basic() {
return (
点赞
);
}
```
## 示例
### 变体
```tsx
import {Heart} from "@gravity-ui/icons";
import {ToggleButton} from "@heroui/react";
export function Variants() {
return (
默认
幽灵
);
}
```
### 仅图标
```tsx
import {Bookmark, Heart} from "@gravity-ui/icons";
import {ToggleButton} from "@heroui/react";
export function IconOnly() {
return (
);
}
```
### 尺寸
```tsx
import {Heart} from "@gravity-ui/icons";
import {ToggleButton} from "@heroui/react";
export function Sizes() {
return (
);
}
```
### 禁用
```tsx
import {Heart, HeartFill} from "@gravity-ui/icons";
import {ToggleButton} from "@heroui/react";
export function Disabled() {
return (
点赞
点赞
);
}
```
### 受控组件
```tsx
"use client";
import {Heart, HeartFill} from "@gravity-ui/icons";
import {ToggleButton} from "@heroui/react";
import {useState} from "react";
export function Controlled() {
const [isSelected, setIsSelected] = useState(false);
return (
{({isSelected: selected}) => (
<>
{selected ? : }
{selected ? "已点赞" : "点赞"}
>
)}
状态:{isSelected ? "已选" : "未选"}
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Heart} from "@gravity-ui/icons";
import {ToggleButton} from "@heroui/react";
export function CustomStyles() {
return (
收藏文章
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.toggle-button {
@apply bg-purple-500 text-white;
}
.toggle-button--icon-only {
@apply rounded-lg;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
ToggleButton 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/toggle-button.css)):
#### 基础与尺寸类 \[!toc]
* `.toggle-button` - 切换按钮基础样式
* `.toggle-button--sm` - 小尺寸变体
* `.toggle-button--md` - 中尺寸变体(默认)
* `.toggle-button--lg` - 大尺寸变体
#### 变体类 \[!toc]
* `.toggle-button--default` - 默认变体(填充背景)
* `.toggle-button--ghost` - 幽灵变体(透明背景)
#### 修饰符类 \[!toc]
* `.toggle-button--icon-only` - 仅图标切换按钮
* `.toggle-button--icon-only.toggle-button--sm` - 小尺寸仅图标
* `.toggle-button--icon-only.toggle-button--lg` - 大尺寸仅图标
### 交互状态
该切换按钮同时支持 CSS 伪类与 data 属性,以便灵活控制状态:
* **已选中**:`[data-selected="true"]`(强调色背景与前景)
* **悬停**:`:hover` 或 `[data-hovered="true"]`
* **激活/按下**:`:active` 或 `[data-pressed="true"]`(包含缩放变换)
* **聚焦**:`:focus-visible` 或 `[data-focus-visible="true"]`(显示焦点环)
* **禁用**:`:disabled` 或 `[aria-disabled="true"]`(降低透明度,禁用指针事件)
## API 参考
### ToggleButton
继承自 [React Aria ToggleButton](https://react-spectrum.adobe.com/react-aria/ToggleButton.html)。
| Prop | 类型 | 默认值 | 描述 |
| ----------------- | ------------------------------------------------------------------------- | ----------- | --------------- |
| `variant` | `'default' \| 'ghost'` | `'default'` | 视觉样式变体 |
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | 切换按钮尺寸 |
| `isIconOnly` | `boolean` | `false` | 按钮是否仅包含图标 |
| `isSelected` | `boolean` | - | 受控的已选中状态 |
| `defaultSelected` | `boolean` | `false` | 默认已选中状态(非受控) |
| `isDisabled` | `boolean` | `false` | 是否禁用切换按钮 |
| `onChange` | `(isSelected: boolean) => void` | - | 已选中状态变化时调用的处理函数 |
| `onPress` | `(e: PressEvent) => void` | - | 按钮按下时调用的处理函数 |
| `children` | `React.ReactNode \| (values: ToggleButtonRenderProps) => React.ReactNode` | - | 按钮内容或渲染 prop |
### ToggleButtonRenderProps
使用渲染 prop 模式时,会提供以下值:
| Prop | 类型 | 描述 |
| ---------------- | --------- | ------------ |
| `isSelected` | `boolean` | 按钮当前是否已选中 |
| `isPressed` | `boolean` | 按钮当前是否处于按下状态 |
| `isHovered` | `boolean` | 按钮是否处于悬停状态 |
| `isFocused` | `boolean` | 按钮是否处于聚焦状态 |
| `isFocusVisible` | `boolean` | 按钮是否应显示焦点指示 |
| `isDisabled` | `boolean` | 按钮是否被禁用 |
## 相关组件
## Related Components
* **Button**: Allows a user to perform an action
* **Switch**: Toggle between two states
* **Checkbox**: Binary choice input control
# Dropdown 下拉菜单
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/dropdown
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(collections)/dropdown.mdx
> 展示用户可选择的操作或选项列表
## 用法
```tsx
import { Dropdown } from '@heroui/react';
```
```tsx
"use client";
import {Button, Dropdown, Label} from "@heroui/react";
export function Default() {
return (
操作
console.log(`Selected: ${key}`)}>
新建文件
复制链接
编辑文件
删除文件
);
}
```
## 组件结构
```tsx
import { Dropdown, Button, Label, Description, Header, Kbd, Separator } from '@heroui/react';
export default () => (
)
```
## 示例
### 带图标
```tsx
"use client";
import {FloppyDisk, FolderOpen, SquarePlus, TrashBin} from "@gravity-ui/icons";
import {Button, Dropdown, Kbd, Label} from "@heroui/react";
export function WithIcons() {
return (
操作
console.log(`Selected: ${key}`)}>
新建文件
N
打开文件
O
保存文件
S
删除文件
D
);
}
```
### 带描述
```tsx
"use client";
import {FloppyDisk, FolderOpen, SquarePlus, TrashBin} from "@gravity-ui/icons";
import {Button, Description, Dropdown, Kbd, Label} from "@heroui/react";
export function WithDescriptions() {
return (
操作
console.log(`Selected: ${key}`)}>
新建文件
创建新文件
N
打开文件
打开已有文件
O
保存文件
保存当前文件
S
删除文件
移至废纸篓
D
);
}
```
### 含禁用项
```tsx
"use client";
import {Bars, Pencil, SquarePlus, TrashBin} from "@gravity-ui/icons";
import {Button, Description, Dropdown, Header, Kbd, Label, Separator} from "@heroui/react";
export function WithDisabledItems() {
return (
console.log(`Selected: ${key}`)}
>
新建文件
创建新文件
N
编辑文件
进行修改
E
删除文件
移至废纸篓
D
);
}
```
### 分组选项
```tsx
"use client";
import {EllipsisVertical, Pencil, SquarePlus, TrashBin} from "@gravity-ui/icons";
import {Button, Description, Dropdown, Header, Kbd, Label, Separator} from "@heroui/react";
export function WithSections() {
return (
console.log(`Selected: ${key}`)}>
新建文件
创建新文件
N
编辑文件
进行修改
E
删除文件
移至废纸篓
D
);
}
```
### 多选
```tsx
"use client";
import type {Selection} from "@heroui/react";
import {Button, Dropdown, Header, Label} from "@heroui/react";
import {useState} from "react";
export function WithMultipleSelection() {
const [selected, setSelected] = useState(new Set(["apple"]));
return (
喜爱的水果
苹果
香蕉
樱桃
橙子
梨
);
}
```
### 受控组件
```tsx
"use client";
import type {Selection} from "@heroui/react";
import {Button, Dropdown, Label} from "@heroui/react";
import {useState} from "react";
export function Controlled() {
const [selected, setSelected] = useState(new Set(["bold"]));
const selectedItems = Array.from(selected);
return (
已选:{selectedItems.length > 0 ? selectedItems.join("、") : "无"}
操作
粗体
斜体
下划线
);
}
```
### 受控展开状态
```tsx
"use client";
import {Button, Dropdown, Label} from "@heroui/react";
import {useState} from "react";
export function ControlledOpenState() {
const [open, setOpen] = useState(false);
return (
下拉菜单:{open ? "打开" : "关闭"}
操作
新建文件
打开文件
保存文件
删除文件
);
}
```
### 单选
```tsx
"use client";
import type {Selection} from "@heroui/react";
import {Button, Dropdown, Header, Label} from "@heroui/react";
import {useState} from "react";
export function WithSingleSelection() {
const [selected, setSelected] = useState(new Set(["apple"]));
return (
水果
苹果
香蕉
樱桃
橙子
梨
);
}
```
### 单选自定义指示器
```tsx
"use client";
import type {Selection} from "@heroui/react";
import {Button, Dropdown, Header, Label} from "@heroui/react";
import {useState} from "react";
export function SingleWithCustomIndicator() {
const [selected, setSelected] = useState(new Set(["apple"]));
const CustomCheckmarkIcon = (
);
return (
水果
{({isSelected}) => (isSelected ? CustomCheckmarkIcon : null)}
苹果
{({isSelected}) => (isSelected ? CustomCheckmarkIcon : null)}
香蕉
{({isSelected}) => (isSelected ? CustomCheckmarkIcon : null)}
樱桃
{({isSelected}) => (isSelected ? CustomCheckmarkIcon : null)}
橙子
{({isSelected}) => (isSelected ? CustomCheckmarkIcon : null)}
梨
);
}
```
### 分组级选择
```tsx
"use client";
import type {Selection} from "@heroui/react";
import {Button, Dropdown, Header, Kbd, Label, Separator} from "@heroui/react";
import {useState} from "react";
export function WithSectionLevelSelection() {
const [textStyles, setTextStyles] = useState(new Set(["bold", "italic"]));
const [textAlignment, setTextAlignment] = useState(new Set(["left"]));
return (
样式
剪切
X
复制
C
粘贴
U
粗体
B
斜体
I
下划线
U
左对齐
A
居中
H
右对齐
D
);
}
```
### 带快捷键
```tsx
"use client";
import {Button, Dropdown, Kbd, Label} from "@heroui/react";
export function WithKeyboardShortcuts() {
return (
操作
console.log(`Selected: ${key}`)}>
新建
N
打开
O
保存
S
删除
D
);
}
```
### 含子菜单
```tsx
"use client";
import {Button, Dropdown, Label} from "@heroui/react";
export function WithSubmenus() {
return (
分享
console.log(`Selected: ${key}`)}>
复制链接
Facebook
其他
WhatsApp
Telegram
Discord
Email
工作邮箱
个人邮箱
);
}
```
### 自定义子菜单指示器
```tsx
"use client";
import {ArrowRight} from "@gravity-ui/icons";
import {Button, Dropdown, Label} from "@heroui/react";
export function WithCustomSubmenuIndicator() {
return (
分享
console.log(`Selected: ${key}`)}>
复制链接
Facebook
更多选项
WhatsApp
Telegram
Email
工作邮箱
个人邮箱
Discord
其他(默认指示器)
SMS
);
}
```
### 自定义触发器
```tsx
import {ArrowRightFromSquare, Gear, Persons} from "@gravity-ui/icons";
import {Avatar, Dropdown, Label} from "@heroui/react";
export function CustomTrigger() {
return (
JD
JD
Jane Doe
jane@example.com
仪表盘
个人资料
设置
);
}
```
### 长按触发
```tsx
import {Button, Dropdown, Label} from "@heroui/react";
export function LongPressTrigger() {
return (
长按
新建文件
打开文件
保存文件
删除文件
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Button, Dropdown, Label} from "@heroui/react";
export function CustomStyles() {
return (
操作
重命名
复制
删除
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 Dropdown 组件类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.dropdown {
@apply flex flex-col gap-1;
}
.dropdown__trigger {
@apply outline-none;
}
.dropdown__popover {
@apply rounded-lg border border-border bg-overlay p-2;
}
.dropdown__menu {
@apply flex flex-col gap-1;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Dropdown 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/dropdown.css)):
#### 基础类 \[!toc]
* `.dropdown` - Dropdown 根容器
* `.dropdown__trigger` - 触发 Dropdown 的按钮或元素
* `.dropdown__popover` - Popover 容器
* `.dropdown__menu` - Popover 内的菜单容器
#### 状态类 \[!toc]
* `.dropdown__trigger[data-focus-visible="true"]` - 触发器聚焦状态
* `.dropdown__trigger[data-disabled="true"]` - 触发器禁用状态
* `.dropdown__trigger[data-pressed="true"]` - 触发器按下状态
* `.dropdown__popover[data-entering]` - 进入动画状态
* `.dropdown__popover[data-exiting]` - 退出动画状态
* `.dropdown__menu[data-selection-mode="single"]` - 单选模式
* `.dropdown__menu[data-selection-mode="multiple"]` - 多选模式
### 菜单组件类
Dropdown 使用 Menu、MenuItem 与 MenuSection 作为底层组件。以下类名也可用于自定义:
#### 菜单类 \[!toc]
* `.menu` - 菜单容器([menu.css](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/menu.css))
* `[data-slot="separator"]` - 菜单内的分隔线元素
#### 菜单项类 \[!toc]
* `.menu-item` - 菜单项容器([menu-item.css](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/menu-item.css))
* `.menu-item__indicator` - 选中指示器(对勾或圆点)
* `[data-slot="menu-item-indicator--checkmark"]` - 对勾指示器 SVG
* `[data-slot="menu-item-indicator--dot"]` - 圆点指示器 SVG
* `.menu-item__indicator--submenu` - 子菜单指示器(箭头)
* `.menu-item--default` - 默认样式变体
* `.menu-item--danger` - 危险样式变体
#### 菜单项状态类 \[!toc]
* `.menu-item[data-focus-visible="true"]` - 聚焦状态(键盘焦点)
* `.menu-item[data-focus="true"]` - 聚焦状态
* `.menu-item[data-pressed]` - 按下状态
* `.menu-item[data-hovered]` - 悬停状态
* `.menu-item[data-selected="true"]` - 选中状态
* `.menu-item[data-disabled]` - 禁用状态
* `.menu-item[data-has-submenu="true"]` - 带子菜单的项
* `.menu-item[data-selection-mode="single"]` - 单选模式
* `.menu-item[data-selection-mode="multiple"]` - 多选模式
* `.menu-item[aria-checked="true"]` - 已勾选(ARIA)
* `.menu-item[aria-selected="true"]` - 已选中(ARIA)
#### 菜单分区类 \[!toc]
* `.menu-section` - 菜单分区容器([menu-section.css](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/menu-section.css))
### 交互状态
组件同时支持 CSS 伪类与 data 属性:
* **Hover**:触发器与菜单项上 `:hover` 或 `[data-hovered="true"]`
* **Focus**:触发器与菜单项上 `:focus-visible` 或 `[data-focus-visible="true"]`
* **Disabled**:触发器与菜单项上 `:disabled` 或 `[data-disabled="true"]`
* **Pressed**:触发器与菜单项上 `:active` 或 `[data-pressed="true"]`
* **Selected**:菜单项上 `[data-selected="true"]` 或 `[aria-selected="true"]`
## API 参考
### Dropdown
| Prop | 类型 | 默认值 | 描述 |
| -------------- | --------------------------- | --------- | ------------------- |
| `isOpen` | `boolean` | - | 设置菜单展开状态(受控)。 |
| `defaultOpen` | `boolean` | - | 设置菜单默认展开状态(非受控)。 |
| `onOpenChange` | `(isOpen: boolean) => void` | - | 展开状态变化时调用的事件处理函数。 |
| `trigger` | `"press" \| "longPress"` | `"press"` | 触发菜单的交互类型。 |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode` | - | Dropdown 内容。 |
### Dropdown.Trigger
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------------------- | --- | ------------------- |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode \| RenderFunction` | - | 触发器内容或渲染函数。 |
使用 Button 作为触发器时,同样支持所有 [Button](https://react-spectrum.adobe.com/react-aria/Button.html) props。
### Dropdown.Popover
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- | ------------------- |
| `placement` | `"bottom" \| "bottom left" \| "bottom right" \| "bottom start" \| "bottom end" \| "top" \| "top left" \| "top right" \| "top start" \| "top end" \| "left" \| "left top" \| "left bottom" \| "start" \| "start top" \| "start bottom" \| "right" \| "right top" \| "right bottom" \| "end" \| "end top" \| "end bottom"` | `"bottom"` | 相对于触发器的 Popover 位置。 |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode` | - | 子内容。 |
同样支持所有 [Popover](https://react-spectrum.adobe.com/react-aria/Popover.html) props。
### Dropdown.Menu
| Prop | 类型 | 默认值 | 描述 |
| --------------------- | ---------------------------------- | -------- | ------------------- |
| `selectionMode` | `"single" \| "multiple" \| "none"` | `"none"` | 是否启用单选、多选或不启用选择。 |
| `selectedKeys` | `Iterable` | - | 当前选中的 key(受控)。 |
| `defaultSelectedKeys` | `Iterable` | - | 初始选中的 key(非受控)。 |
| `onSelectionChange` | `(keys: Selection) => void` | - | 选中变化时调用的事件处理函数。 |
| `disabledKeys` | `Iterable` | - | 禁用项的 key。 |
| `onAction` | `(key: Key) => void` | - | 激活菜单项时调用的事件处理函数。 |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode` | - | 菜单内容。 |
同样支持所有 [Menu](https://react-spectrum.adobe.com/react-aria/Menu.html#menu) props。
### Dropdown.Section
| Prop | 类型 | 默认值 | 描述 |
| --------------------- | --------------------------- | --- | ------------------- |
| `selectionMode` | `"single" \| "multiple"` | - | 该分组内菜单项的选择模式。 |
| `selectedKeys` | `Iterable` | - | 当前选中的 key(受控)。 |
| `defaultSelectedKeys` | `Iterable` | - | 初始选中的 key(非受控)。 |
| `onSelectionChange` | `(keys: Selection) => void` | - | 选中变化时调用的事件处理函数。 |
| `disabledKeys` | `Iterable` | - | 禁用项的 key。 |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode` | - | 分组内容。 |
同样支持所有 [MenuSection](https://react-spectrum.adobe.com/react-aria/Menu.html#menusection) props。
### Dropdown.Item
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------------------- | ----------- | ------------------- |
| `id` | `Key` | - | 菜单项唯一标识。 |
| `textValue` | `string` | - | 用于首字母导航的文本内容。 |
| `variant` | `"default" \| "danger"` | `"default"` | 菜单项视觉变体。 |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode \| RenderFunction` | - | 菜单项内容或渲染函数。 |
同样支持所有 [MenuItem](https://react-spectrum.adobe.com/react-aria/Menu.html#menuitem) props。
### Dropdown.ItemIndicator
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------------------- | ------------- | ------------------- |
| `type` | `"checkmark" \| "dot"` | `"checkmark"` | 指示器类型。 |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode \| RenderFunction` | - | 自定义指示器内容或渲染函数。 |
使用渲染函数时,会传入以下值:
| Prop | 类型 | 描述 |
| ----------------- | --------- | ------------ |
| `isSelected` | `boolean` | 该项是否选中。 |
| `isIndeterminate` | `boolean` | 该项是否处于不确定状态。 |
### Dropdown.SubmenuIndicator
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | ------------------- |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode` | - | 自定义指示器内容。 |
### Dropdown.SubmenuTrigger
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | ------------------- |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode` | - | 子菜单触发器内容。 |
同样支持所有 [SubmenuTrigger](https://react-spectrum.adobe.com/react-aria/Menu.html#submenutrigger) props。
### Render Props
在 Dropdown.Item 中使用渲染函数时,会传入以下值:
| Prop | 类型 | 描述 |
| ------------ | --------- | ----------- |
| `isSelected` | `boolean` | 该项是否选中。 |
| `isFocused` | `boolean` | 该项是否聚焦。 |
| `isDisabled` | `boolean` | 该项是否禁用。 |
| `isPressed` | `boolean` | 该项是否处于按下状态。 |
## 示例
### 基本用法
```tsx
import { Dropdown, Button, Label } from '@heroui/react';
Actions
alert(`Selected: ${key}`)}>
New file
Open file
Delete file
```
### 代码示例:分组选项
```tsx
import { Dropdown, Button, Label, Header, Separator } from '@heroui/react';
Actions
alert(`Selected: ${key}`)}>
New file
Edit file
Delete file
```
### 受控选择
```tsx
import type { Selection } from '@heroui/react';
import { Dropdown, Button, Label } from '@heroui/react';
import { useState } from 'react';
function ControlledDropdown() {
const [selected, setSelected] = useState(new Set(['bold']));
return (
Actions
Bold
Italic
);
}
```
### 代码示例:含子菜单
```tsx
import { Dropdown, Button, Label } from '@heroui/react';
Share
alert(`Selected: ${key}`)}>
Copy Link
Other
WhatsApp
Telegram
```
## 无障碍
Dropdown 组件实现 ARIA 菜单模式,并提供:
* 完整键盘导航(方向键、Home/End、首字母导航)
* 屏幕阅读器对操作与选中变化的播报
* 合理的焦点管理
* 禁用态支持
* 长按交互支持
* 子菜单导航
更多信息见 [React Aria Menu 文档](https://react-spectrum.adobe.com/react-aria/Menu.html#menu)。
## 相关组件
## Related Components
* **Button**: Allows a user to perform an action
* **Popover**: Displays content in context with a trigger
* **Separator**: Visual divider between content
# ListBox 列表框
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/list-box
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(collections)/list-box.mdx
> 列表框展示一组选项,并允许用户选择一个或多个。
## 用法
```tsx
import { ListBox } from '@heroui/react';
```
```tsx
import {Avatar, Description, Label, ListBox} from "@heroui/react";
export function Default() {
return (
B
Bob
bob@heroui.com
F
Fred
fred@heroui.com
M
Martha
martha@heroui.com
);
}
```
## 组件结构
```tsx
import { ListBox, Label, Description, Header } from '@heroui/react';
export default () => (
)
```
## 示例
### 含禁用项
```tsx
"use client";
import {Pencil, SquarePlus, TrashBin} from "@gravity-ui/icons";
import {Description, Header, Kbd, Label, ListBox, Separator, Surface} from "@heroui/react";
export function WithDisabledItems() {
return (
alert(`已选项目:${key}`)}
>
新建文件
创建新文件
N
编辑文件
进行修改
E
删除文件
移至废纸篓
D
);
}
```
### 分组选项
```tsx
"use client";
import {Pencil, SquarePlus, TrashBin} from "@gravity-ui/icons";
import {Description, Header, Kbd, Label, ListBox, Separator, Surface} from "@heroui/react";
export function WithSections() {
return (
alert(`已选项目:${key}`)}
>
新建文件
创建新文件
N
编辑文件
进行修改
E
删除文件
移至废纸篓
D
);
}
```
### 多选
```tsx
import {Avatar, Description, Label, ListBox, Surface} from "@heroui/react";
export function MultiSelect() {
return (
B
Bob
bob@heroui.com
F
Fred
fred@heroui.com
M
Martha
martha@heroui.com
);
}
```
### 受控组件
```tsx
"use client";
import type {Selection} from "@heroui/react";
import {Check} from "@gravity-ui/icons";
import {Avatar, Description, Label, ListBox, Surface} from "@heroui/react";
import {useState} from "react";
export function Controlled() {
const [selected, setSelected] = useState(new Set(["1"]));
const selectedItems = Array.from(selected);
return (
B
Bob
bob@heroui.com
{({isSelected}) => (isSelected ? : null)}
F
Fred
fred@heroui.com
{({isSelected}) => (isSelected ? : null)}
M
Martha
martha@heroui.com
{({isSelected}) => (isSelected ? : null)}
已选:{selectedItems.length > 0 ? selectedItems.join("、") : "无"}
);
}
```
### 虚拟滚动
ListBox 通过 [Virtualizer](https://react-aria.adobe.com/Virtualizer) 支持虚拟化,仅渲染视口内可见行,从而高效展示大数据集。
```tsx
"use client";
import {Description, Label, ListBox, ListLayout, Virtualizer} from "@heroui/react";
interface User {
id: number;
name: string;
email: string;
}
export function Virtualization() {
const firstNames = [
"Emma",
"Liam",
"Olivia",
"Noah",
"Ava",
"James",
"Sophia",
"Oliver",
"Isabella",
"Lucas",
"Mia",
"Ethan",
"Charlotte",
"Mason",
"Amelia",
"Logan",
"Harper",
"Alexander",
"Ella",
"Benjamin",
];
const lastNames = [
"Smith",
"Johnson",
"Williams",
"Brown",
"Jones",
"Garcia",
"Miller",
"Davis",
"Rodriguez",
"Martinez",
"Anderson",
"Taylor",
"Thomas",
"Jackson",
"White",
"Harris",
"Clark",
"Lewis",
"Robinson",
"Walker",
];
function generateUsers(n: number): User[] {
const users: User[] = [];
for (let i = 0; i < n; i++) {
const firstName = firstNames[i % firstNames.length];
const lastName = lastNames[Math.floor(i / firstNames.length) % lastNames.length];
const name = `${firstName} ${lastName}`;
users.push({
email: `${firstName?.toLowerCase()}.${lastName?.toLowerCase()}@acme.com`,
id: i + 1,
name,
});
}
return users;
}
const users = generateUsers(1000);
return (
{(user) => (
{user.name}
{user.email}
)}
);
}
```
### 自定义勾选图标
```tsx
"use client";
import {Check} from "@gravity-ui/icons";
import {Avatar, Description, Label, ListBox, Surface} from "@heroui/react";
export function CustomCheckIcon() {
return (
B
Bob
bob@heroui.com
{({isSelected}) => (isSelected ? : null)}
F
Fred
fred@heroui.com
{({isSelected}) => (isSelected ? : null)}
M
Martha
martha@heroui.com
{({isSelected}) => (isSelected ? : null)}
);
}
```
### 渲染函数
```tsx
"use client";
import {Avatar, Description, Label, ListBox} from "@heroui/react";
export function RenderFunction() {
return (
}
selectionMode="single"
>
}
textValue="Bob"
>
B
Bob
bob@heroui.com
}
textValue="Fred"
>
F
Fred
fred@heroui.com
}
textValue="Martha"
>
M
Martha
martha@heroui.com
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Avatar, Description, Label, ListBox} from "@heroui/react";
export function CustomStyles() {
return (
B
Bob
bob@heroui.com
F
Fred
fred@heroui.com
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.list-box {
@apply rounded-lg border border-border bg-surface p-2;
}
.list-box-item {
@apply rounded px-2 py-1 cursor-pointer;
}
.list-box-item--danger {
@apply text-danger;
}
.list-box-item__indicator {
@apply text-accent;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
ListBox 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/list-box.css)):
#### 基础类 \[!toc]
* `.list-box` - ListBox 根容器
* `.list-box-item` - 单个列表项
* `.list-box-item__indicator` - 选中指示图标
* `.list-box-section` - 用于分组的区块容器
#### 变体类 \[!toc]
* `.list-box--default` - 默认变体样式
* `.list-box--danger` - 危险变体样式
* `.list-box-item--default` - 列表项默认变体
* `.list-box-item--danger` - 列表项危险变体
#### 状态类 \[!toc]
* `.list-box-item[data-selected="true"]` - 选中状态
* `.list-box-item[data-focus-visible="true"]` - 聚焦状态
* `.list-box-item[data-disabled="true"]` - 禁用状态
* `.list-box-item__indicator[data-visible="true"]` - 指示器可见状态
### 交互状态
该组件同时支持 CSS 伪类与 data 属性:
* **悬停**:列表项上 `:hover` 或 `[data-hovered="true"]`
* **聚焦**:列表项上 `:focus-visible` 或 `[data-focus-visible="true"]`
* **已选中**:列表项上 `[data-selected="true"]`
* **禁用**:列表项上 `:disabled` 或 `[data-disabled="true"]`
## API 参考
### ListBox
| Prop | 类型 | 默认值 | 描述 |
| --------------------- | -------------------------------------------------------------------------- | ----------- | --------------------- |
| `aria-label` | `string` | - | ListBox 的无障碍标签。 |
| `aria-labelledby` | `string` | - | 标注 ListBox 的元素 id。 |
| `selectionMode` | `"none" \| "single" \| "multiple"` | `"single"` | 选择行为。 |
| `selectedKeys` | `Selection` | - | 受控的选中 key。 |
| `defaultSelectedKeys` | `Selection` | - | 初始选中 key。 |
| `onSelectionChange` | `(keys: Selection) => void` | - | 选中变化时调用的事件处理函数。 |
| `disabledKeys` | `Iterable` | - | 禁用项的 key。 |
| `onAction` | `(key: Key) => void` | - | 激活某项时调用的事件处理函数。 |
| `variant` | `"default" \| "danger"` | `"default"` | 视觉变体。 |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode` | - | ListBox 项与分组。 |
| `render` | `DOMRenderFunction` | - | 使用自定义渲染函数覆盖默认 DOM 元素。 |
### ListBox.Item
| Prop | 类型 | 默认值 | 描述 |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | --------------------- |
| `id` | `Key` | - | 列表项唯一标识。 |
| `textValue` | `string` | - | 用于无障碍与首字母导航的文本值。 |
| `isDisabled` | `boolean` | `false` | 是否禁用该项。 |
| `variant` | `"default" \| "danger"` | `"default"` | 视觉变体。 |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode \| RenderFunction` | - | 列表项内容或渲染函数。 |
| `render` | `(props: DetailedHTMLProps \| React.JSX.IntrinsicElements[keyof React.JSX.IntrinsicElements], renderProps: ListBoxItemRenderProps) => ReactElement` | - | 使用自定义渲染函数覆盖默认 DOM 元素。 |
### ListBox.ItemIndicator
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------------------- | --- | ------------------- |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode \| RenderFunction` | - | 自定义指示器内容或渲染函数。 |
### ListBox.Section
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | -------------------- |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode` | - | 分组内容,包含 Header 与列表项。 |
### RenderProps
在 ListBox.Item 或 ListBox.ItemIndicator 中使用渲染函数时,会传入以下值:
| Prop | 类型 | 描述 |
| ------------ | --------- | ----------- |
| `isSelected` | `boolean` | 该项是否选中。 |
| `isFocused` | `boolean` | 该项是否聚焦。 |
| `isDisabled` | `boolean` | 该项是否禁用。 |
| `isPressed` | `boolean` | 该项是否处于按下状态。 |
### ListLayout
| Name | 类型 | 默认值 | 描述 |
| ------------------------ | --------------------- | --- | ------------------------------------------- |
| `rowHeight` | `number \| undefined` | 48 | 行固定高度(px)。 |
| `estimatedRowHeight` | `number \| undefined` | — | 行高可变时的估算高度。 |
| `headingHeight` | `number \| undefined` | 48 | 分组标题固定高度(px)。 |
| `estimatedHeadingHeight` | `number \| undefined` | — | 标题高度可变时的估算高度。 |
| `loaderHeight` | `number \| undefined` | 48 | 加载器元素固定高度(px)。该加载器用于在根级或嵌套行/分组中渲染「加载更多」等内容。 |
| `dropIndicatorThickness` | `number \| undefined` | 2 | 放置指示线厚度。 |
| `gap` | `number \| undefined` | 0 | 项之间的间距。 |
| `padding` | `number \| undefined` | 0 | 列表内边距。 |
## 示例
### 基本用法
```tsx
import { ListBox, Label, Description } from '@heroui/react';
Bob
bob@heroui.com
Alice
alice@heroui.com
```
### 分组选项
```tsx
import { ListBox, Header, Separator } from '@heroui/react';
console.log(key)}>
New file
Edit file
Delete
```
### 受控选择
```tsx
import { ListBox, Selection } from '@heroui/react';
import { useState } from 'react';
function ControlledListBox() {
const [selected, setSelected] = useState(new Set(["1"]));
return (
Option 1
Option 2
Option 3
);
}
```
### 自定义指示器
```tsx
import { ListBox, ListBoxItemIndicator } from '@heroui/react';
import { Icon } from '@iconify/react';
Option 1
{({isSelected}) =>
isSelected ? : null
}
```
## 无障碍
ListBox 组件实现 ARIA listbox 模式,并提供:
* 完整键盘导航支持
* 屏幕阅读器对选中变化的播报
* 合理的焦点管理
* 禁用状态支持
* 首字母导航(typeahead)搜索能力
更多信息见 [React Aria ListBox 文档](https://react-spectrum.adobe.com/react-aria/ListBox.html)。
## 相关组件
## Related Components
* **Select**: Dropdown select control
* **ComboBox**: Text input with searchable dropdown list
* **Avatar**: Display user profile images
# TagGroup 标签组
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/tag-group
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(collections)/tag-group.mdx
> 可聚焦的标签列表,支持键盘导航、选择与移除。
## 用法
```tsx
import { TagGroup } from '@heroui/react';
```
```tsx
"use client";
import {PlanetEarth, Rocket, ShoppingBag, SquareArticle} from "@gravity-ui/icons";
import {Tag, TagGroup} from "@heroui/react";
export function TagGroupBasic() {
return (
资讯
旅行
游戏
购物
);
}
```
## 组件结构
```tsx
import { TagGroup, Tag, Label, Description, ErrorMessage } from '@heroui/react';
export default () => (
)
```
## 示例
### 尺寸
```tsx
"use client";
import {Label, Tag, TagGroup} from "@heroui/react";
export function TagGroupSizes() {
return (
小
资讯
旅行
游戏
中
资讯
旅行
游戏
大
资讯
旅行
游戏
);
}
```
### 变体
```tsx
"use client";
import {Label, Tag, TagGroup} from "@heroui/react";
export function TagGroupVariants() {
return (
默认
资讯
旅行
游戏
表面
资讯
旅行
游戏
);
}
```
### 禁用
```tsx
"use client";
import {Description, Label, Tag, TagGroup} from "@heroui/react";
export function TagGroupDisabled() {
return (
已禁用的标签
资讯
旅行
游戏
部分标签已禁用
禁用的键
资讯
旅行
游戏
通过 disabledKeys 属性禁用的标签
);
}
```
### 选择模式
```tsx
"use client";
import type {Key} from "@heroui/react";
import {Description, Label, Tag, TagGroup} from "@heroui/react";
import {useState} from "react";
export function TagGroupSelectionModes() {
const [singleSelected, setSingleSelected] = useState>(new Set(["news"]));
const [multipleSelected, setMultipleSelected] = useState>(
new Set(["news", "travel"]),
);
return (
setSingleSelected(keys)}
>
单选
资讯
旅行
游戏
购物
选择一个分类
setMultipleSelected(keys)}
>
多选
资讯
旅行
游戏
购物
选择多个分类
);
}
```
### 受控组件
```tsx
"use client";
import type {Key} from "@heroui/react";
import {Description, Label, Tag, TagGroup} from "@heroui/react";
import {useState} from "react";
export function TagGroupControlled() {
const [selected, setSelected] = useState>(new Set(["news", "travel"]));
return (
setSelected(keys)}
>
分类(受控)
资讯
旅行
游戏
购物
已选:{Array.from(selected).length > 0 ? Array.from(selected).join(", ") : "无"}
);
}
```
### 带错误信息
```tsx
"use client";
import type {Key} from "@heroui/react";
import {Description, ErrorMessage, Label, Tag, TagGroup} from "@heroui/react";
import {useMemo, useState} from "react";
export function TagGroupWithErrorMessage() {
const [selected, setSelected] = useState>(new Set());
const isInvalid = useMemo(() => Array.from(selected).length === 0, [selected]);
return (
setSelected(keys)}
>
设施
洗衣
健身中心
停车
游泳池
早餐
{isInvalid ? "请至少选择一个分类" : "已选:" + Array.from(selected).join(", ")}
{!!isInvalid && <>请至少选择一个分类>}
);
}
```
### 带列表数据
```tsx
"use client";
import type {Key} from "@heroui/react";
import {Avatar, Description, EmptyState, Label, Tag, TagGroup, useListData} from "@heroui/react";
export function TagGroupWithListData() {
type User = {
id: string;
name: string;
avatar: string;
fallback: string;
};
const list = useListData({
getKey: (item) => item.id,
initialItems: [
{
avatar: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/blue.jpg",
fallback: "F",
id: "fred",
name: "Fred",
},
{
avatar: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/green.jpg",
fallback: "M",
id: "michael",
name: "Michael",
},
{
avatar: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/purple.jpg",
fallback: "J",
id: "jane",
name: "Jane",
},
{
avatar: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/red.jpg",
fallback: "A",
id: "alice",
name: "Alice",
},
{
avatar: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/orange.jpg",
fallback: "B",
id: "bob",
name: "Bob",
},
{
avatar: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/black.jpg",
fallback: "C",
id: "charlie",
name: "Charlie",
},
],
initialSelectedKeys: new Set(["fred", "michael"]),
});
const onRemove = (keys: Set) => {
list.remove(...keys);
};
return (
list.setSelectedKeys(keys)}
>
团队成员
暂无团队成员 }
>
{(user) => (
{user.fallback}
{user.name}
)}
为项目选择团队成员
{list.selectedKeys !== "all" && Array.from(list.selectedKeys).length > 0 && (
已选:
{Array.from(list.selectedKeys).map((key) => {
const user = list.getItem(key);
if (!user) return null;
return (
{user.fallback}
{user.name}
);
})}
)}
);
}
```
### 带前缀
```tsx
"use client";
import {PlanetEarth, Rocket, ShoppingBag, SquareArticle} from "@gravity-ui/icons";
import {Avatar, Description, Label, Tag, TagGroup} from "@heroui/react";
export function TagGroupWithPrefix() {
return (
带图标
News
Travel
Gaming
Shopping
带图标的标签
带头像
F
Fred
M
Michael
J
Jane
带头像的标签
);
}
```
### 带移除按钮
```tsx
"use client";
import type {Key} from "@heroui/react";
import {CircleXmarkFill} from "@gravity-ui/icons";
import {Description, EmptyState, Label, Tag, TagGroup} from "@heroui/react";
import {useState} from "react";
export function TagGroupWithRemoveButton() {
type TagItem = {id: string; name: string};
const [tags, setTags] = useState([
{id: "news", name: "资讯"},
{id: "travel", name: "旅行"},
{id: "gaming", name: "游戏"},
{id: "shopping", name: "购物"},
]);
const [frameworks, setFrameworks] = useState([
{id: "react", name: "React"},
{id: "vue", name: "Vue"},
{id: "angular", name: "Angular"},
{id: "svelte", name: "Svelte"},
]);
const onRemoveTags = (keys: Set) => {
setTags(tags.filter((tag) => !keys.has(tag.id)));
};
const onRemoveFrameworks = (keys: Set) => {
setFrameworks(frameworks.filter((framework) => !keys.has(framework.id)));
};
return (
默认移除按钮
未找到分类 }
>
{(tag) => (
{tag.name}
)}
点击 × 移除标签
自定义移除按钮
未找到框架 }
>
{(tag) => (
{(renderProps) => (
<>
{tag.name}
{!!renderProps.allowsRemoving && (
)}
>
)}
)}
带图标的自定义移除按钮
);
}
```
### 渲染函数
```tsx
"use client";
import {PlanetEarth, Rocket, ShoppingBag, SquareArticle} from "@gravity-ui/icons";
import {Tag, TagGroup} from "@heroui/react";
export function RenderFunction() {
return (
}
selectionMode="single"
>
资讯
旅行
游戏
购物
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
"use client";
import {PlanetEarth, Rocket, ShoppingBag, SquareArticle} from "@gravity-ui/icons";
import {Tag, TagGroup} from "@heroui/react";
const tagClass =
"group/tag gap-1.5 rounded-full border border-neutral-300/80 bg-white/80 px-2.5 py-1 text-sm font-medium text-neutral-700 shadow-sm ring-1 ring-black/5 backdrop-blur-sm transition-colors data-[selected=true]:border-neutral-500 data-[selected=true]:bg-neutral-900 data-[selected=true]:text-neutral-50 dark:border-neutral-600/80 dark:bg-neutral-900/60 dark:text-neutral-200 dark:ring-white/10 dark:data-[selected=true]:border-neutral-400 dark:data-[selected=true]:bg-neutral-100 dark:data-[selected=true]:text-neutral-900";
const iconClass =
"size-4 shrink-0 text-neutral-500 group-data-[selected=true]/tag:text-current dark:text-neutral-400";
export function CustomStyles() {
return (
资讯
旅行
游戏
购物
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.tag-group {
@apply flex flex-col gap-2;
}
.tag-group__list {
@apply flex flex-wrap gap-2;
}
.tag {
@apply rounded-full px-3 py-1;
}
.tag__remove-button {
@apply ml-1;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
TagGroup 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/tag-group.css) 与 [tag.css](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/tag.css)):
#### 基础类 \[!toc]
* `.tag-group` - TagGroup 根容器
* `.tag-group__list` - 标签列表容器
* `.tag` - 标签基础样式
* `.tag__remove-button` - 移除按钮触发器
#### 插槽类 \[!toc]
* `.tag-group [slot="description"]` - Description 插槽样式
* `.tag-group [slot="errorMessage"]` - ErrorMessage 插槽样式
#### 尺寸类 \[!toc]
* `.tag--sm` - 小尺寸标签
* `.tag--md` - 中尺寸标签(默认)
* `.tag--lg` - 大尺寸标签
#### 变体类 \[!toc]
* `.tag--default` - 默认变体
* `.tag--surface` - 带 Surface 背景的变体
#### 状态类 \[!toc]
* `.tag[data-selected="true"]` - 选中状态
* `.tag[data-disabled="true"]` - 禁用状态
* `.tag[data-hovered="true"]` - 悬停状态
* `.tag[data-pressed="true"]` - 按下状态
* `.tag[data-focus-visible="true"]` - 聚焦状态(键盘焦点)
### 交互状态
该组件同时支持 CSS 伪类与 data 属性:
* **悬停**:标签上 `:hover` 或 `[data-hovered="true"]`
* **聚焦**:标签上 `:focus-visible` 或 `[data-focus-visible="true"]`
* **按下**:标签上 `:active` 或 `[data-pressed="true"]`
* **已选中**:标签上 `[data-selected="true"]` 或 `[aria-selected="true"]`
* **禁用**:标签上 `:disabled` 或 `[data-disabled="true"]`
## API 参考
### TagGroup
| Prop | 类型 | 默认值 | 描述 |
| --------------------- | ----------------------------------------------------------------- | ----------- | --------------------- |
| `selectionMode` | `"none" \| "single" \| "multiple"` | `"none"` | 允许的选择类型。 |
| `selectedKeys` | `Selection` | - | 当前选中的 key(受控)。 |
| `defaultSelectedKeys` | `Selection` | - | 初始选中的 key(非受控)。 |
| `onSelectionChange` | `(keys: Selection) => void` | - | 选中变化时调用的事件处理函数。 |
| `disabledKeys` | `Iterable` | - | 禁用标签的 key。 |
| `isDisabled` | `boolean` | - | 是否禁用整个 TagGroup。 |
| `onRemove` | `(keys: Set) => void` | - | 移除标签时调用的事件处理函数。 |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | 组内标签尺寸。 |
| `variant` | `"default" \| "surface"` | `"default"` | 标签视觉变体。 |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode \| RenderFunction` | - | TagGroup 内容或渲染函数。 |
| `render` | `DOMRenderFunction` | - | 使用自定义渲染函数覆盖默认 DOM 元素。 |
### TagGroup.List
| Prop | 类型 | 默认值 | 描述 |
| ------------------ | -------------------------------------------------------------------------- | --- | --------------------- |
| `items` | `Iterable` | - | 标签列表要展示的数据项。 |
| `renderEmptyState` | `() => ReactNode` | - | 列表为空时的渲染函数。 |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode \| RenderFunction` | - | 标签列表内容或渲染函数。 |
| `render` | `DOMRenderFunction` | - | 使用自定义渲染函数覆盖默认 DOM 元素。 |
### Tag
| Prop | 类型 | 默认值 | 描述 |
| ------------ | ---------------------------------------------------------------------- | --- | --------------------- |
| `id` | `Key` | - | 标签唯一标识。 |
| `textValue` | `string` | - | 标签内容的字符串表示,用于无障碍。 |
| `isDisabled` | `boolean` | - | 是否禁用该标签。 |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode \| RenderFunction` | - | 标签内容或渲染函数。 |
| `render` | `DOMRenderFunction` | - | 使用自定义渲染函数覆盖默认 DOM 元素。 |
**提示:** `size`、`variant` 由父级 `TagGroup` 继承,无法在单个 `Tag` 上直接设置。
### Tag.RemoveButton
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | ------------------- |
| `className` | `string` | - | 额外的 Tailwind CSS 类。 |
| `children` | `ReactNode` | - | 自定义移除按钮内容(默认为关闭图标)。 |
**提示:** `Tag.RemoveButton` 支持类似 `SearchField.ClearButton` 的定制方式。当为 `TagGroup` 提供 `onRemove` 时:
* **自动渲染**:若 `Tag` 的子节点中未包含自定义 `Tag.RemoveButton`,会自动渲染默认移除按钮。
* **自定义按钮**:若在 `Tag` 下提供了自定义 `Tag.RemoveButton`,将替换自动渲染的按钮。
* **自定义图标**:可向 `Tag.RemoveButton` 传入自定义子内容(如图标)以改变外观。
**示例 — 自动渲染(默认)**:
```tsx
News
{/* Remove button is automatically rendered */}
```
**示例 — 自定义 RemoveButton(带图标)**:
```tsx
News
```
**示例 — 在 render props 中使用自定义 RemoveButton**:
```tsx
{(renderProps) => (
<>
News
{!!renderProps.allowsRemoving && (
)}
>
)}
```
### RenderProps
在 TagGroup.List 中使用渲染函数时,会传入以下值:
| Prop | 类型 | 描述 |
| ---------------- | --------- | ------------ |
| `isSelected` | `boolean` | 标签是否选中。 |
| `isDisabled` | `boolean` | 标签是否禁用。 |
| `isHovered` | `boolean` | 标签是否悬停。 |
| `isPressed` | `boolean` | 标签是否按下。 |
| `isFocused` | `boolean` | 标签是否聚焦。 |
| `isFocusVisible` | `boolean` | 标签是否为可见键盘焦点。 |
## 相关组件
## Related Components
* **Label**: Accessible label for form controls
* **Description**: Helper text for form fields
* **ErrorMessage**: Displays validation error messages for components with validation support
# ColorArea 颜色区域
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/color-area
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(colors)/color-area.mdx
> 二维颜色选择器,允许用户从渐变区域中选择颜色
## 用法
```tsx
import { ColorArea } from '@heroui/react';
```
```tsx
import {ColorArea} from "@heroui/react";
export function ColorAreaBasic() {
return (
);
}
```
## 组件结构
```tsx
import { ColorArea } from '@heroui/react';
export default () => (
);
```
## 示例
### 带定位点
```tsx
import {ColorArea} from "@heroui/react";
export function ColorAreaWithDots() {
return (
);
}
```
### 色彩空间与通道
使用 `colorSpace` 设置颜色空间(RGB、HSL、HSB),使用 `xChannel`/`yChannel` 自定义各轴显示的颜色通道。
```tsx
"use client";
import type {ColorSpace, Key} from "@heroui/react";
import {ColorArea, Label, ListBox, Select, parseColor} from "@heroui/react";
import {useState} from "react";
type ColorChannel = "hue" | "saturation" | "brightness" | "lightness" | "red" | "green" | "blue";
interface ChannelOption {
id: ColorChannel;
name: string;
}
const colorSpaces: Array<{id: ColorSpace; name: string}> = [
{id: "rgb", name: "RGB"},
{id: "hsl", name: "HSL"},
{id: "hsb", name: "HSB"},
];
const channelsBySpace: Record = {
hsb: [
{id: "hue", name: "Hue"},
{id: "saturation", name: "Saturation"},
{id: "brightness", name: "Brightness"},
],
hsl: [
{id: "hue", name: "Hue"},
{id: "saturation", name: "Saturation"},
{id: "lightness", name: "Lightness"},
],
rgb: [
{id: "red", name: "Red"},
{id: "green", name: "Green"},
{id: "blue", name: "Blue"},
],
};
export function ColorAreaSpaceAndChannels() {
const [colorSpace, setColorSpace] = useState("hsb");
const [color, setColor] = useState(() => parseColor("hsb(219, 58%, 93%)"));
const channels = channelsBySpace[colorSpace];
const defaultX = colorSpace === "rgb" ? "blue" : "saturation";
const defaultY =
colorSpace === "rgb" ? "green" : colorSpace === "hsl" ? "lightness" : "brightness";
const [xChannel, setXChannel] = useState(defaultX);
const [yChannel, setYChannel] = useState(defaultY);
const handleColorSpaceChange = (newSpace: Key | null) => {
if (!newSpace) return;
const space = newSpace as ColorSpace;
setColorSpace(space);
// Reset channels to appropriate defaults for the new color space
if (space === "rgb") {
setXChannel("blue");
setYChannel("green");
} else if (space === "hsl") {
setXChannel("saturation");
setYChannel("lightness");
} else {
setXChannel("saturation");
setYChannel("brightness");
}
};
// Filter out the other channel from options (can't have same channel on both axes)
const xChannelOptions = channels.filter((c) => c.id !== yChannel);
const yChannelOptions = channels.filter((c) => c.id !== xChannel);
return (
{/* Controls */}
{/* Color Space Select */}
Color Space
{colorSpaces.map((space) => (
{space.name}
))}
{/* X Channel Select */}
value && setXChannel(value as ColorChannel)}
>
X Axis
{xChannelOptions.map((channel) => (
{channel.name}
))}
{/* Y Channel Select */}
value && setYChannel(value as ColorChannel)}
>
Y Axis
{yChannelOptions.map((channel) => (
{channel.name}
))}
{/* Color Area */}
{/* Color Value Display */}
{color.toString(colorSpace)}
);
}
```
### 禁用
```tsx
import {ColorArea} from "@heroui/react";
export function ColorAreaDisabled() {
return (
);
}
```
### 受控组件
```tsx
"use client";
import type {Color} from "@heroui/react";
import {ColorArea, ColorSwatch, parseColor} from "@heroui/react";
import {useState} from "react";
export function ColorAreaControlled() {
const [color, setColor] = useState(parseColor("#9B80FF"));
return (
Current color:{" "}
{color ? color.toString("hex") : "(empty)"}
);
}
```
### 渲染函数
```tsx
"use client";
import {ColorArea} from "@heroui/react";
export function RenderFunction() {
return (
}
>
} />
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {ColorArea} from "@heroui/react";
export function CustomStyles() {
return (
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 ColorArea 组件类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.color-area {
@apply rounded-3xl;
}
.color-area__thumb {
@apply size-5 border-4;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
ColorArea 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/color-area.css)):
#### 基础类 \[!toc]
* `.color-area` - 渐变背景与内阴影的基础样式
* `.color-area--show-dots` - 添加点阵网格覆盖层以精确选色
#### 元素类 \[!toc]
* `.color-area__thumb` - 可拖拽的滑块指示器
### 交互状态
组件同时支持 CSS 伪类与 data 属性:
* **Disabled**:`[data-disabled="true"]`
* **Focus**:`[data-focus-visible="true"]`
* **Dragging**:`[data-dragging="true"]`(仅 thumb)
## API 参考
### ColorArea
继承自 [React Aria ColorArea](https://react-spectrum.adobe.com/react-aria/ColorArea.html)。
| Prop | 类型 | 默认值 | 描述 |
| -------------- | ---------------------------------------------------------------------------- | -------------- | -------------------------- |
| `value` | `string \| Color` | - | 当前颜色值(受控) |
| `defaultValue` | `string \| Color` | - | 默认颜色值(非受控) |
| `onChange` | `(color: Color) => void` | - | 拖拽过程中颜色变化时的回调 |
| `onChangeEnd` | `(color: Color) => void` | - | 用户停止拖拽时的回调 |
| `xChannel` | `ColorChannel` | `"saturation"` | 水平轴的颜色通道 |
| `yChannel` | `ColorChannel` | `"brightness"` | 垂直轴的颜色通道 |
| `colorSpace` | `ColorSpace` | - | 通道使用的颜色空间 |
| `isDisabled` | `boolean` | `false` | 是否禁用 |
| `showDots` | `boolean` | `false` | 是否显示点阵网格覆盖层 |
| `className` | `string` | - | 附加 CSS 类 |
| `render` | `DOMRenderFunction` | - | 使用自定义 render 函数覆盖默认 DOM 元素 |
### ColorArea.Thumb
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------------------------------------------------------------------- | --- | -------------------------- |
| `className` | `string` | - | 附加 CSS 类 |
| `style` | `CSSProperties \| ((renderProps) => CSSProperties)` | - | 内联样式或 render props 函数 |
| `render` | `DOMRenderFunction` | - | 使用自定义 render 函数覆盖默认 DOM 元素 |
## 相关组件
## Related Components
* **ColorSwatch**: Visual preview of a color value
* **ColorSwatchPicker**: Color swatch selection from a list of colors
* **ColorField**: Input for entering color values with hex format
# ColorField 颜色输入框
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/color-field
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(colors)/color-field.mdx
> 基于 React Aria ColorField 的颜色输入字段,支持标签、描述与验证
## 用法
```tsx
import { ColorField, parseColor } from '@heroui/react';
```
```tsx
"use client";
import type {Color} from "@heroui/react";
import {ColorField, ColorSwatch, Label, parseColor} from "@heroui/react";
import {useState} from "react";
export function Basic() {
const [color, setColor] = useState(parseColor("#0485F7"));
return (
颜色
);
}
```
## 组件结构
```tsx
import {ColorField, Label, ColorSwatch, Description, FieldError, parseColor} from '@heroui/react';
export default () => (
)
```
> **ColorField** 将标签、颜色输入、描述与错误合并为单个无障碍组件。
## 示例
### 变体
ColorField.Group 组件支持两种视觉变体:
* **`primary`**(默认)- 标准样式带阴影,适用于大多数场景
* **`secondary`** - 低强调变体无阴影,适用于 Surface 组件内
```tsx
import {ColorField, Label} from "@heroui/react";
export function Variants() {
return (
主要变体
次要变体
);
}
```
### 表面样式
在 [Surface](/docs/components/surface) 组件内使用时,在 ColorField.Group 上使用 `variant="secondary"` 以应用适合 Surface 背景的低强调变体。
```tsx
import {ColorField, Description, Label, Surface} from "@heroui/react";
export function OnSurface() {
return (
主题色
选择你的主题色
);
}
```
### 带描述
```tsx
import {ColorField, Description, Label} from "@heroui/react";
export function WithDescription() {
return (
主色
输入品牌主色
强调色
用于高亮与行动按钮
);
}
```
### 必填字段
```tsx
import {ColorField, Description, Label} from "@heroui/react";
export function Required() {
return (
品牌色
主题色
必填项
);
}
```
### 禁用
```tsx
"use client";
import {ColorField, Description, Label} from "@heroui/react";
export function Disabled() {
return (
颜色
该颜色字段已禁用
颜色
该颜色字段已禁用
);
}
```
### 宽度充满
```tsx
import {ColorField, Label} from "@heroui/react";
export function FullWidth() {
return (
品牌色
主题色
);
}
```
### 表单校验
将 `isInvalid` 与 `FieldError` 一起使用以显示验证消息。
```tsx
import {ColorField, FieldError, Label} from "@heroui/react";
export function Invalid() {
return (
颜色
请输入有效的十六进制颜色
背景色
颜色格式无效,请使用十六进制(例如 #FF5733)
);
}
```
### 分量编辑
ColorField 支持通过设置 `colorSpace` 与 `channel` 属性编辑单个颜色通道(hue、saturation、lightness、red、green、blue、alpha)。
```tsx
"use client";
import type {Color} from "@heroui/react";
import {ColorField, ColorSwatch, Label, parseColor} from "@heroui/react";
import {useState} from "react";
export function ChannelEditing() {
const [color, setColor] = useState(parseColor("#7F007F"));
return (
分别编辑 HSL 通道:
色相
饱和度
%
明度
%
当前:{color ? color.toString("hex") : "(空)"}
);
}
```
### 受控组件
控制值以与其他组件或状态管理同步。
```tsx
"use client";
import type {Color} from "@heroui/react";
import {Button, ColorField, ColorSwatch, Description, Label, parseColor} from "@heroui/react";
import {useState} from "react";
export function Controlled() {
const [value, setValue] = useState(parseColor("#0485F7"));
return (
颜色
当前值:{value ? value.toString("hex") : "(空)"}
setValue(parseColor("#EF4444"))}>
设为红色
setValue(parseColor("#10B981"))}>
设为绿色
setValue(null)}>
清空
);
}
```
### 表单示例
包含验证与提交处理的完整表单示例。
```tsx
"use client";
import type {Color} from "@heroui/react";
import {Button, ColorField, ColorSwatch, Description, Form, Label} from "@heroui/react";
import {useState} from "react";
export function FormExample() {
const [value, setValue] = useState(null);
const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!value) {
return;
}
setIsSubmitting(true);
// Simulate API call
setTimeout(() => {
console.log("已提交颜色:", {color: value.toString("hex")});
setValue(null);
setIsSubmitting(false);
}, 1500);
};
return (
品牌色
选择品牌主色
{isSubmitting ? "保存中…" : "保存颜色"}
);
}
```
### 渲染函数
```tsx
"use client";
import type {Color} from "@heroui/react";
import {ColorField, ColorSwatch, Label, parseColor} from "@heroui/react";
import {useState} from "react";
export function RenderFunction() {
const [color, setColor] = useState(parseColor("#0485F7"));
return (
}
value={color}
onChange={setColor}
>
颜色
}>
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
"use client";
import type {Color} from "@heroui/react";
import {ColorField, ColorSwatch, Description, Label, parseColor} from "@heroui/react";
import {useState} from "react";
export function CustomStyles() {
const [color, setColor] = useState(parseColor("#6366F1"));
return (
强调色
应用于按钮、链接和焦点环。
);
}
```
### 全局 CSS
ColorField 默认样式较少。覆盖 `.color-field` 类以自定义容器样式。
```css
@layer components {
.color-field {
@apply flex flex-col gap-1;
&[data-invalid="true"],
&[aria-invalid="true"] {
[data-slot="description"] {
@apply hidden;
}
}
[data-slot="label"] {
@apply w-fit;
}
[data-slot="description"] {
@apply px-1;
}
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
* `.color-field` – 最小样式的根容器(`flex flex-col gap-1`)
> **Note:** 子组件([Label](/docs/components/label)、[Description](/docs/components/description)、[FieldError](/docs/components/field-error))有各自的 CSS 类与样式。请参阅各自文档了解自定义选项。ColorField.Group 样式见下方 API 参考。
### 交互状态
ColorField 根据状态自动管理以下 data 属性:
* **Invalid**:`[data-invalid="true"]` 或 `[aria-invalid="true"]` - 无效时自动隐藏 description slot
* **Required**:`[data-required="true"]` - `isRequired` 为 true 时应用
* **Disabled**:`[data-disabled="true"]` - `isDisabled` 为 true 时应用
* **Focus Within**:`[data-focus-within="true"]` - 任一子 input 聚焦时应用
## API 参考
### ColorField
ColorField 继承 React Aria [ColorField](https://react-aria.adobe.com/ColorField.md) 组件的所有属性。
#### Base Props
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------------------------------------------------------------------------- | ------- | ---------------------------------------- |
| `children` | `React.ReactNode \| (values: ColorFieldRenderProps) => React.ReactNode` | - | 子组件(Label、ColorField.Group 等)或 render 函数 |
| `className` | `string \| (values: ColorFieldRenderProps) => string` | - | CSS 类,支持 render props |
| `style` | `React.CSSProperties \| (values: ColorFieldRenderProps) => React.CSSProperties` | - | 内联样式,支持 render props |
| `fullWidth` | `boolean` | `false` | 是否占满容器宽度 |
| `id` | `string` | - | 元素唯一标识符 |
| `render` | `DOMRenderFunction` | - | 使用自定义 render 函数覆盖默认 DOM 元素 |
#### Value Props
| Prop | 类型 | 默认值 | 描述 |
| -------------- | -------------------------------- | --- | -------- |
| `value` | `Color \| null` | - | 当前值(受控) |
| `defaultValue` | `Color \| null` | - | 默认值(非受控) |
| `onChange` | `(color: Color \| null) => void` | - | 值变化时的回调 |
#### Channel Props
| Prop | 类型 | 默认值 | 描述 |
| ------------ | -------------- | --- | ------------------------- |
| `colorSpace` | `ColorSpace` | - | 提供 `channel` 时颜色字段操作的颜色空间 |
| `channel` | `ColorChannel` | - | 要编辑的颜色通道。未提供时编辑 hex 值 |
#### Validation Props
| Prop | 类型 | 默认值 | 描述 |
| -------------------- | ---------------------------------------------------------------- | ---------- | ------------------------ |
| `isRequired` | `boolean` | `false` | 表单提交前是否必须输入 |
| `isInvalid` | `boolean` | - | 值是否无效 |
| `validate` | `(value: Color) => ValidationError \| true \| null \| undefined` | - | 自定义验证函数 |
| `validationBehavior` | `'native' \| 'aria'` | `'native'` | 使用原生 HTML 表单验证还是 ARIA 属性 |
#### State Props
| Prop | 类型 | 默认值 | 描述 |
| ----------------- | --------- | --- | ---------- |
| `isDisabled` | `boolean` | - | 是否禁用 |
| `isReadOnly` | `boolean` | - | 是否可选中但不可更改 |
| `isWheelDisabled` | `boolean` | - | 是否禁用滚轮更改值 |
#### Form Props
| Prop | 类型 | 默认值 | 描述 |
| ----------- | --------- | --- | ---------------------- |
| `name` | `string` | - | HTML 表单提交时 input 元素的名称 |
| `autoFocus` | `boolean` | - | 渲染时是否自动聚焦 |
#### Accessibility Props
| Prop | 类型 | 默认值 | 描述 |
| ------------------ | -------- | --- | ------------ |
| `aria-label` | `string` | - | 无可见标签时的无障碍标签 |
| `aria-labelledby` | `string` | - | 标注此字段的元素 ID |
| `aria-describedby` | `string` | - | 描述此字段的元素 ID |
| `aria-details` | `string` | - | 包含附加详情的元素 ID |
### Composition Components
ColorField 与以下需单独导入并直接使用的组件配合:
* **Label** - 来自 `@heroui/react` 的字段标签组件
* **ColorField.Group** - 颜色输入组组件(见下方文档)
* **ColorField.Input** - ColorField.Group 内的 input 元素
* **ColorField.Prefix** / **ColorField.Suffix** - 输入组的前缀与后缀 slot
* **ColorSwatch** - 来自 `@heroui/react` 的颜色预览组件
* **Description** - 来自 `@heroui/react` 的帮助文本组件
* **FieldError** - 来自 `@heroui/react` 的验证错误消息
每个组件有各自的 props API。在 ColorField 内直接使用它们进行组合:
```tsx
import {ColorField, Label, ColorSwatch, Description, FieldError, parseColor} from '@heroui/react';
Brand Color
Select your brand's primary color.
Please enter a valid color.
```
### Color Types
ColorField 使用 React Aria Components 的 `Color` 对象:
```tsx
import {parseColor} from '@heroui/react';
// Parse from hex string
const color = parseColor('#3B82F6');
// Get hex string from color
const hex = color.toString('hex'); // "#3b82f6"
// Get RGB values
const rgb = color.toString('rgb'); // "rgb(59, 130, 246)"
// Use in ColorField
{/* ... */}
```
### Render Props
对 `className`、`style` 或 `children` 使用 render props 时,可使用以下值:
| Prop | 类型 | 描述 |
| ---------------- | --------- | ------------ |
| `isDisabled` | `boolean` | 字段是否禁用 |
| `isInvalid` | `boolean` | 字段是否当前无效 |
| `isReadOnly` | `boolean` | 字段是否只读 |
| `isRequired` | `boolean` | 字段是否必填 |
| `isFocused` | `boolean` | 字段是否当前聚焦 |
| `isFocusWithin` | `boolean` | 是否有子元素聚焦 |
| `isFocusVisible` | `boolean` | 焦点是否可见(键盘导航) |
### ColorField.Group
ColorField.Group 接受 React Aria `Group` 组件的所有属性,以及以下属性:
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------------------------------------------------------------------ | ----------- | --------------------------------------------------------- |
| `className` | `string` | - | 与组件样式合并的 Tailwind 类 |
| `fullWidth` | `boolean` | `false` | 颜色输入组是否占满容器宽度 |
| `variant` | `"primary" \| "secondary"` | `"primary"` | 视觉变体。`primary` 为默认带阴影样式;`secondary` 为低强调无阴影,适用于 Surface 内 |
| `render` | `DOMRenderFunction` | - | 使用自定义 render 函数覆盖默认 DOM 元素 |
### ColorField.Input
ColorField.Input 接受 React Aria `Input` 组件的所有属性,以及以下属性:
| Prop | 类型 | 默认值 | 描述 |
| ------------- | -------- | --- | ------------------- |
| `className` | `string` | - | 与组件样式合并的 Tailwind 类 |
| `placeholder` | `string` | - | 为空时显示的占位文本 |
### ColorField.Prefix
ColorField.Prefix 接受标准 HTML `div` 属性:
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | ------------------- |
| `className` | `string` | - | 与组件样式合并的 Tailwind 类 |
| `children` | `ReactNode` | - | 前缀 slot 中显示的内容 |
### ColorField.Suffix
ColorField.Suffix 接受标准 HTML `div` 属性:
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | ------------------- |
| `className` | `string` | - | 与组件样式合并的 Tailwind 类 |
| `children` | `ReactNode` | - | 后缀 slot 中显示的内容 |
## ColorField.Group Styling
### Customizing the component classes
基础类驱动每个实例。使用 `@layer components` 一次性覆盖。
```css
@layer components {
.color-input-group {
@apply inline-flex h-9 items-center overflow-hidden rounded-field border bg-field text-sm text-field-foreground shadow-field outline-none;
&:hover,
&[data-hovered="true"] {
@apply bg-field-hover;
}
&[data-focus-within="true"],
&:focus-within {
@apply status-focused-field;
}
&[data-invalid="true"] {
@apply status-invalid-field;
}
&[data-disabled="true"],
&[aria-disabled="true"] {
@apply status-disabled;
}
}
.color-input-group__input {
@apply flex flex-1 items-center rounded-none border-0 bg-transparent px-3 py-2 shadow-none outline-none;
}
.color-input-group__prefix,
.color-input-group__suffix {
@apply shrink-0 text-field-placeholder flex items-center;
}
}
```
### ColorField.Group CSS Classes
* `.color-input-group` – 根容器样式
* `.color-input-group__input` – Input 包装器样式
* `.color-input-group__prefix` – 前缀元素样式
* `.color-input-group__suffix` – 后缀元素样式
### ColorField.Group Interactive States
* **Hover**:`:hover` 或 `[data-hovered="true"]`
* **Focus Within**:`[data-focus-within="true"]` 或 `:focus-within`
* **Invalid**:`[data-invalid="true"]`(与 `aria-invalid` 同步)
* **Disabled**:`[data-disabled="true"]` 或 `[aria-disabled="true"]`
## 相关组件
## Related Components
* **ColorSwatch**: Visual preview of a color value
* **ColorSwatchPicker**: Color swatch selection from a list of colors
* **ColorPicker**: Composable color picker with popover
# ColorPicker 颜色选择器
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/color-picker
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(colors)/color-picker.mdx
> 可组合的颜色选择器,在多个颜色组件间同步颜色值
## 用法
```tsx
import {
ColorPicker,
ColorArea,
ColorSlider,
ColorSwatch,
ColorField,
ColorSwatchPicker,
} from '@heroui/react';
```
```tsx
import {ColorArea, ColorPicker, ColorSlider, ColorSwatch, Label} from "@heroui/react";
export function Basic() {
return (
选择颜色
色相
);
}
```
## 组件结构
ColorPicker 是组合多个颜色组件的可组合组件:
```tsx
import { ColorPicker, ColorArea, ColorSlider, ColorSwatch, Label } from '@heroui/react';
export default () => (
Pick a color
);
```
## 示例
### 受控组件
```tsx
"use client";
import {
Button,
ColorArea,
ColorField,
ColorPicker,
ColorSlider,
ColorSwatch,
ColorSwatchPicker,
Label,
parseColor,
} from "@heroui/react";
import {Icon} from "@iconify/react";
import {useState} from "react";
export function Controlled() {
const [color, setColor] = useState(parseColor("#325578"));
const colorPresets = [
"#ef4444",
"#f97316",
"#eab308",
"#22c55e",
"#06b6d4",
"#3b82f6",
"#8b5cf6",
"#ec4899",
"#f43f5e",
];
const shuffleColor = () => {
const randomHue = Math.floor(Math.random() * 360);
const randomSaturation = 50 + Math.floor(Math.random() * 50); // 50-100%
const randomLightness = 40 + Math.floor(Math.random() * 30); // 40-70%
setColor(parseColor(`hsl(${randomHue}, ${randomSaturation}%, ${randomLightness}%)`));
};
return (
选择颜色
{colorPresets.map((preset) => (
))}
已选:{color.toString("hex")}
);
}
```
### 带色板
```tsx
import {
ColorArea,
ColorPicker,
ColorSlider,
ColorSwatch,
ColorSwatchPicker,
Label,
} from "@heroui/react";
export function WithSwatches() {
const presets = [
"#ef4444",
"#f97316",
"#eab308",
"#22c55e",
"#06b6d4",
"#3b82f6",
"#8b5cf6",
"#ec4899",
"#f43f5e",
];
return (
品牌色
色相
{presets.map((preset) => (
))}
);
}
```
### 带输入字段
使用 `ColorField` 允许用户编辑单个颜色通道值,配合 `Select` 切换颜色空间。
```tsx
"use client";
import type {ColorChannel, ColorSpace} from "@heroui/react";
import {
ColorArea,
ColorField,
ColorPicker,
ColorSlider,
ColorSwatch,
Label,
ListBox,
Select,
} from "@heroui/react";
import {useState} from "react";
const CHANNEL_LABELS: Record = {
alpha: "透明度",
blue: "蓝",
brightness: "亮度",
green: "绿",
hue: "色相",
lightness: "明度",
red: "红",
saturation: "饱和度",
};
export function WithFields() {
const [colorSpace, setColorSpace] = useState("hsl");
const colorChannelsByColorSpace: Record = {
hsb: ["hue", "saturation", "brightness"],
hsl: ["hue", "saturation", "lightness"],
rgb: ["red", "green", "blue"],
};
return (
选择颜色
色相
setColorSpace(value as ColorSpace)}
>
{Object.keys(colorChannelsByColorSpace).map((space) => (
{space}
))}
{colorChannelsByColorSpace[colorSpace].map((channel) => (
))}
);
}
```
### 带滑块
使用多个 `ColorSlider` 组件调整颜色值的各通道。
```tsx
"use client";
import type {ColorChannel, ColorSpace} from "@heroui/react";
import {ColorPicker, ColorSlider, ColorSwatch, Label, ListBox, Select} from "@heroui/react";
import {useState} from "react";
const CHANNEL_LABELS: Record = {
alpha: "透明度",
blue: "蓝",
brightness: "亮度",
green: "绿",
hue: "色相",
lightness: "明度",
red: "红",
saturation: "饱和度",
};
export function WithSliders() {
const [colorSpace, setColorSpace] = useState("hsl");
const colorChannelsByColorSpace: Record = {
hsb: ["hue", "saturation", "brightness", "alpha"],
hsl: ["hue", "saturation", "lightness", "alpha"],
rgb: ["red", "green", "blue", "alpha"],
};
return (
选择颜色
setColorSpace(value as ColorSpace)}
>
{Object.keys(colorChannelsByColorSpace).map((space) => (
{space}
))}
{colorChannelsByColorSpace[colorSpace].map((channel: ColorChannel) => (
// @ts-expect-error - TypeScript can't correlate dynamic colorSpace with channel type
{CHANNEL_LABELS[channel]}
))}
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {ColorArea, ColorPicker, ColorSlider, ColorSwatch, Label} from "@heroui/react";
export function CustomStyles() {
return (
主题色
色相
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 ColorPicker 组件类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.color-picker {
@apply inline-flex;
}
.color-picker__trigger {
@apply inline-flex items-center gap-4 rounded-lg;
}
.color-picker__popover {
@apply p-4 rounded-xl;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
ColorPicker 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/color-picker.css)):
#### 基础类 \[!toc]
* `.color-picker` - 基础容器
* `.color-picker__trigger` - 触发按钮
* `.color-picker__popover` - 弹出层容器
### 交互状态
组件同时支持 CSS 伪类与 data 属性:
* **Focus**:`:focus-visible` 或 `[data-focus-visible="true"]`
* **Disabled**:`:disabled` 或 `[data-disabled="true"]`
## API 参考
### ColorPicker
继承自 [React Aria ColorPicker](https://react-spectrum.adobe.com/react-aria/ColorPicker.html)。
| Prop | 类型 | 默认值 | 描述 |
| -------------- | ------------------------ | --- | -------------------------- |
| `value` | `string \| Color` | - | 当前颜色值(受控) |
| `defaultValue` | `string \| Color` | - | 默认颜色值(非受控) |
| `onChange` | `(color: Color) => void` | - | 颜色变化时的回调 |
| `children` | `React.ReactNode` | - | 颜色选择器内容(Trigger、Popover 等) |
| `className` | `string` | - | 附加 CSS 类 |
### ColorPicker.Trigger
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------------------------------------------------- | --- | ------------------ |
| `children` | `React.ReactNode \| ((renderProps) => React.ReactNode)` | - | 触发器内容或 render prop |
| `className` | `string` | - | 附加 CSS 类 |
### ColorPicker.Popover
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --------------- | -------- |
| `placement` | `Placement` | `"bottom left"` | 弹出层位置 |
| `children` | `React.ReactNode` | - | 弹出层内容 |
| `className` | `string` | - | 附加 CSS 类 |
### Related Types
#### Color
表示颜色值。完整 API 请参阅 [React Aria Color](https://react-spectrum.adobe.com/react-aria/ColorPicker.html#color)。
| Method | Description |
| ---------------------------------- | ----------------------------------- |
| `toString(format)` | 将颜色转换为指定格式的字符串(hex、rgb、hsl、hsb、css) |
| `toFormat(format)` | 将颜色转换为指定格式并返回新的 Color 对象 |
| `getChannelValue(channel)` | 返回指定通道的数值 |
| `withChannelValue(channel, value)` | 设置通道数值并返回新的 Color |
#### parseColor
```tsx
import { parseColor } from 'react-aria-components';
// Parse from string
const color = parseColor('#ff0000');
const hslColor = parseColor('hsl(0, 100%, 50%)');
```
## 相关组件
## Related Components
* **ColorArea**: 2D color picker for selecting colors from a gradient area
* **ColorSlider**: Slider for adjusting individual color channel values
* **ColorSwatch**: Visual preview of a color value
# ColorSlider 颜色滑块
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/color-slider
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(colors)/color-slider.mdx
> 颜色滑块允许用户调整颜色值的单个通道
## 用法
```tsx
import { ColorSlider, Label } from '@heroui/react';
```
```tsx
import {ColorSlider, Label} from "@heroui/react";
export function Basic() {
return (
色相
);
}
```
## 组件结构
```tsx
import { ColorSlider, Label } from '@heroui/react';
export default () => (
Hue
)
```
## 示例
### 禁用
```tsx
import {ColorSlider, Label} from "@heroui/react";
export function Disabled() {
return (
色相
);
}
```
### 垂直方向
```tsx
import {ColorSlider} from "@heroui/react";
export function Vertical() {
return (
);
}
```
### 受控组件
```tsx
"use client";
import {ColorSlider, ColorSwatch, Label} from "@heroui/react";
import {useState} from "react";
import {parseColor} from "react-aria-components";
export function Controlled() {
const [color, setColor] = useState(parseColor("hsl(200, 100%, 50%)"));
return (
色相
当前颜色:{color.toString("hsl")}
);
}
```
### HSL 通道
使用多个 ColorSlider 控制颜色值的不同通道。滑块可共享同一颜色值以构建完整颜色选择器。
```tsx
"use client";
import {ColorSlider, ColorSwatch, Label} from "@heroui/react";
import {useState} from "react";
import {parseColor} from "react-aria-components";
export function Channels() {
const [color, setColor] = useState(parseColor("hsl(0, 100%, 50%)"));
return (
色相
饱和度
明度
当前颜色:{color.toString("hsl")}
);
}
```
### 透明度通道
Alpha 通道滑块显示透明棋盘格图案,帮助可视化透明度级别。
```tsx
import {ColorSlider, Label} from "@heroui/react";
export function AlphaChannel() {
return (
透明度
);
}
```
### RGB 通道
也可使用 RGB 颜色空间的红、绿、蓝通道。
```tsx
"use client";
import {ColorSlider, ColorSwatch, Label} from "@heroui/react";
import {useState} from "react";
import {parseColor} from "react-aria-components";
export function RGBChannels() {
const [color, setColor] = useState(parseColor("rgb(255, 100, 50)"));
return (
红
绿
蓝
当前颜色:{color.toString("rgb")}
);
}
```
### 渲染函数
```tsx
"use client";
import {ColorSlider, Label} from "@heroui/react";
export function RenderFunction() {
return (
}
>
色相
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {ColorSlider, Label} from "@heroui/react";
export function CustomStyles() {
return (
色相
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 ColorSlider 组件类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.color-slider {
@apply flex flex-col gap-2;
}
.color-slider__output {
@apply text-muted text-sm;
}
.color-slider__track {
@apply relative h-5 w-full rounded-full;
}
.color-slider__thumb {
@apply size-4 rounded-full border-3 border-white shadow-overlay;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
ColorSlider 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/color-slider.css)):
#### 基础类 \[!toc]
* `.color-slider` - 基础滑块容器
* `.color-slider__output` - 显示当前值的输出元素
* `.color-slider__track` - 带颜色渐变的轨道元素
* `.color-slider__thumb` - 显示当前颜色的滑块元素
#### 状态类 \[!toc]
* `.color-slider[data-disabled="true"]` - 禁用滑块状态
* `.color-slider[data-orientation="vertical"]` - 垂直方向
* `.color-slider__thumb[data-dragging="true"]` - 滑块正在拖拽
* `.color-slider__thumb[data-focus-visible="true"]` - 滑块键盘聚焦
* `.color-slider__thumb[data-disabled="true"]` - 禁用滑块状态
### 交互状态
组件同时支持 CSS 伪类与 data 属性:
* **Hover**:滑块上的 `:hover` 或 `[data-hovered="true"]`
* **Focus**:滑块上的 `:focus-visible` 或 `[data-focus-visible="true"]`
* **Dragging**:滑块上的 `[data-dragging="true"]`
* **Disabled**:滑块或 thumb 上的 `:disabled` 或 `[data-disabled="true"]`
## API 参考
### ColorSlider
继承自 [React Aria ColorSlider](https://react-spectrum.adobe.com/react-aria/ColorSlider.html)。
| Prop | 类型 | 默认值 | 描述 |
| -------------- | ------------------------------------------------------------------------------ | -------------- | ------------------------------------------------------------------- |
| `channel` | `ColorChannel` | - | 滑块操作的颜色通道(hue、saturation、lightness、brightness、alpha、red、green、blue) |
| `colorSpace` | `ColorSpace` | - | 颜色空间(hsl、hsb、rgb)。默认为值的颜色空间 |
| `value` | `string \| Color` | - | 当前颜色值(受控) |
| `defaultValue` | `string \| Color` | - | 默认颜色值(非受控) |
| `onChange` | `(value: Color) => void` | - | 拖拽过程中值变化时的回调 |
| `onChangeEnd` | `(value: Color) => void` | - | 拖拽结束时的回调 |
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | 滑块方向 |
| `isDisabled` | `boolean` | - | 是否禁用 |
| `name` | `string` | - | 表单提交时 input 元素的名称 |
| `aria-label` | `string` | - | 滑块的无障碍标签 |
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `ReactNode \| RenderFunction` | - | 滑块内容或 render 函数 |
| `render` | `DOMRenderFunction` | - | 使用自定义 render 函数覆盖默认 DOM 元素 |
### ColorSlider.Output
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------------------- | --- | --------------- |
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `ReactNode \| RenderFunction` | - | 输出内容或 render 函数 |
### ColorSlider.Track
| Prop | 类型 | 默认值 | 描述 |
| ----------- | --------------------------------- | --- | --------------- |
| `className` | `string` | - | 附加 CSS 类 |
| `style` | `CSSProperties \| RenderFunction` | - | 内联样式或 render 函数 |
| `children` | `ReactNode \| RenderFunction` | - | 轨道内容或 render 函数 |
### ColorSlider.Thumb
| Prop | 类型 | 默认值 | 描述 |
| ----------- | --------------------------------- | --- | --------------- |
| `className` | `string` | - | 附加 CSS 类 |
| `style` | `CSSProperties \| RenderFunction` | - | 内联样式或 render 函数 |
| `children` | `ReactNode \| RenderFunction` | - | 滑块内容或 render 函数 |
### Render Props
使用 render 函数时,提供以下值:
| Prop | 类型 | 描述 |
| ------------- | ---------------------------- | ------- |
| `state` | `ColorSliderState` | 颜色滑块的状态 |
| `color` | `Color` | 当前颜色值 |
| `orientation` | `"horizontal" \| "vertical"` | 滑块方向 |
| `isDisabled` | `boolean` | 是否禁用 |
## 无障碍
ColorSlider 组件实现 ARIA slider 模式,提供:
* 完整键盘导航支持(方向键、Home、End、Page Up/Down)
* 值变化的屏幕阅读器播报
* 正确的焦点管理
* 禁用状态支持
* 通过隐藏 input 元素集成 HTML 表单
* 支持 locale 感知值格式化的国际化
更多信息请参阅 [React Aria ColorSlider 文档](https://react-spectrum.adobe.com/react-aria/ColorSlider.html)。
## 相关组件
## Related Components
* **ColorSwatch**: Visual preview of a color value
* **ColorSwatchPicker**: Color swatch selection from a list of colors
* **ColorPicker**: Composable color picker with popover
# ColorSwatchPicker 颜色色块选择器
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/color-swatch-picker
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(colors)/color-swatch-picker.mdx
> 允许用户从预置调色板中选择颜色的 swatch 列表
## 用法
```tsx
import { ColorSwatchPicker, parseColor } from '@heroui/react';
```
```tsx
import {ColorSwatchPicker} from "@heroui/react";
const colors = ["#F43F5E", "#D946EF", "#8B5CF6", "#3B82F6", "#06B6D4", "#10B981", "#84CC16"];
export function Basic() {
return (
{colors.map((color) => (
))}
);
}
```
## 组件结构
```tsx
import { ColorSwatchPicker } from '@heroui/react';
export default () => (
);
```
## 示例
### 变体
```tsx
import {ColorSwatchPicker} from "@heroui/react";
const colors = ["#F43F5E", "#D946EF", "#8B5CF6", "#3B82F6", "#06B6D4", "#10B981", "#84CC16"];
export function Variants() {
return (
圆形(默认)
{colors.map((color) => (
))}
方形
{colors.map((color) => (
))}
);
}
```
### 尺寸
```tsx
import {ColorSwatchPicker} from "@heroui/react";
const colors = ["#F43F5E", "#D946EF", "#8B5CF6", "#3B82F6", "#06B6D4", "#10B981", "#84CC16"];
const sizes = ["xs", "sm", "md", "lg", "xl"] as const;
const SIZE_LABELS: Record<(typeof sizes)[number], string> = {
lg: "大",
md: "中",
sm: "小",
xl: "特大",
xs: "特小",
};
export function Sizes() {
return (
{sizes.map((size) => (
{SIZE_LABELS[size]}
{colors.map((color) => (
))}
))}
);
}
```
### 禁用
```tsx
import {ColorSwatchPicker} from "@heroui/react";
const colors = ["#F43F5E", "#D946EF", "#8B5CF6", "#3B82F6", "#06B6D4", "#10B981", "#84CC16"];
export function Disabled() {
return (
{colors.map((color) => (
))}
);
}
```
### 堆叠布局
```tsx
import {ColorSwatchPicker} from "@heroui/react";
const colors = ["#F43F5E", "#D946EF", "#8B5CF6", "#3B82F6", "#06B6D4", "#10B981", "#84CC16"];
export function StackLayout() {
return (
{colors.map((color) => (
))}
);
}
```
### 默认值
```tsx
import {ColorSwatchPicker} from "@heroui/react";
const colors = ["#F43F5E", "#D946EF", "#8B5CF6", "#3B82F6", "#06B6D4", "#10B981", "#84CC16"];
export function DefaultValue() {
return (
{colors.map((color) => (
))}
);
}
```
### 受控组件
```tsx
"use client";
import {ColorSwatchPicker, parseColor} from "@heroui/react";
import {useState} from "react";
const colors = ["#F43F5E", "#D946EF", "#8B5CF6", "#3B82F6", "#06B6D4", "#10B981", "#84CC16"];
export function Controlled() {
const [value, setValue] = useState(parseColor("#F43F5E"));
return (
{colors.map((color) => (
))}
已选:{value.toString("hex")}
);
}
```
### 自定义指示器
```tsx
import {HeartFill} from "@gravity-ui/icons";
import {ColorSwatchPicker} from "@heroui/react";
export function CustomIndicator() {
const colors = ["#F43F5E", "#D946EF", "#8B5CF6", "#3B82F6", "#06B6D4", "#10B981", "#84CC16"];
return (
{colors.map((color) => (
))}
);
}
```
### 渲染函数
```tsx
"use client";
import {ColorSwatchPicker} from "@heroui/react";
const colors = ["#F43F5E", "#D946EF", "#8B5CF6", "#3B82F6", "#06B6D4", "#10B981", "#84CC16"];
export function RenderFunction() {
return (
}>
{colors.map((color) => (
))}
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {ColorSwatchPicker} from "@heroui/react";
const colors = ["#F43F5E", "#D946EF", "#8B5CF6", "#3B82F6", "#06B6D4", "#10B981", "#84CC16"];
export function CustomStyles() {
return (
{colors.map((color) => (
))}
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 ColorSwatchPicker 组件类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.color-swatch-picker {
@apply gap-4;
}
.color-swatch-picker__item {
@apply shadow-md;
}
.color-swatch-picker__swatch {
@apply border-2 border-white;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
ColorSwatchPicker 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/color-swatch-picker.css)):
#### 基础与结构 \[!toc]
* `.color-swatch-picker` - 基础容器(flex 布局)
* `.color-swatch-picker__item` - 单个 swatch 包裹层
* `.color-swatch-picker__swatch` - swatch 视觉元素
#### 尺寸类 \[!toc]
* `.color-swatch-picker--xs` - 特小(16px)
* `.color-swatch-picker--sm` - 小(24px)
* `.color-swatch-picker--md` - 中(32px,默认)
* `.color-swatch-picker--lg` - 大(36px)
* `.color-swatch-picker--xl` - 特大(40px)
#### 形状变体 \[!toc]
* `.color-swatch-picker--circle` - 圆形(默认)
* `.color-swatch-picker--square` - 圆角方形
#### 布局类 \[!toc]
* `.color-swatch-picker--grid` - 横向换行网格(默认)
* `.color-swatch-picker--stack` - 纵向堆叠
### 交互状态
组件同时支持 CSS 伪类与 data 属性:
* **Hover**:`:hover` 或 `[data-hovered="true"]` - 缩放至 1.1(仅在未选中时)
* **Focus**:`:focus-visible` 或 `[data-focus-visible="true"]` - 焦点环
* **Selected**:`[data-selected="true"]` - 与 swatch 同色的内边框
* **Disabled**:`[data-disabled="true"]` - 降低透明度
## API 参考
### ColorSwatchPicker
继承自 [React Aria ColorSwatchPicker](https://react-spectrum.adobe.com/react-aria/ColorSwatchPicker.html)。
| Prop | 类型 | 默认值 | 描述 |
| -------------- | ------------------------------------------------------------------------------------ | ---------- | -------------------------- |
| `value` | `string \| Color` | - | 当前选中颜色(受控) |
| `defaultValue` | `string \| Color` | - | 默认选中颜色(非受控) |
| `onChange` | `(value: Color) => void` | - | 选中变化时的回调 |
| `size` | `"xs" \| "sm" \| "md" \| "lg" \| "xl"` | `"md"` | swatch 尺寸 |
| `variant` | `"circle" \| "square"` | `"circle"` | swatch 形状 |
| `layout` | `"grid" \| "stack"` | `"grid"` | 布局方向 |
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `React.ReactNode` | - | ColorSwatchPicker.Item 元素 |
| `render` | `DOMRenderFunction` | - | 使用自定义 render 函数覆盖默认 DOM 元素 |
### ColorSwatchPicker.Item
| Prop | 类型 | 默认值 | 描述 |
| ------------ | ---------------------------------------------------------------------------------------- | ------- | --------------------------- |
| `color` | `string \| Color` | **必填** | swatch 颜色 |
| `isDisabled` | `boolean` | `false` | 是否禁用该项 |
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `React.ReactNode` | - | ColorSwatchPicker.Swatch 元素 |
| `render` | `DOMRenderFunction` | - | 使用自定义 render 函数覆盖默认 DOM 元素 |
### ColorSwatchPicker.Swatch
| Prop | 类型 | 默认值 | 描述 |
| ----------- | -------- | --- | -------- |
| `className` | `string` | - | 附加 CSS 类 |
### parseColor
为方便使用,从 React Aria Components 重新导出 `parseColor` 函数:
```tsx
import { parseColor } from '@heroui/react';
// 解析十六进制颜色
const red = parseColor('#ff0000');
// 解析 RGB
const green = parseColor('rgb(0, 255, 0)');
// 解析 HSL
const blue = parseColor('hsl(240, 100%, 50%)');
```
## 相关组件
## Related Components
* **ColorSwatch**: Visual preview of a color value
* **ColorField**: Input for entering color values with hex format
* **ColorArea**: 2D color picker for selecting colors from a gradient area
# ColorSwatch 颜色色块
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/color-swatch
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(colors)/color-swatch.mdx
> 颜色值的视觉预览,并提供无障碍支持
## 用法
```tsx
import { ColorSwatch } from '@heroui/react';
```
```tsx
import {ColorSwatch} from "@heroui/react";
export function ColorSwatchBasic() {
return (
);
}
```
## 示例
### 尺寸
```tsx
import {ColorSwatch} from "@heroui/react";
export function ColorSwatchSizes() {
return (
);
}
```
### 形状
```tsx
import {ColorSwatch} from "@heroui/react";
export function ColorSwatchShapes() {
return (
);
}
```
### 透明度
```tsx
import {ColorSwatch} from "@heroui/react";
export function ColorSwatchTransparency() {
return (
);
}
```
### 渲染函数
可使用 `style` render prop 读取颜色值并创建自定义视觉效果。
```tsx
"use client";
import {ColorSwatch} from "@heroui/react";
export function RenderFunction() {
return (
);
}
```
### 无障碍
使用 `colorName` 为颜色提供自定义可访问名称,并使用 `aria-label` 补充颜色用途的上下文。
```tsx
import {ColorSwatch} from "@heroui/react";
export function ColorSwatchAccessibility() {
return (
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
"use client";
import {ColorSwatch} from "@heroui/react";
export function ColorSwatchCustomStyles() {
const colors = ["#0485F7", "#EF4444", "#F59E0B", "#10B981", "#D946EF"];
return (
{/* 发光效果 */}
发光效果
{colors.map((color) => (
({
boxShadow: `0 0 20px 2px ${color}`,
})}
/>
))}
{/* 渐变色块 */}
渐变
{colors.map((color) => (
({
background: `linear-gradient(135deg, ${c.toString("css")}, white)`,
})}
/>
))}
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 ColorSwatch 组件类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.color-swatch {
@apply border-2 border-white;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
ColorSwatch 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/color-swatch.css)):
#### 基础类 \[!toc]
* `.color-swatch` - 基础 swatch 样式,透明区域使用棋盘格背景
#### 形状类 \[!toc]
* `.color-swatch--circle` - 圆形(默认)
* `.color-swatch--square` - 圆角方形
#### 尺寸类 \[!toc]
* `.color-swatch--xs` - 特小(16px)
* `.color-swatch--sm` - 小(24px)
* `.color-swatch--md` - 中(32px,默认)
* `.color-swatch--lg` - 大(36px)
* `.color-swatch--xl` - 特大(40px)
## API 参考
### ColorSwatch
| Prop | 类型 | 默认值 | 描述 |
| ------------ | ------------------------------------------------------------------------------ | ---------- | ----------------------------- |
| `color` | `string \| Color` | - | 要展示的颜色值(hex、rgb、hsl 等) |
| `colorName` | `string` | - | 颜色的可访问名称(会覆盖自动生成的描述) |
| `className` | `string` | - | 附加 CSS 类 |
| `shape` | `"circle" \| "square"` | `"circle"` | swatch 形状 |
| `size` | `"xs" \| "sm" \| "md" \| "lg" \| "xl"` | `"md"` | swatch 尺寸 |
| `style` | `CSSProperties \| ((renderProps) => CSSProperties)` | - | 行内样式,或带颜色访问能力的 render prop 函数 |
| `aria-label` | `string` | - | swatch 的无障碍标签 |
| `render` | `DOMRenderFunction` | - | 使用自定义 render 函数覆盖默认 DOM 元素 |
### Style Render
当把 `style` 作为函数传入时,会获得包含颜色对象在内的 render props:
```tsx
({
boxShadow: `0 4px 14px ${color.toString("css")}80`,
})}
/>
```
`color` 对象提供例如:
* `color.toString("css")` - 返回 CSS 颜色字符串
* `color.toString("hex")` - 返回十六进制颜色字符串
* `color.getChannelValue("alpha")` - 返回 alpha 通道数值
## 相关组件
## Related Components
* **ColorSwatchPicker**: Color swatch selection from a list of colors
* **ColorField**: Input for entering color values with hex format
* **ColorArea**: 2D color picker for selecting colors from a gradient area
# Slider 滑块
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/slider
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(controls)/slider.mdx
> Slider 允许用户在范围内选择一个或多个值。
## 用法
```tsx
import { Slider } from '@heroui/react';
```
```tsx
import {Label, Slider} from "@heroui/react";
export function Default() {
return (
音量
);
}
```
## 组件结构
```tsx
import { Slider, Label } from '@heroui/react';
export default () => (
)
```
## 示例
### 禁用
```tsx
import {Label, Slider} from "@heroui/react";
export function Disabled() {
return (
音量
);
}
```
### 范围滑块结构
```tsx
import { Slider, Label } from '@heroui/react';
export default () => (
{({state}) => (
<>
{state.values.map((_, i) => (
))}
>
)}
)
```
### 垂直方向
```tsx
import {Label, Slider} from "@heroui/react";
export function Vertical() {
return (
音量
);
}
```
### 范围选择
```tsx
"use client";
import {Label, Slider} from "@heroui/react";
export function Range() {
return (
价格区间
{({state}) => (
<>
{state.values.map((_, i) => (
))}
>
)}
);
}
```
### 渲染函数
```tsx
"use client";
import {Label, Slider} from "@heroui/react";
export function RenderFunction() {
return (
}
>
音量
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Label, Slider} from "@heroui/react";
export function CustomStyles() {
return (
亮度
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.slider {
@apply flex flex-col gap-2;
}
.slider__output {
@apply text-muted-fg text-sm;
}
.slider-track {
@apply relative h-2 w-full rounded-full bg-surface-secondary;
}
.slider-fill {
@apply absolute h-full rounded-full bg-accent;
}
.slider-thumb {
@apply size-4 rounded-full bg-accent border-2 border-background;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Slider 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/slider.css)):
#### 基础类 \[!toc]
* `.slider` - Slider 根容器
* `.slider__output` - 显示当前值的输出元素
* `.slider-track` - 包含填充与滑块的轨道元素
* `.slider-fill` - 显示已选范围的填充元素
* `.slider-thumb` - 单个滑块控制点
#### 状态类 \[!toc]
* `.slider[data-disabled="true"]` - 禁用状态
* `.slider[data-orientation="vertical"]` - 纵向方向
* `.slider-thumb[data-dragging="true"]` - 滑块正在拖动
* `.slider-thumb[data-focus-visible="true"]` - 滑块键盘聚焦
* `.slider-thumb[data-disabled="true"]` - 滑块禁用状态
* `.slider-track[data-fill-start="true"]` - 填充从起点开始
* `.slider-track[data-fill-end="true"]` - 填充在终点结束
### 交互状态
该组件同时支持 CSS 伪类与 data 属性,以提供更灵活的状态控制:
* **悬停**:滑块上的 `:hover` 或 `[data-hovered="true"]`
* **聚焦**:滑块上的 `:focus-visible` 或 `[data-focus-visible="true"]`
* **拖动**:滑块上的 `[data-dragging="true"]`
* **禁用**:Slider 或滑块上的 `:disabled` 或 `[data-disabled="true"]`
## API 参考
### Slider
| Prop | 类型 | 默认值 | 描述 |
| ----------------- | ------------------------------------------------------------------------- | -------------- | --------------------- |
| `value` | `number \| number[]` | - | 当前值(受控)。 |
| `defaultValue` | `number \| number[]` | - | 默认值(非受控)。 |
| `onChange` | `(value: number \| number[]) => void` | - | 值变化时的事件处理函数。 |
| `onChangeEnd` | `(value: number \| number[]) => void` | - | 拖动结束时的事件处理函数。 |
| `minValue` | `number` | `0` | Slider 的最小值。 |
| `maxValue` | `number` | `100` | Slider 的最大值。 |
| `step` | `number` | `1` | Slider 的步进值。 |
| `formatOptions` | `Intl.NumberFormatOptions` | - | 数值标签的显示格式。 |
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Slider 的方向。 |
| `isDisabled` | `boolean` | - | Slider 是否禁用。 |
| `aria-label` | `string` | - | Slider 的无障碍标签。 |
| `aria-labelledby` | `string` | - | 标注 Slider 的元素 ID。 |
| `className` | `string` | - | 额外的 CSS 类。 |
| `children` | `ReactNode \| RenderFunction` | - | Slider 内容或渲染函数。 |
| `render` | `DOMRenderFunction` | - | 使用自定义渲染函数覆盖默认 DOM 元素。 |
### Slider.Output
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------------------------------------------------------------------------- | --- | --------------------- |
| `className` | `string` | - | 额外的 CSS 类。 |
| `children` | `ReactNode \| RenderFunction` | - | 输出内容或渲染函数。 |
| `render` | `DOMRenderFunction` | - | 使用自定义渲染函数覆盖默认 DOM 元素。 |
### Slider.Track
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------------------------------------------------------------------------ | --- | --------------------- |
| `className` | `string` | - | 额外的 CSS 类。 |
| `children` | `ReactNode \| RenderFunction` | - | 轨道内容或渲染函数。 |
| `render` | `DOMRenderFunction` | - | 使用自定义渲染函数覆盖默认 DOM 元素。 |
### Slider.Fill
| Prop | 类型 | 默认值 | 描述 |
| ----------- | --------------- | --- | ---------- |
| `className` | `string` | - | 额外的 CSS 类。 |
| `style` | `CSSProperties` | - | 行内样式。 |
### Slider.Thumb
| Prop | 类型 | 默认值 | 描述 |
| ------------ | ------------------------------------------------------------------------------ | --- | --------------------- |
| `index` | `number` | `0` | 滑块在 Slider 内的索引。 |
| `isDisabled` | `boolean` | - | 该滑块是否禁用。 |
| `name` | `string` | - | 输入元素名称,用于提交 HTML 表单。 |
| `className` | `string` | - | 额外的 CSS 类。 |
| `children` | `ReactNode \| RenderFunction` | - | 滑块内容或渲染函数。 |
| `render` | `DOMRenderFunction` | - | 使用自定义渲染函数覆盖默认 DOM 元素。 |
### RenderProps
对 `Slider.Output` 或 `Slider.Track` 使用渲染函数时,会提供以下值:
| Prop | 类型 | 描述 |
| -------------------- | ---------------------------- | --------------- |
| `state` | `SliderState` | Slider 的状态。 |
| `values` | `number[]` | 按滑块索引管理的数值。 |
| `getThumbValueLabel` | `(index: number) => string` | 返回指定滑块数值的字符串标签。 |
| `orientation` | `"horizontal" \| "vertical"` | Slider 的方向。 |
| `isDisabled` | `boolean` | Slider 是否禁用。 |
## 示例
### 基本用法
```tsx
import { Slider, Label } from '@heroui/react';
Volume
```
### 范围滑块
```tsx
import { Slider, Label } from '@heroui/react';
Price Range
{({state}) => (
<>
{state.values.map((_, i) => (
))}
>
)}
```
### 受控数值
```tsx
import { Slider, Label } from '@heroui/react';
import { useState } from 'react';
function ControlledSlider() {
const [value, setValue] = useState(25);
return (
<>
Volume
Current value: {value}
>
);
}
```
### 自定义数值格式
```tsx
import { Slider, Label } from '@heroui/react';
Price
```
### 垂直方向
```tsx
import { Slider, Label } from '@heroui/react';
Volume
```
### 自定义输出展示
```tsx
import { Slider, Label } from '@heroui/react';
Range
{({state}) =>
state.values.map((_, i) => state.getThumbValueLabel(i)).join(' – ')
}
{({state}) => (
<>
{state.values.map((_, i) => (
))}
>
)}
```
## 无障碍
Slider 组件实现 ARIA slider 模式,并提供:
* 完整的键盘导航支持(方向键、Home、End、Page Up/Down)
* 数值变化时的屏幕阅读器播报
* 合理的焦点管理
* 禁用状态支持
* 通过隐藏 input 元素与 HTML 表单集成
* 结合区域设置进行数值格式化的国际化支持
* 从右到左(RTL)语言支持
更多信息见 [React Aria Slider 文档](https://react-spectrum.adobe.com/react-aria/Slider.html)。
## 相关组件
## Related Components
* **Label**: Accessible label for form controls
* **Form**: Form validation and submission handling
* **Description**: Helper text for form fields
# Switch 开关
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/switch
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(controls)/switch.mdx
> 用于布尔状态的开关组件。
## 用法
```tsx
import { Switch, SwitchGroup, Label } from '@heroui/react';
```
```tsx
import {Switch} from "@heroui/react";
export function Basic() {
return (
启用通知
);
}
```
## 组件结构
```tsx
import { Switch, Label, Description } from '@heroui/react';
export default () => (
{/* 可选 */}
{/* 可选 */}
);
```
要对多个 Switch 进行分组,请使用 `SwitchGroup` 组件:
```tsx
import { Switch, SwitchGroup, Label } from '@heroui/react';
export default () => (
Option 1
Option 2
);
```
## 示例
### 尺寸
```tsx
import {Switch} from "@heroui/react";
export function Sizes() {
return (
小
中
大
);
}
```
### 带图标
```tsx
"use client";
import {
BellFill,
BellSlash,
Check,
Microphone,
MicrophoneSlash,
Moon,
Power,
Sun,
VolumeFill,
VolumeSlashFill,
} from "@gravity-ui/icons";
import {Switch} from "@heroui/react";
export function WithIcons() {
const icons = {
check: {
off: Power,
on: Check,
selectedControlClass: "bg-green-500/80",
},
darkMode: {
off: Moon,
on: Sun,
selectedControlClass: "",
},
microphone: {
off: Microphone,
on: MicrophoneSlash,
selectedControlClass: "bg-red-500/80",
},
notification: {
off: BellSlash,
on: BellFill,
selectedControlClass: "bg-purple-500/80",
},
volume: {
off: VolumeFill,
on: VolumeSlashFill,
selectedControlClass: "bg-blue-500/80",
},
};
return (
{Object.entries(icons).map(([key, value]) => (
{({isSelected}) => (
{isSelected ? (
) : (
)}
)}
))}
);
}
```
### 禁用
```tsx
import {Switch} from "@heroui/react";
export function Disabled() {
return (
启用通知
);
}
```
### 无标签
```tsx
import {Switch} from "@heroui/react";
export function WithoutLabel() {
return (
);
}
```
### 带描述
```tsx
import {Description, Switch} from "@heroui/react";
export function WithDescription() {
return (
公开资料
允许他人查看你的资料信息
);
}
```
### 默认选中
```tsx
import {Switch} from "@heroui/react";
export function DefaultSelected() {
return (
启用通知
);
}
```
### 受控组件
```tsx
"use client";
import {Switch} from "@heroui/react";
import React from "react";
export function Controlled() {
const [isSelected, setIsSelected] = React.useState(false);
return (
启用通知
开关{isSelected ? "已打开" : "已关闭"}
);
}
```
### 标签位置
```tsx
import {Switch} from "@heroui/react";
export function LabelPosition() {
return (
标签在后
标签在前
);
}
```
### 分组
```tsx
import {Switch, SwitchGroup} from "@heroui/react";
export function Group() {
return (
允许通知
营销邮件
社交媒体更新
);
}
```
### 横向分组
```tsx
import {Switch, SwitchGroup} from "@heroui/react";
export function GroupHorizontal() {
return (
通知
营销
社交
);
}
```
### 表单集成
```tsx
"use client";
import {Button, Switch, SwitchGroup} from "@heroui/react";
import React from "react";
export function Form() {
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
alert(
`表单提交内容:\n${Array.from(formData.entries())
.map(([key, value]) => `${key}: ${value}`)
.join("\n")}`,
);
};
return (
启用通知
订阅新闻简报
接收营销更新
Submit
);
}
```
### 渲染属性
```tsx
"use client";
import {Switch} from "@heroui/react";
export function RenderProps() {
return (
{({isSelected}) => (
{isSelected ? "已开启" : "已关闭"}
)}
);
}
```
### 渲染函数
```tsx
"use client";
import {Switch} from "@heroui/react";
export function RenderFunction() {
return (
}>
启用通知
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
"use client";
import {Description, Label, Switch} from "@heroui/react";
export function CustomStyles() {
return (
自动保存草稿
输入时会自动保存更改。
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.switch {
@apply inline-flex gap-3 items-center;
}
.switch__control {
@apply h-5 w-8 bg-gray-400 data-[selected=true]:bg-blue-500;
}
.switch__thumb {
@apply bg-white shadow-sm;
}
.switch__content {
@apply flex flex-col gap-1;
}
.switch__icon {
@apply h-3 w-3 text-current;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
#### Switch 类 \[!toc]
Switch 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/switch.css)):
* `.switch` - Switch 根容器(字段)
* `.switch__content` - 包裹控件与标签文本的可点击 label
* `.switch__control` - Switch 轨道
* `.switch__thumb` - 可移动的滑块
* `.switch__icon` - 滑块内可选图标
* `.switch--sm` - 小尺寸变体
* `.switch--md` - 中尺寸变体(默认)
* `.switch--lg` - 大尺寸变体
#### SwitchGroup 类 \[!toc]
SwitchGroup 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/switch-group.css)):
* `.switch-group` - Switch 组容器
* `.switch-group__items` - Switch 项容器
* `.switch-group--horizontal` - 横向布局
* `.switch-group--vertical` - 纵向布局(默认)
### 交互状态
该 Switch 同时支持 CSS 伪类与 data 属性,以提供更灵活的状态控制:
* **已选中**:`[data-selected="true"]`(滑块位置与背景色变化)
* **悬停**:`:hover` 或 `[data-hovered="true"]`(作用于 `Switch.Control` / 按钮)
* **聚焦**:`:focus-visible` 或 `[data-focus-visible="true"]`(在按钮上显示轨道焦点环)
* **禁用**:`[data-disabled="true"]`(降低透明度,包括帮助文本)
* **按压**:`:active` 或 `[data-pressed="true"]`
## API 参考
### Switch
继承自 [React Aria SwitchField](https://react-spectrum.adobe.com/react-aria/Switch.html)。
| Prop | 类型 | 默认值 | 描述 |
| -------------------- | ------------------------------------------------------------------------------ | ---------- | ---------------------- |
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Switch 尺寸。 |
| `isSelected` | `boolean` | `false` | Switch 是否打开。 |
| `defaultSelected` | `boolean` | `false` | 默认是否打开(非受控)。 |
| `isDisabled` | `boolean` | `false` | Switch 是否禁用。 |
| `isInvalid` | `boolean` | `false` | Switch 是否无效。 |
| `isReadOnly` | `boolean` | `false` | Switch 是否只读。 |
| `isRequired` | `boolean` | `false` | Switch 是否必须打开。 |
| `validate` | `(value: boolean) => ValidationError \| true \| null \| undefined` | - | 自定义校验函数。 |
| `validationBehavior` | `'native' \| 'aria'` | `'native'` | 使用原生 HTML 校验或 ARIA 校验。 |
| `name` | `string` | - | 输入元素名称,用于提交 HTML 表单。 |
| `value` | `string` | - | 输入元素值,用于提交 HTML 表单。 |
| `onChange` | `(isSelected: boolean) => void` | - | Switch 值变化时的事件处理函数。 |
| `onPress` | `(e: PressEvent) => void` | - | Switch 被按下时的事件处理函数。 |
| `children` | `React.ReactNode \| (values: SwitchFieldRenderProps) => React.ReactNode` | - | Switch 内容或字段级渲染 prop。 |
| `render` | `DOMRenderFunction` | - | 使用自定义渲染函数覆盖默认 DOM 元素。 |
### Switch.Content
包裹控件与标签文本的可点击 ``。请把 `Switch.Control` 与 `Label` 放在它内部;`Description`/`FieldError` 作为 `Switch.Content` 的兄弟节点。对于没有标签的 switch,省略 `Label` 并在 `Switch` 上传入 `aria-label`。
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------------------------------------------------------------------- | --- | ------------------------- |
| `children` | `React.ReactNode \| (values: SwitchButtonRenderProps) => React.ReactNode` | - | 按钮内容(控件 + 标签),或按钮级渲染 prop |
| `className` | `string \| (values: SwitchButtonRenderProps) => string` | - | 应用到可点击 label 的类名 |
### SwitchFieldRenderProps
在根 `Switch` 上使用渲染 prop 时,提供以下字段级值:
| Prop | 类型 | 描述 |
| ------------ | ------------- | -------------- |
| `isSelected` | `boolean` | Switch 当前是否打开。 |
| `isDisabled` | `boolean` | Switch 是否禁用。 |
| `isReadOnly` | `boolean` | Switch 是否只读。 |
| `isInvalid` | `boolean` | Switch 是否无效。 |
| `isRequired` | `boolean` | Switch 是否必填。 |
| `state` | `ToggleState` | Switch 的状态。 |
### SwitchButtonRenderProps
`Switch.Control` 使用按钮级渲染 prop(`isHovered`、`isPressed`、`isFocusVisible` 等)。将函数作为 `Switch.Control` 的子元素即可访问。
### SwitchGroup
| Prop | 类型 | 默认值 | 描述 |
| ------------- | ---------------------------- | ------------ | -------------- |
| `orientation` | `'horizontal' \| 'vertical'` | `'vertical'` | Switch 组方向。 |
| `children` | `React.ReactNode` | - | 要渲染的 Switch 项。 |
| `className` | `string` | - | 额外的 CSS 类。 |
## 相关组件
## Related Components
* **Label**: Accessible label for form controls
* **Description**: Helper text for form fields
* **Button**: Allows a user to perform an action
# Badge 徽章
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/badge
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(data-display)/badge.mdx
> 相对其他元素定位的小型指示器,常用于通知数量、状态点与标签
## 用法
```tsx
import { Badge } from '@heroui/react';
```
```tsx
import {Avatar, Badge} from "@heroui/react";
const GREEN_AVATAR_URL = "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/green.jpg";
const ORANGE_AVATAR_URL =
"https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/orange.jpg";
const BLUE_AVATAR_URL = "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/blue.jpg";
export function BadgeBasic() {
return (
);
}
```
## 组件结构
Badge 通过 `Badge.Anchor` 相对其他元素定位。纯文本子节点会自动包裹在 `` 中。
> 独立标签用法请使用 [Chip](/docs/react/components/chip) 组件。
```tsx
5
```
## 示例
### 变体
```tsx
import {Avatar, Badge, Separator} from "@heroui/react";
import React from "react";
const AVATAR_URL = "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/green.jpg";
const variants = ["primary", "secondary", "soft"] as const;
const VARIANT_LABELS: Record<(typeof variants)[number], string> = {
primary: "主色",
secondary: "次色",
soft: "柔和",
};
const colors = ["accent", "default", "success", "warning", "danger"] as const;
export function BadgeVariants() {
return (
{variants.map((variant, index) => (
{VARIANT_LABELS[variant]}
{colors.map((color) => (
JD
5
))}
{index < variants.length - 1 && }
))}
);
}
```
### 尺寸
```tsx
import {Avatar, Badge} from "@heroui/react";
const AVATAR_URL = "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/green.jpg";
export function BadgeSizes() {
const sizes = ["sm", "md", "lg"] as const;
return (
{sizes.map((size) => (
JD
5
))}
);
}
```
### 颜色
```tsx
import {Avatar, Badge} from "@heroui/react";
const AVATAR_URL = "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/green.jpg";
export function BadgeColors() {
const colors = ["default", "accent", "success", "warning", "danger"] as const;
return (
{colors.map((color) => (
JD
))}
);
}
```
### 徽章位置
```tsx
import {Avatar, Badge} from "@heroui/react";
const AVATAR_URL = "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/green.jpg";
const placements = ["top-right", "top-left", "bottom-right", "bottom-left"] as const;
const PLACEMENT_LABELS: Record<(typeof placements)[number], string> = {
"bottom-left": "左下",
"bottom-right": "右下",
"top-left": "左上",
"top-right": "右上",
};
export function BadgePlacements() {
return (
{placements.map((placement) => (
JD
{PLACEMENT_LABELS[placement]}
))}
);
}
```
### 点状徽标
空徽章作为状态指示器,适用于在线/离线或活动信号。
```tsx
import {Avatar, Badge} from "@heroui/react";
const AVATAR_URL = "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/green.jpg";
export function BadgeDot() {
const colors = ["accent", "success", "warning", "danger"] as const;
return (
{colors.map((color) => (
JD
))}
);
}
```
### 带内容
Badge 支持文本、数字与图标。无子节点时渲染为点状指示器。
```tsx
import {Bell} from "@gravity-ui/icons";
import {Avatar, Badge} from "@heroui/react";
const AVATAR_URL = "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/green.jpg";
export function BadgeWithContent() {
return (
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Avatar, Badge} from "@heroui/react";
export function CustomStyles() {
return (
KW
5
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 Badge 组件类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.badge {
@apply rounded-full text-xs;
}
.badge__label {
@apply font-semibold;
}
.badge--accent {
@apply shadow-sm;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Badge 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/badge.css)):
#### 基础类 \[!toc]
* `.badge` - 基础徽章容器样式
* `.badge__label` - 标签文本 slot 样式
* `.badge-anchor` - 锚定元素的定位包装器
#### 颜色类 \[!toc]
* `.badge--accent` - 强调色变体
* `.badge--danger` - 危险色变体
* `.badge--default` - 默认色变体
* `.badge--success` - 成功色变体
* `.badge--warning` - 警告色变体
#### 变体类 \[!toc]
* `.badge--primary` - 填充背景的主变体
* `.badge--secondary` - 默认背景的次变体
* `.badge--soft` - 浅色背景的 soft 变体
#### 尺寸类 \[!toc]
* `.badge--sm` - 小尺寸
* `.badge--md` - 中尺寸(默认)
* `.badge--lg` - 大尺寸
#### 位置类 \[!toc]
* `.badge--top-right` - 右上角(默认)
* `.badge--top-left` - 左上角
* `.badge--bottom-right` - 右下角
* `.badge--bottom-left` - 左下角
#### 复合变体类 \[!toc]
Badge 支持组合变体与颜色类(如 `.badge--primary.badge--accent`)。以下组合有默认样式:
**Primary Variants:**
* `.badge--primary.badge--accent` - 填充背景的 primary accent
* `.badge--primary.badge--default` - 填充背景的 primary default
* `.badge--primary.badge--success` - 填充背景的 primary success
* `.badge--primary.badge--warning` - 填充背景的 primary warning
* `.badge--primary.badge--danger` - 填充背景的 primary danger
**Soft Variants:**
* `.badge--soft.badge--accent` - 浅色背景的 soft accent
* `.badge--soft.badge--default` - 浅色背景的 soft default
* `.badge--soft.badge--success` - 浅色背景的 soft success
* `.badge--soft.badge--warning` - 浅色背景的 soft warning
* `.badge--soft.badge--danger` - 浅色背景的 soft danger
## API 参考
### Badge
| Prop | 类型 | 默认值 | 描述 |
| ----------- | -------------------------------------------------------------- | ------------- | ---------------------- |
| `children` | `React.ReactNode` | - | 徽章内容(文本、数字或图标)。省略时渲染为点 |
| `className` | `string` | - | 根元素附加 CSS 类 |
| `color` | `"default" \| "accent" \| "success" \| "warning" \| "danger"` | `"default"` | 徽章颜色变体 |
| `variant` | `"primary" \| "secondary" \| "soft"` | `"primary"` | 视觉样式变体 |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | 徽章尺寸 |
| `placement` | `"top-right" \| "top-left" \| "bottom-right" \| "bottom-left"` | `"top-right"` | 相对锚点的位置 |
### Badge.Anchor
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --- | -------------- |
| `children` | `React.ReactNode` | - | 锚定元素及 Badge 本身 |
| `className` | `string` | - | 锚点包装器附加 CSS 类 |
### Badge.Label
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --- | ---------------- |
| `children` | `React.ReactNode` | - | 标签文本内容 |
| `className` | `string` | - | 标签 slot 附加 CSS 类 |
## 相关组件
## Related Components
* **Avatar**: Display user profile images
* **Chip**: Compact elements for tags and filters
# Chip 标签
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/chip
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(data-display)/chip.mdx
> 用于显示标签、状态与分类的小型信息徽章
## 用法
```tsx
import { Chip } from '@heroui/react';
```
```tsx
import {Chip} from "@heroui/react";
export function ChipBasic() {
return (
默认
强调
成功
警告
危险
);
}
```
## 组件结构
> 纯文本子节点会自动包裹在 `` 中。
```tsx
Label text
```
## 示例
### 变体
```tsx
import {CircleDashed} from "@gravity-ui/icons";
import {Chip, Separator} from "@heroui/react";
import React from "react";
const sizes = ["lg", "md", "sm"] as const;
const SIZE_LABELS: Record<(typeof sizes)[number], string> = {
lg: "大",
md: "中",
sm: "小",
};
const variants = ["primary", "secondary", "tertiary", "soft"] as const;
const VARIANT_LABELS: Record<(typeof variants)[number], string> = {
primary: "主要",
secondary: "次要",
soft: "柔和",
tertiary: "第三",
};
const colors = ["accent", "default", "success", "warning", "danger"] as const;
const COLOR_LABELS: Record<(typeof colors)[number], string> = {
accent: "强调",
danger: "危险",
default: "默认",
success: "成功",
warning: "警告",
};
export function ChipVariants() {
return (
{sizes.map((size, index) => (
{SIZE_LABELS[size]}
{colors.map((color) => (
{COLOR_LABELS[color]}
))}
{variants.map((variant) => (
{VARIANT_LABELS[variant]}
{colors.map((color) => (
标签
))}
))}
{index < sizes.length - 1 && }
))}
);
}
```
### 状态类型
```tsx
import {Ban, Check, CircleFill, CircleInfo, TriangleExclamation} from "@gravity-ui/icons";
import {Chip} from "@heroui/react";
export function ChipStatuses() {
return (
默认
活跃
待处理
未激活
新功能
可用
测试版
已弃用
);
}
```
### 带图标
```tsx
import {ChevronDown, CircleCheckFill, CircleFill, Clock, Xmark} from "@gravity-ui/icons";
import {Chip} from "@heroui/react";
export function ChipWithIcon() {
return (
信息
已完成
待处理
失败
标签
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Chip} from "@heroui/react";
export function CustomStyles() {
return (
草稿
审核中
已发布
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 Chip 组件类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.chip {
@apply rounded-full text-xs;
}
.chip__label {
@apply font-medium;
}
.chip--accent {
@apply border-accent/20;
}
.chip--accent .chip__label {
@apply text-accent;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Chip 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/chip.css)):
#### 基础类 \[!toc]
* `.chip` - 基础标签容器样式
* `.chip__label` - 标签文本 slot 样式
#### 颜色类 \[!toc]
* `.chip--accent` - 强调色变体
* `.chip--danger` - 危险色变体
* `.chip--default` - 默认色变体
* `.chip--success` - 成功色变体
* `.chip--warning` - 警告色变体
#### 变体类 \[!toc]
* `.chip--primary` - 填充背景的主变体
* `.chip--secondary` - 带边框的次变体
* `.chip--tertiary` - 透明背景的三级变体
* `.chip--soft` - 浅色背景的 soft 变体
#### 尺寸类 \[!toc]
* `.chip--sm` - 小尺寸
* `.chip--md` - 中尺寸(默认)
* `.chip--lg` - 大尺寸
#### 复合变体类 \[!toc]
Chip 支持组合变体与颜色类(如 `.chip--secondary.chip--accent`)。以下组合有默认样式:
**Primary Variants:**
* `.chip--primary.chip--accent` - 填充背景的 primary accent 组合
* `.chip--primary.chip--success` - 填充背景的 primary success 组合
* `.chip--primary.chip--warning` - 填充背景的 primary warning 组合
* `.chip--primary.chip--danger` - 填充背景的 primary danger 组合
**Soft Variants:**
* `.chip--accent.chip--soft` - 浅色背景的 soft accent 组合
* `.chip--success.chip--soft` - 浅色背景的 soft success 组合
* `.chip--warning.chip--soft` - 浅色背景的 soft warning 组合
* `.chip--danger.chip--soft` - 浅色背景的 soft danger 组合
**Note:** 可使用 CSS 中的 `@layer components` 指令为任意变体-颜色组合(如 `.chip--secondary.chip--accent`、`.chip--tertiary.chip--success`)应用自定义样式。
## API 参考
### Chip
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------------------------------------------------------- | ------------- | ----------- |
| `children` | `React.ReactNode` | - | 标签内显示的内容 |
| `className` | `string` | - | 根元素附加 CSS 类 |
| `color` | `"default" \| "accent" \| "success" \| "warning" \| "danger"` | `"default"` | 标签颜色变体 |
| `variant` | `"primary" \| "secondary" \| "tertiary" \| "soft"` | `"secondary"` | 视觉样式变体 |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | 标签尺寸 |
### Chip.Label
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --- | ---------------- |
| `children` | `React.ReactNode` | - | 标签文本内容 |
| `className` | `string` | - | 标签 slot 附加 CSS 类 |
## 相关组件
## Related Components
* **Avatar**: Display user profile images
* **CloseButton**: Button for dismissing overlays
* **Separator**: Visual divider between content
# Table 表格
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/table
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(data-display)/table.mdx
> 表格以行和列展示结构化数据,支持排序、选择、列宽调整与无限滚动。
## 用法
```tsx
import { Table } from '@heroui/react';
```
```tsx
import {Table} from "@heroui/react";
export function Basic() {
return (
姓名
角色
状态
邮箱
Kate Moore
首席执行官
在职
kate@acme.com
John Smith
首席技术官
在职
john@acme.com
Sara Johnson
首席营销官
休假
sara@acme.com
Michael Brown
首席财务官
在职
michael@acme.com
);
}
```
## 组件结构
```tsx
import { Table } from '@heroui/react';
export default () => (
{({ sortDirection }) => (
Name
)}
Role
Kate Moore
CEO
{/* Optional footer content */}
);
```
## 示例
### 次要变体
```tsx
import {Table} from "@heroui/react";
export function SecondaryVariant() {
return (
姓名
角色
状态
邮箱
Kate Moore
首席执行官
在职
kate@acme.com
John Smith
首席技术官
在职
john@acme.com
Sara Johnson
首席营销官
休假
sara@acme.com
Michael Brown
首席财务官
在职
michael@acme.com
);
}
```
### 异步加载
使用 `Table.LoadMore` 实现无限滚动。它会渲染一个哨兵行,滚动到视口时触发 `onLoadMore`。
```tsx
"use client";
import {Chip, Spinner, Table} from "@heroui/react";
import {useCallback, useRef, useState} from "react";
interface User {
id: number;
name: string;
role: string;
status: string;
email: string;
}
const statusColorMap: Record = {
休假: "warning",
在职: "success",
未激活: "danger",
};
const allUsers: User[] = [
{email: "kate@acme.com", id: 1, name: "Kate Moore", role: "首席执行官", status: "在职"},
{email: "john@acme.com", id: 2, name: "John Smith", role: "首席技术官", status: "在职"},
{email: "sara@acme.com", id: 3, name: "Sara Johnson", role: "首席营销官", status: "休假"},
{email: "michael@acme.com", id: 4, name: "Michael Brown", role: "首席财务官", status: "在职"},
{
email: "emily@acme.com",
id: 5,
name: "Emily Davis",
role: "产品经理",
status: "未激活",
},
{email: "davis@acme.com", id: 6, name: "Davis Wilson", role: "首席设计师", status: "在职"},
{
email: "olivia@acme.com",
id: 7,
name: "Olivia Martinez",
role: "前端工程师",
status: "在职",
},
{
email: "james@acme.com",
id: 8,
name: "James Taylor",
role: "后端工程师",
status: "在职",
},
{
email: "sophia@acme.com",
id: 9,
name: "Sophia Anderson",
role: "测试工程师",
status: "休假",
},
{email: "liam@acme.com", id: 10, name: "Liam Thomas", role: "DevOps 工程师", status: "在职"},
{
email: "lucas@acme.com",
id: 11,
name: "Lucas Martinez",
role: "产品经理",
status: "在职",
},
{
email: "emma@acme.com",
id: 12,
name: "Emma Johnson",
role: "前端工程师",
status: "在职",
},
{email: "noah@acme.com", id: 13, name: "Noah Davis", role: "后端工程师", status: "在职"},
{email: "ava@acme.com", id: 14, name: "Ava Wilson", role: "首席设计师", status: "在职"},
{
email: "oliver@acme.com",
id: 15,
name: "Oliver Martinez",
role: "前端工程师",
status: "在职",
},
{
email: "isabella@acme.com",
id: 16,
name: "Isabella Johnson",
role: "后端工程师",
status: "在职",
},
{email: "mia@acme.com", id: 17, name: "Mia Davis", role: "首席设计师", status: "在职"},
{
email: "william@acme.com",
id: 18,
name: "William Wilson",
role: "前端工程师",
status: "在职",
},
];
const ITEMS_PER_PAGE = 6;
const columns = [
{id: "name", name: "姓名"},
{id: "role", name: "角色"},
{id: "status", name: "状态"},
{id: "email", name: "邮箱"},
];
export function AsyncLoading() {
const [items, setItems] = useState(() => allUsers.slice(0, ITEMS_PER_PAGE));
const [isLoading, setIsLoading] = useState(false);
const isLoadingRef = useRef(false);
const hasMore = items.length < allUsers.length;
const loadMore = useCallback(() => {
if (!hasMore || isLoadingRef.current) return;
isLoadingRef.current = true;
setIsLoading(true);
setTimeout(() => {
setItems((prev) => allUsers.slice(0, prev.length + ITEMS_PER_PAGE));
setIsLoading(false);
requestAnimationFrame(() => {
isLoadingRef.current = false;
});
}, 1500);
}, [hasMore]);
return (
{columns.map((col) => (
{col.name}
))}
{(user) => (
{user.name}
{user.role}
{user.status}
{user.email}
)}
{!!hasMore && (
)}
);
}
```
### 排序
在 `Table.Column` 上使用 `allowsSorting` 属性可启用列排序。在 `Table.Content` 上使用 `sortDescriptor` 与 `onSortChange` 管理排序状态。将标签包裹在 `Table.SortableColumnHeader` 中,并将列 render prop 的 `sortDirection` 转发以渲染默认升序/降序指示器。
```tsx
"use client";
import type {SortDescriptor} from "@heroui/react";
import {Table} from "@heroui/react";
import {useMemo, useState} from "react";
interface User {
id: number;
name: string;
role: string;
status: string;
email: string;
}
const users: User[] = [
{email: "kate@acme.com", id: 1, name: "Kate Moore", role: "首席执行官", status: "在职"},
{email: "john@acme.com", id: 2, name: "John Smith", role: "首席技术官", status: "在职"},
{email: "sara@acme.com", id: 3, name: "Sara Johnson", role: "首席营销官", status: "休假"},
{email: "michael@acme.com", id: 4, name: "Michael Brown", role: "首席财务官", status: "在职"},
{
email: "emily@acme.com",
id: 5,
name: "Emily Davis",
role: "产品经理",
status: "未激活",
},
];
export function Sorting() {
const [sortDescriptor, setSortDescriptor] = useState({
column: "name",
direction: "ascending",
});
const sortedUsers = useMemo(() => {
return [...users].sort((a, b) => {
const col = sortDescriptor.column as keyof User;
const first = String(a[col]);
const second = String(b[col]);
let cmp = first.localeCompare(second);
if (sortDescriptor.direction === "descending") {
cmp *= -1;
}
return cmp;
});
}, [sortDescriptor]);
return (
{({sortDirection}) => (
姓名
)}
{({sortDirection}) => (
角色
)}
{({sortDirection}) => (
状态
)}
{({sortDirection}) => (
邮箱
)}
{sortedUsers.map((user) => (
{user.name}
{user.role}
{user.status}
{user.email}
))}
);
}
```
### 选择
在 `Table.Content` 上使用 `selectionMode` 启用行选择。使用 `slot="selection"` 的 `Checkbox` 实现全选与逐行勾选。
```tsx
"use client";
import type {Selection} from "@heroui/react";
import {Checkbox, Table} from "@heroui/react";
import {useState} from "react";
const users = [
{email: "kate@acme.com", id: 1, name: "Kate Moore", role: "首席执行官", status: "在职"},
{email: "john@acme.com", id: 2, name: "John Smith", role: "首席技术官", status: "在职"},
{email: "sara@acme.com", id: 3, name: "Sara Johnson", role: "首席营销官", status: "休假"},
{email: "michael@acme.com", id: 4, name: "Michael Brown", role: "首席财务官", status: "在职"},
];
export function SelectionDemo() {
const [selectedKeys, setSelectedKeys] = useState(new Set());
return (
姓名
角色
状态
邮箱
{users.map((user) => (
{user.name}
{user.role}
{user.status}
{user.email}
))}
已选:{" "}
{selectedKeys === "all"
? "全部"
: selectedKeys.size > 0
? Array.from(selectedKeys).join(", ")
: "无"}
);
}
```
### 可展开行
行可嵌套以展示层级数据。使用 `treeColumn` 指定列,并在该列单元格中渲染 `slot="chevron"` 的 `Button`,供用户展开/收起行。使用 `expandedKeys` 控制哪些行处于展开状态。
```tsx
"use client";
import type {Selection} from "@heroui/react";
import {Button, Table, cn} from "@heroui/react";
import {Icon} from "@iconify/react";
import {useState} from "react";
export function ExpandableRows() {
type Row = {
children: Row[];
date: string;
id: string;
title: string;
type: string;
};
const data: Row[] = [
{
children: [
{
children: [
{children: [], date: "7/10/2025", id: "3", title: "周报", type: "文件"},
{children: [], date: "8/20/2025", id: "4", title: "预算", type: "文件"},
],
date: "8/2/2025",
id: "2",
title: "项目",
type: "文件夹",
},
],
date: "10/20/2025",
id: "1",
title: "文档",
type: "文件夹",
},
{
children: [
{children: [], date: "1/23/2026", id: "6", title: "图片 1", type: "文件"},
{children: [], date: "2/3/2026", id: "7", title: "图片 2", type: "文件"},
],
date: "2/3/2026",
id: "5",
title: "照片",
type: "文件夹",
},
];
const [expandedKeys, setExpandedKeys] = useState(() => new Set(["1"]));
const renderExpandableRow = (item: Row) => {
return (
{({hasChildItems, isDisabled, isExpanded, isTreeColumn}) => (
{hasChildItems && isTreeColumn ? (
) : null}
{item.title}
)}
{item.type}
{item.date}
{renderExpandableRow}
);
};
return (
姓名
类型
修改日期
{renderExpandableRow}
);
}
```
### 分页
使用 `Table.Footer` 在表格下方添加分页组件。
```tsx
"use client";
import {Pagination, Table} from "@heroui/react";
import {useMemo, useState} from "react";
const columns = [
{id: "name", name: "姓名"},
{id: "role", name: "角色"},
{id: "status", name: "状态"},
{id: "email", name: "邮箱"},
];
const users = [
{email: "kate@acme.com", id: 1, name: "Kate Moore", role: "首席执行官", status: "在职"},
{email: "john@acme.com", id: 2, name: "John Smith", role: "首席技术官", status: "在职"},
{email: "sara@acme.com", id: 3, name: "Sara Johnson", role: "首席营销官", status: "休假"},
{email: "michael@acme.com", id: 4, name: "Michael Brown", role: "首席财务官", status: "在职"},
{
email: "emily@acme.com",
id: 5,
name: "Emily Davis",
role: "产品经理",
status: "未激活",
},
{email: "davis@acme.com", id: 6, name: "Davis Wilson", role: "首席设计师", status: "在职"},
{
email: "olivia@acme.com",
id: 7,
name: "Olivia Martinez",
role: "前端工程师",
status: "在职",
},
{
email: "james@acme.com",
id: 8,
name: "James Taylor",
role: "后端工程师",
status: "在职",
},
];
const ROWS_PER_PAGE = 4;
export function PaginationDemo() {
const [page, setPage] = useState(1);
const totalPages = Math.ceil(users.length / ROWS_PER_PAGE);
const pages = Array.from({length: totalPages}, (_, i) => i + 1);
const paginatedItems = useMemo(() => {
const start = (page - 1) * ROWS_PER_PAGE;
return users.slice(start, start + ROWS_PER_PAGE);
}, [page]);
const start = (page - 1) * ROWS_PER_PAGE + 1;
const end = Math.min(page * ROWS_PER_PAGE, users.length);
return (
{(column) => (
{column.name}
)}
{(user) => (
{(column) => {user[column.id as keyof typeof user]} }
)}
{start}–{end} / 共 {users.length} 条
setPage((p) => Math.max(1, p - 1))}
>
上一页
{pages.map((p) => (
setPage(p)}>
{p}
))}
setPage((p) => Math.min(totalPages, p + 1))}
>
下一页
);
}
```
### 列宽调整
将表格包裹在 `Table.ResizableContainer` 中,并在每个可调整宽度的列内添加 `Table.ColumnResizer`。
```tsx
import {Chip, Table} from "@heroui/react";
export function ColumnResizing() {
return (
姓名
角色
状态
邮箱
Kate Moore
首席执行官
Active
kate@acme.com
John Smith
首席技术官
Active
john@acme.com
Sara Johnson
首席营销官
On Leave
sara@acme.com
Michael Brown
首席财务官
Active
michael@acme.com
Emily Davis
产品经理
Inactive
emily@acme.com
);
}
```
### 空状态
在 `Table.Body` 上使用 `renderEmptyState`,在表格无数据时展示自定义消息。
```tsx
"use client";
import {EmptyState, Table} from "@heroui/react";
import {Icon} from "@iconify/react";
export function EmptyStateDemo() {
return (
姓名
角色
状态
邮箱
(
未找到结果
)}
>
{[]}
);
}
```
### 虚拟滚动
Table 通过 [Virtualizer](https://react-aria.adobe.com/Virtualizer) 支持虚拟化,仅渲染视口内可见行,从而高效展示大数据集。
```tsx
"use client";
import {Table, TableLayout, Virtualizer} from "@heroui/react";
interface User {
id: number;
name: string;
role: string;
email: string;
}
export function Virtualization() {
const roles = [
"软件工程师",
"高级工程师",
"资深工程师",
"产品经理",
"设计师",
"数据分析师",
"测试工程师",
"DevOps 工程师",
"营销经理",
"销售代表",
];
const firstNames = [
"Emma",
"Liam",
"Olivia",
"Noah",
"Ava",
"James",
"Sophia",
"Oliver",
"Isabella",
"Lucas",
"Mia",
"Ethan",
"Charlotte",
"Mason",
"Amelia",
"Logan",
"Harper",
"Alexander",
"Ella",
"Benjamin",
];
const lastNames = [
"Smith",
"Johnson",
"Williams",
"Brown",
"Jones",
"Garcia",
"Miller",
"Davis",
"Rodriguez",
"Martinez",
"Anderson",
"Taylor",
"Thomas",
"Jackson",
"White",
"Harris",
"Clark",
"Lewis",
"Robinson",
"Walker",
];
function generateUsers(count: number): User[] {
const users: User[] = [];
for (let i = 0; i < count; i++) {
const firstName = firstNames[i % firstNames.length];
const lastName = lastNames[Math.floor(i / firstNames.length) % lastNames.length];
const name = `${firstName} ${lastName}`;
users.push({
email: `${firstName?.toLowerCase()}.${lastName?.toLowerCase()}@acme.com`,
id: i + 1,
name,
role: roles[i % roles.length] || "",
});
}
return users;
}
const virtualizedUsers = generateUsers(1000);
return (
姓名
角色
邮箱
{(user) => (
{user.name}
{user.role}
{user.email}
)}
);
}
```
### TanStack Table
HeroUI 的 Table 作为无头表格库之上的渲染层。
本示例使用 [TanStack Table](https://tanstack.com/table) 处理列定义、排序与分页,而 HeroUI 负责样式与无障碍。
```tsx
"use client";
import type {SortDescriptor} from "@heroui/react";
import type {SortingState} from "@tanstack/react-table";
import {Chip, Pagination, Table} from "@heroui/react";
import {
createColumnHelper,
createPaginatedRowModel,
createSortedRowModel,
flexRender,
rowPaginationFeature,
rowSortingFeature,
sortFn_alphanumeric,
tableFeatures,
useTable,
} from "@tanstack/react-table";
import {useMemo, useState} from "react";
// --- Data -----------------------------------------------------------------
interface User {
id: number;
name: string;
role: string;
status: "在职" | "未激活" | "休假";
email: string;
}
const statusColorMap: Record = {
休假: "warning",
在职: "success",
未激活: "danger",
};
const users: User[] = [
{email: "kate@acme.com", id: 1, name: "Kate Moore", role: "首席执行官", status: "在职"},
{email: "john@acme.com", id: 2, name: "John Smith", role: "首席技术官", status: "在职"},
{email: "sara@acme.com", id: 3, name: "Sara Johnson", role: "首席营销官", status: "休假"},
{email: "michael@acme.com", id: 4, name: "Michael Brown", role: "首席财务官", status: "在职"},
{
email: "emily@acme.com",
id: 5,
name: "Emily Davis",
role: "产品经理",
status: "未激活",
},
{email: "davis@acme.com", id: 6, name: "Davis Wilson", role: "首席设计师", status: "在职"},
{
email: "olivia@acme.com",
id: 7,
name: "Olivia Martinez",
role: "前端工程师",
status: "在职",
},
{
email: "james@acme.com",
id: 8,
name: "James Taylor",
role: "后端工程师",
status: "在职",
},
];
// --- TanStack Features & Column Definitions -------------------------------
const features = tableFeatures({
paginatedRowModel: createPaginatedRowModel(),
rowPaginationFeature,
rowSortingFeature,
sortFns: {
alphanumeric: sortFn_alphanumeric,
},
sortedRowModel: createSortedRowModel(),
});
const columnHelper = createColumnHelper();
const columns = columnHelper.columns([
columnHelper.accessor("name", {header: "姓名"}),
columnHelper.accessor("role", {header: "角色"}),
columnHelper.accessor("status", {
cell: (info) => (
{info.getValue()}
),
header: "状态",
}),
columnHelper.accessor("email", {header: "邮箱"}),
]);
// --- Sorting Bridge -------------------------------------------------------
// Convert TanStack SortingState → React Aria SortDescriptor
function toSortDescriptor(sorting: SortingState): SortDescriptor | undefined {
const first = sorting[0];
if (!first) return undefined;
return {
column: first.id,
direction: first.desc ? "descending" : "ascending",
};
}
// Convert React Aria SortDescriptor → TanStack SortingState
function toSortingState(descriptor: SortDescriptor): SortingState {
return [{desc: descriptor.direction === "descending", id: descriptor.column as string}];
}
// --- Component ------------------------------------------------------------
const PAGE_SIZE = 4;
export function TanstackTable() {
const [sorting, setSorting] = useState([]);
const table = useTable({
columns,
data: users,
features,
initialState: {pagination: {pageIndex: 0, pageSize: PAGE_SIZE}},
onSortingChange: setSorting,
state: {sorting},
});
const sortDescriptor = useMemo(() => toSortDescriptor(sorting), [sorting]);
const {pageIndex} = table.state.pagination;
const pageCount = table.getPageCount();
const pages = Array.from({length: pageCount}, (_, i) => i + 1);
const start = pageIndex * PAGE_SIZE + 1;
const end = Math.min((pageIndex + 1) * PAGE_SIZE, users.length);
return (
setSorting(toSortingState(d))}
>
{table.getHeaderGroups()[0]?.headers.map((header) => (
))}
{table.getRowModel().rows.map((row) => (
{row.getAllCells().map((cell) => (
{flexRender(cell.column.columnDef.cell, cell.getContext())}
))}
))}
{start}–{end} / 共 {users.length} 条
table.previousPage()}
>
上一页
{pages.map((p) => (
table.setPageIndex(p - 1)}
>
{p}
))}
table.nextPage()}
>
下一页
);
}
```
### 自定义单元格
```tsx
"use client";
import type {Selection, SortDescriptor} from "@heroui/react";
import {Avatar, Button, Checkbox, Chip, Table} from "@heroui/react";
import {Icon} from "@iconify/react";
import {useMemo, useState} from "react";
interface User {
id: number;
name: string;
image_url: string;
role: string;
status: "在职" | "未激活" | "休假";
email: string;
}
const statusColorMap: Record = {
休假: "warning",
在职: "success",
未激活: "danger",
};
const users: User[] = [
{
email: "kate@acme.com",
id: 4586932,
image_url: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/red.jpg",
name: "Kate Moore",
role: "首席执行官",
status: "在职",
},
{
email: "john@acme.com",
id: 5273849,
image_url: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/green.jpg",
name: "John Smith",
role: "首席技术官",
status: "在职",
},
{
email: "sara@acme.com",
id: 7492836,
image_url: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/blue.jpg",
name: "Sara Johnson",
role: "首席营销官",
status: "休假",
},
{
email: "michael@acme.com",
id: 8293746,
image_url: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/purple.jpg",
name: "Michael Brown",
role: "首席财务官",
status: "在职",
},
{
email: "emily@acme.com",
id: 1234567,
image_url: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/orange.jpg",
name: "Emily Davis",
role: "产品经理",
status: "未激活",
},
];
export function CustomCells() {
const [selectedKeys, setSelectedKeys] = useState(new Set());
const [sortDescriptor, setSortDescriptor] = useState({
column: "name",
direction: "ascending",
});
const sortedUsers = useMemo(() => {
return [...users].sort((a, b) => {
const col = sortDescriptor.column as keyof User;
const first = String(a[col]);
const second = String(b[col]);
let cmp = first.localeCompare(second);
if (sortDescriptor.direction === "descending") {
cmp *= -1;
}
return cmp;
});
}, [sortDescriptor]);
return (
{({sortDirection}) => (
员工 ID
)}
{({sortDirection}) => (
成员
)}
{({sortDirection}) => (
角色
)}
{({sortDirection}) => (
状态
)}
操作
{sortedUsers.map((user) => (
#{user.id.toString()}{" "}
{user.name
.split(" ")
.map((n) => n[0])
.join("")}
{user.name}
{user.email}
{user.role}
{user.status}
))}
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Table} from "@heroui/react";
const headerCell = "text-xs font-semibold uppercase tracking-wide text-muted";
const rowClass =
"border-t border-border/60 transition-colors hover:bg-default even:bg-surface-secondary";
export function CustomStyles() {
return (
姓名
角色
状态
Kate Moore
CEO
在职
John Smith
CTO
在职
Sara Johnson
CMO
休假中
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.table-root {
@apply relative grid w-full overflow-clip;
}
.table__header {
@apply bg-gray-100;
}
.table__column {
@apply px-4 py-2.5 text-left text-xs font-medium text-gray-600;
}
.table__row {
@apply bg-white border-b border-gray-200;
}
.table__cell {
@apply px-4 py-3 text-sm;
}
.table__footer {
@apply flex items-center px-4 py-2.5;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Table 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/table.css)):
#### 基础类 \[!toc]
* `.table-root` - 根容器(命名为 `table-root` 而非 `table`,因为 `table` 是 Tailwind CSS 内置的 `display: table` 工具类)
* `.table__scroll-container` - 横向滚动包裹层与自定义滚动条
* `.table__content` - `` 元素
* `.table__header` - 表头行(``)
* `.table__column` - 列表头单元格(``)
* `.table__body` - 表体(` `)
* `.table__row` - 行(``)
* `.table__cell` - 数据单元格(``)
* `.table__footer` - 表底容器(位于 table 外部)
#### 进阶类 \[!toc]
* `.table__column-resizer` - 列宽拖拽手柄
* `.table__resizable-container` - 启用列宽调整的包裹层
* `.table__load-more` - 无限滚动的哨兵行
* `.table__load-more-content` - 加载指示器的样式容器
* `.table__sortable-column-header` - 可排序列标签与指示器的包裹层
* `.table__sortable-column-indicator` - 排序方向 chevron(通过 `[data-direction="descending"]` 翻转)
#### 变体类 \[!toc]
* `.table-root--primary` - 灰色背景容器与卡片式表体(默认)
* `.table-root--secondary` - 无背景,独立圆角表头
### 交互状态
Table 同时支持 CSS 伪类与 data 属性,以提供更灵活的状态控制:
* **悬停**:`:hover` 或 `[data-hovered="true"]`(行背景变化)
* **已选中**:`[data-selected="true"]`(行高亮)
* **聚焦**:`:focus-visible` 或 `[data-focus-visible="true"]`(行、列与单元格的内嵌焦点环)
* **禁用**:`:disabled` 或 `[aria-disabled="true"]`(降低透明度)
* **可排序**:`[data-allows-sorting="true"]`(列上的交互指针样式)
* **拖动中**:`[data-dragging="true"]`(降低透明度)
* **放置目标**:`[data-drop-target="true"]`(强调色背景)
## API 参考
### Table
| Prop | 类型 | 默认值 | 描述 |
| ----------- | -------------------------- | ----------- | -------------------------------------- |
| `variant` | `"primary" \| "secondary"` | `"primary"` | 视觉变体。Primary 为灰色背景容器;Secondary 为扁平透明行。 |
| `className` | `string` | - | 根容器的额外 CSS 类。 |
| `children` | `React.ReactNode` | - | 表格内容(ScrollContainer、Footer 等)。 |
### Table.ScrollContainer
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --- | ------------------- |
| `className` | `string` | - | 额外的 CSS 类。 |
| `children` | `React.ReactNode` | - | `Table.Content` 元素。 |
### Table.Content
继承自 [React Aria Table](https://react-spectrum.adobe.com/react-aria/Table.html)。
| Prop | 类型 | 默认值 | 描述 |
| ------------------- | -------------------------------------- | -------- | ------------- |
| `aria-label` | `string` | - | 表格的无障碍标签。 |
| `selectionMode` | `"none" \| "single" \| "multiple"` | `"none"` | 选择行为。 |
| `selectedKeys` | `Selection` | - | 受控的已选中 key。 |
| `onSelectionChange` | `(keys: Selection) => void` | - | 选择变化时的事件处理函数。 |
| `sortDescriptor` | `SortDescriptor` | - | 当前排序状态。 |
| `onSortChange` | `(descriptor: SortDescriptor) => void` | - | 排序变化时的事件处理函数。 |
| `className` | `string` | - | 额外的 CSS 类。 |
### Table.Header
继承自 [React Aria TableHeader](https://react-spectrum.adobe.com/react-aria/Table.html#tableheader)。
| Prop | 类型 | 默认值 | 描述 |
| ---------- | --------------------------------------------------- | --- | -------------- |
| `columns` | `T[]` | - | 渲染函数模式下的动态列数据。 |
| `children` | `React.ReactNode \| (column: T) => React.ReactNode` | - | 静态列或渲染函数。 |
### Table.Column
继承自 [React Aria Column](https://react-spectrum.adobe.com/react-aria/Table.html#column)。
| Prop | 类型 | 默认值 | 描述 |
| --------------- | ------------------------------------------------------------------- | ------- | --------------- |
| `id` | `string` | - | 列标识符。 |
| `allowsSorting` | `boolean` | `false` | 列是否可排序。 |
| `isRowHeader` | `boolean` | `false` | 该列是否作为行表头。 |
| `defaultWidth` | `string \| number` | - | 可调整列的默认宽度。 |
| `minWidth` | `number` | - | 可调整列的最小宽度。 |
| `children` | `React.ReactNode \| (values: ColumnRenderProps) => React.ReactNode` | - | 列内容或带排序方向的渲染函数。 |
### Table.Body
继承自 [React Aria TableBody](https://react-spectrum.adobe.com/react-aria/Table.html#tablebody)。
| Prop | 类型 | 默认值 | 描述 |
| ------------------ | ------------------------------------------------- | --- | -------------- |
| `items` | `T[]` | - | 渲染函数模式下的动态行数据。 |
| `renderEmptyState` | `() => React.ReactNode` | - | 表格为空时展示的内容。 |
| `children` | `React.ReactNode \| (item: T) => React.ReactNode` | - | 静态行或渲染函数。 |
### Table.Row
继承自 [React Aria Row](https://react-spectrum.adobe.com/react-aria/Table.html#row)。
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------------ | --- | ---------- |
| `id` | `string \| number` | - | 行标识符。 |
| `className` | `string` | - | 额外的 CSS 类。 |
| `children` | `React.ReactNode` | - | 行单元格。 |
### Table.Cell
继承自 [React Aria Cell](https://react-spectrum.adobe.com/react-aria/Table.html#cell)。
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --- | ---------- |
| `className` | `string` | - | 额外的 CSS 类。 |
| `children` | `React.ReactNode` | - | 单元格内容。 |
### Table.SortableColumnHeader
渲染可排序列的标签与升序 / 降序指示器。请在 `Table.Column` 的渲染函数回调中使用,并将 `sortDirection` 透传进来。
| Prop | 类型 | 默认值 | 描述 |
| --------------- | ----------------------------- | ------ | ---------------------------------------------------- |
| `sortDirection` | `"ascending" \| "descending"` | - | 当前排序方向。请从 `Table.Column` 的渲染函数中透传。 |
| `showIndicator` | `boolean` | `true` | 当存在排序方向时是否渲染指示器图标。 |
| `indicator` | `React.ReactNode` | - | 自定义指示器元素。会覆盖默认的 chevron,并会被自动注入 `data-direction` 属性。 |
| `className` | `string` | - | 包裹元素的额外 CSS 类。 |
| `children` | `React.ReactNode` | - | 列标签内容。 |
### Table.Footer
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --- | ----------- |
| `className` | `string` | - | 额外的 CSS 类。 |
| `children` | `React.ReactNode` | - | 表底内容(例如分页)。 |
### Table.ColumnResizer
继承自 [React Aria ColumnResizer](https://react-spectrum.adobe.com/react-aria/Table.html#columnresizer)。
| Prop | 类型 | 默认值 | 描述 |
| ----------- | -------- | --- | ---------- |
| `className` | `string` | - | 额外的 CSS 类。 |
### Table.ResizableContainer
继承自 [React Aria ResizableTableContainer](https://react-spectrum.adobe.com/react-aria/Table.html#resizabletablecontainer)。
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --- | ------------------- |
| `className` | `string` | - | 额外的 CSS 类。 |
| `children` | `React.ReactNode` | - | `Table.Content` 元素。 |
### Table.LoadMore
继承自 [React Aria TableLoadMoreItem](https://react-spectrum.adobe.com/react-aria/Table.html)。
| Prop | 类型 | 默认值 | 描述 |
| ------------ | ----------------- | ------- | -------------- |
| `isLoading` | `boolean` | `false` | 数据是否正在加载。 |
| `onLoadMore` | `() => void` | - | 哨兵行可见时的事件处理函数。 |
| `children` | `React.ReactNode` | - | 加载指示器内容。 |
### Table.LoadMoreContent
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --- | -------------------- |
| `className` | `string` | - | 额外的 CSS 类。 |
| `children` | `React.ReactNode` | - | 加载指示器内容(例如 Spinner)。 |
### Table.Collection
由 React Aria `Collection` 重新导出。用于在行内与静态单元格并存时渲染动态单元格(例如复选框)。
| Prop | 类型 | 默认值 | 描述 |
| ---------- | ------------------------------ | --- | ---------- |
| `items` | `T[]` | - | 集合条目。 |
| `children` | `(item: T) => React.ReactNode` | - | 每个条目的渲染函数。 |
### TableLayout
| Name | 类型 | 默认值 | 描述 |
| ------------------------ | --------------------- | --- | --------------------------------------------- |
| `rowHeight` | `number \| undefined` | 48 | 行的固定高度(px)。 |
| `estimatedRowHeight` | `number \| undefined` | — | 行高可变时的估算高度。 |
| `headingHeight` | `number \| undefined` | 48 | 分区表头的固定高度(px)。 |
| `estimatedHeadingHeight` | `number \| undefined` | — | 表头高度可变时的估算高度。 |
| `loaderHeight` | `number \| undefined` | 48 | 加载器元素的固定高度(px)。该加载器用于在根级或嵌套行/分区中渲染「加载更多」等加载行。 |
| `dropIndicatorThickness` | `number \| undefined` | 2 | 放置指示器的线条粗细。 |
| `gap` | `number \| undefined` | 0 | 条目之间的间距。 |
| `padding` | `number \| undefined` | 0 | 列表的内边距。 |
## 相关组件
## Related Components
* **Pagination**: Page navigation with composable page links and controls
* **Checkbox**: Binary choice input control
* **Chip**: Compact elements for tags and filters
# Alert 警告
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/alert
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(feedback)/alert.mdx
> 向用户展示重要消息与通知,并提供状态指示
## 用法
```tsx
import { Alert } from '@heroui/react';
```
```tsx
import {Alert, Button, CloseButton, Spinner} from "@heroui/react";
import React from "react";
export function Basic() {
return (
{/* 默认 — 一般信息 */}
新功能已上线
查看我们的最新更新,包括深色模式支持与改进的无障碍体验。
{/* 强调 — 重要信息含操作 */}
有可用更新
应用有新版本可用。请刷新页面以获取最新功能与问题修复。
刷新
刷新
{/* 危险 — 错误与排查步骤 */}
无法连接到服务器
当前遇到连接问题,请尝试以下操作:
重试
重试
{/* 无描述 */}
个人资料已更新
{/* 自定义指示器 — 加载中 */}
正在处理你的请求
正在同步你的数据,请稍候,这可能需要一点时间。
{/* 无关闭按钮 */}
计划维护
我们将于 UTC 时间 3 月 15 日(周日)凌晨 2:00 至上午 6:00
进行计划维护,期间服务将暂时不可用。
);
}
```
## 组件结构
```tsx
import { Alert } from '@heroui/react';
export default () => (
)
```
## 自定义样式
### Tailwind CSS
```tsx
import {Alert, Button, CloseButton} from "@heroui/react";
export function CustomStyles() {
return (
支付方式即将过期
您的 Visa 卡(尾号 4242)将于 3 月 28 日过期。请更新账单信息,以免影响 Pro 订阅。
更新账单
更新账单
);
}
```
### 全局 CSS
要自定义 Alert 的组件类,可使用 `@layer components` 指令。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.alert {
@apply rounded-2xl shadow-lg;
}
.alert__title {
@apply font-bold text-lg;
}
.alert--danger {
@apply border-l-4 border-red-600;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Alert 使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/alert.css)):
#### 基础类 \[!toc]
* `.alert` - Alert 根容器
* `.alert__indicator` - 图标/指示器容器
* `.alert__content` - 包裹标题与说明的内容容器
* `.alert__title` - Alert 标题文本
* `.alert__description` - Alert 说明文本
#### 状态变体类 \[!toc]
* `.alert--default` - 默认灰色状态
* `.alert--accent` - 强调蓝色状态
* `.alert--success` - 成功绿色状态
* `.alert--warning` - 警告黄/橙色状态
* `.alert--danger` - 危险红色状态
### 交互状态
Alert 主要用于信息展示,基础组件本身通常没有交互状态;但它可以包含按钮或关闭按钮等交互元素。
## API 参考
### Alert
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------------------------------------------------------- | ----------- | ----------- |
| `status` | `"default" \| "accent" \| "success" \| "warning" \| "danger"` | `"default"` | Alert 的视觉状态 |
| `className` | `string` | - | 附加的 CSS 类 |
| `children` | `ReactNode` | - | Alert 内容 |
### Alert.Indicator
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | ----------------- |
| `className` | `string` | - | 附加的 CSS 类 |
| `children` | `ReactNode` | - | 自定义指示图标(默认显示状态图标) |
### Alert.Content
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | --------------------------- |
| `className` | `string` | - | 附加的 CSS 类 |
| `children` | `ReactNode` | - | 内容(通常为 Title 与 Description) |
### Alert.Title
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | ---------- |
| `className` | `string` | - | 附加的 CSS 类 |
| `children` | `ReactNode` | - | Alert 标题文本 |
### Alert.Description
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | ---------- |
| `className` | `string` | - | 附加的 CSS 类 |
| `children` | `ReactNode` | - | Alert 说明文本 |
## 相关组件
## Related Components
* **CloseButton**: Button for dismissing overlays
* **Button**: Allows a user to perform an action
* **Spinner**: Loading indicator
# Meter 计量条
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/meter
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(feedback)/meter.mdx
> Meter 表示已知范围内的数量,或一个比例值。
## 用法
```tsx
import { Meter, Label } from '@heroui/react';
```
```tsx
import {Label, Meter} from "@heroui/react";
export function Basic() {
return (
存储空间
);
}
```
## 组件结构
```tsx
import { Meter, Label } from '@heroui/react';
export default () => (
Storage
);
```
## 示例
### 尺寸
```tsx
import {Label, Meter} from "@heroui/react";
const SIZE_LABELS = {
lg: "大",
md: "中",
sm: "小",
} as const;
export function Sizes() {
return (
{SIZE_LABELS.sm}
{SIZE_LABELS.md}
{SIZE_LABELS.lg}
);
}
```
### 颜色
```tsx
import {Label, Meter} from "@heroui/react";
const colors = ["default", "accent", "success", "warning", "danger"] as const;
const COLOR_LABELS: Record<(typeof colors)[number], string> = {
accent: "强调",
danger: "危险",
default: "默认",
success: "成功",
warning: "警告",
};
export function Colors() {
return (
{colors.map((color) => (
{COLOR_LABELS[color]}
))}
);
}
```
### 无可见标签
无需可见标签时,使用 `aria-label` 提供无障碍标签。
```tsx
import {Meter} from "@heroui/react";
export function WithoutLabel() {
return (
);
}
```
### 自定义取值范围与格式
使用 `minValue`、`maxValue` 与 `formatOptions` 自定义取值范围与显示格式。
```tsx
import {Label, Meter} from "@heroui/react";
export function CustomValue() {
return (
收入
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Label, Meter} from "@heroui/react";
export function CustomStyles() {
return (
已用存储空间
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.meter {
@apply w-full gap-2;
}
.meter__track {
@apply h-3 rounded-full;
}
.meter__fill {
@apply rounded-full;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Meter 使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/meter.css)):
#### 基础与元素类 \[!toc]
* `.meter` — 基础容器(grid 布局)
* `.meter__output` — 数值文本展示
* `.meter__track` — 轨道背景
* `.meter__fill` — 轨道已填充部分
#### 尺寸类 \[!toc]
* `.meter--sm` — 小尺寸变体(更细的轨道)
* `.meter--md` — 中等尺寸变体(默认)
* `.meter--lg` — 大尺寸变体(更粗的轨道)
#### 颜色类 \[!toc]
* `.meter--default` — 默认颜色变体
* `.meter--accent` — 强调色变体
* `.meter--success` — 成功色变体
* `.meter--warning` — 警告色变体
* `.meter--danger` — 危险色变体
## API 参考
### Meter
继承自 [React Aria Meter](https://react-spectrum.adobe.com/react-aria/Meter.html)。
| Prop | 类型 | 默认值 | 描述 |
| --------------- | ------------------------------------------------------------- | -------------------- | ---------- |
| `value` | `number` | `0` | 当前值 |
| `minValue` | `number` | `0` | 最小值 |
| `maxValue` | `number` | `100` | 最大值 |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Meter 轨道尺寸 |
| `color` | `"default" \| "accent" \| "success" \| "warning" \| "danger"` | `"accent"` | 填充条颜色 |
| `formatOptions` | `Intl.NumberFormatOptions` | `{style: 'percent'}` | 数值展示的格式化选项 |
| `valueLabel` | `ReactNode` | - | 自定义数值标签内容 |
| `children` | `ReactNode \| (values: MeterRenderProps) => ReactNode` | - | 内容或渲染 prop |
### MeterRenderProps
使用渲染 prop 模式时,会提供以下值:
| Prop | 类型 | 描述 |
| ------------ | -------- | ---------------- |
| `percentage` | `number` | Meter 百分比(0–100) |
| `valueText` | `string` | 格式化后的数值文本 |
## 相关组件
# ProgressBar 进度条
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/progress-bar
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(feedback)/progress-bar.mdx
> 进度条用于展示某项操作随时间变化的确定或不确定进度。
## 用法
```tsx
import { ProgressBar, Label } from '@heroui/react';
```
```tsx
import {Label, ProgressBar} from "@heroui/react";
export function Basic() {
return (
加载中
);
}
```
## 组件结构
```tsx
import { ProgressBar, Label } from '@heroui/react';
export default () => (
Loading
);
```
## 示例
### 尺寸
```tsx
import {Label, ProgressBar} from "@heroui/react";
const SIZE_LABELS = {
lg: "大",
md: "中",
sm: "小",
} as const;
export function Sizes() {
return (
{SIZE_LABELS.sm}
{SIZE_LABELS.md}
{SIZE_LABELS.lg}
);
}
```
### 颜色
```tsx
import {Label, ProgressBar} from "@heroui/react";
const colors = ["default", "accent", "success", "warning", "danger"] as const;
const COLOR_LABELS: Record<(typeof colors)[number], string> = {
accent: "强调",
danger: "危险",
default: "默认",
success: "成功",
warning: "警告",
};
export function Colors() {
return (
{colors.map((color) => (
{COLOR_LABELS[color]}
))}
);
}
```
### 无可见标签
无需可见标签时,使用 `aria-label` 提供无障碍标签。
```tsx
import {ProgressBar} from "@heroui/react";
export function WithoutLabel() {
return (
);
}
```
### 不确定进度
无法确定进度时使用 `isIndeterminate`。
```tsx
import {Label, ProgressBar} from "@heroui/react";
export function Indeterminate() {
return (
加载中…
);
}
```
### 自定义数值范围
使用 `minValue`、`maxValue` 与 `formatOptions` 自定义取值范围与显示格式。
```tsx
"use client";
import {Label, ListBox, NumberField, ProgressBar, Select, Separator} from "@heroui/react";
import {useState} from "react";
const formatStyleOptions: {label: string; value: string}[] = [
{label: "货币", value: "currency"},
{label: "百分比", value: "percent"},
{label: "小数", value: "decimal"},
{label: "单位", value: "unit"},
];
const formatOptionsMap: Record = {
currency: {currency: "USD", style: "currency"},
decimal: {style: "decimal"},
percent: {style: "percent"},
unit: {style: "unit", unit: "mile"},
};
export function CustomValue() {
const [value, setValue] = useState(750);
const [minValue, setMinValue] = useState(0);
const [maxValue, setMaxValue] = useState(1000);
const [format, setFormat] = useState("percent");
return (
选项
setValue(v)}
>
值
{
setMinValue(v);
if (value < v) setValue(v);
}}
>
最小值
{
setMaxValue(v);
if (value > v) setValue(v);
}}
>
最大值
setFormat(key as string)}>
格式
{formatStyleOptions.map((option) => (
{option.label}
))}
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Label, ProgressBar} from "@heroui/react";
export function CustomStyles() {
return (
正在上传 resume.pdf
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.progress-bar {
@apply w-full gap-2;
}
.progress-bar__track {
@apply h-3 rounded-full;
}
.progress-bar__fill {
@apply rounded-full;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
ProgressBar 使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/progress-bar.css)):
#### 基础与元素类 \[!toc]
* `.progress-bar` - 基础容器(网格布局)
* `.progress-bar__output` - 数值文本展示
* `.progress-bar__track` - 轨道背景
* `.progress-bar__fill` - 轨道上已填充部分
#### 尺寸类 \[!toc]
* `.progress-bar--sm` - 小尺寸变体(更细的轨道)
* `.progress-bar--md` - 中等尺寸变体(默认)
* `.progress-bar--lg` - 大尺寸变体(更粗的轨道)
#### 颜色类 \[!toc]
* `.progress-bar--default` - 默认颜色变体
* `.progress-bar--accent` - 强调色变体
* `.progress-bar--success` - 成功色变体
* `.progress-bar--warning` - 警告色变体
* `.progress-bar--danger` - 危险色变体
## API 参考
### ProgressBar
继承自 [React Aria ProgressBar](https://react-spectrum.adobe.com/react-aria/ProgressBar.html)。
| Prop | 类型 | 默认值 | 描述 |
| ----------------- | ------------------------------------------------------------- | -------------------- | ---------- |
| `value` | `number` | `0` | 当前值 |
| `minValue` | `number` | `0` | 最小值 |
| `maxValue` | `number` | `100` | 最大值 |
| `isIndeterminate` | `boolean` | `false` | 是否为不确定进度 |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | 进度轨道尺寸 |
| `color` | `"default" \| "accent" \| "success" \| "warning" \| "danger"` | `"accent"` | 填充条颜色 |
| `formatOptions` | `Intl.NumberFormatOptions` | `{style: 'percent'}` | 数值展示的数字格式 |
| `valueLabel` | `ReactNode` | - | 自定义数值标签内容 |
| `children` | `ReactNode \| (values: ProgressBarRenderProps) => ReactNode` | - | 内容或渲染 prop |
### ProgressBarRenderProps
使用渲染 prop 模式时,会提供以下值:
| Prop | 类型 | 描述 |
| ----------------- | --------- | ------------ |
| `percentage` | `number` | 进度百分比(0–100) |
| `valueText` | `string` | 格式化后的数值文本 |
| `isIndeterminate` | `boolean` | 是否为不确定进度 |
## 相关组件
# ProgressCircle 环形进度条
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/progress-circle
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(feedback)/progress-circle.mdx
> 环形进度指示器,用于展示确定或不确定的进度。
## 用法
```tsx
import { ProgressCircle } from '@heroui/react';
```
```tsx
import {ProgressCircle} from "@heroui/react";
export function Basic() {
return (
);
}
```
## 组件结构
```tsx
import { ProgressCircle } from '@heroui/react';
export default () => (
);
```
## 示例
### 尺寸
```tsx
import {ProgressCircle} from "@heroui/react";
const SIZE_LABELS = {
lg: "大",
md: "中",
sm: "小",
} as const;
export function Sizes() {
return (
);
}
```
### 颜色
```tsx
import {ProgressCircle} from "@heroui/react";
const colors = ["default", "accent", "success", "warning", "danger"] as const;
const COLOR_LABELS: Record<(typeof colors)[number], string> = {
accent: "强调",
danger: "危险",
default: "默认",
success: "成功",
warning: "警告",
};
export function Colors() {
return (
{colors.map((color) => (
))}
);
}
```
### 不确定进度
无法确定进度时使用 `isIndeterminate`。
```tsx
import {ProgressCircle} from "@heroui/react";
export function Indeterminate() {
return (
);
}
```
### 带标签
```tsx
import {Label, ProgressCircle} from "@heroui/react";
export function WithLabel() {
return (
);
}
```
### 自定义 SVG 属性
各子部分均为可组合组件,可直接覆盖 `strokeWidth`、`r`、`cx`、`cy`、`viewBox` 等 SVG 属性。
```tsx
import {ProgressCircle} from "@heroui/react";
export function CustomSvg() {
return (
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {ProgressCircle} from "@heroui/react";
export function CustomStyles() {
return (
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.progress-circle {
@apply inline-flex;
}
.progress-circle__track {
@apply size-12;
}
.progress-circle__fill-circle {
stroke: purple;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
ProgressCircle 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/progress-circle.css)):
#### 基础与元素类 \[!toc]
* `.progress-circle` - 基础容器
* `.progress-circle__track` - SVG 元素
* `.progress-circle__track-circle` - 背景圆环
* `.progress-circle__fill-circle` - 进度弧
#### 尺寸类 \[!toc]
* `.progress-circle--sm` - 小尺寸
* `.progress-circle--md` - 中等尺寸(默认)
* `.progress-circle--lg` - 大尺寸
#### 颜色类 \[!toc]
* `.progress-circle--default` - 默认颜色
* `.progress-circle--accent` - 强调色
* `.progress-circle--success` - 成功色
* `.progress-circle--warning` - 警告色
* `.progress-circle--danger` - 危险色
## API 参考
### ProgressCircle
继承自 [React Aria ProgressBar](https://react-spectrum.adobe.com/react-aria/ProgressBar.html)。
| Prop | 类型 | 默认值 | 描述 |
| ----------------- | ------------------------------------------------------------- | -------------------- | ---------- |
| `value` | `number` | `0` | 当前值 |
| `minValue` | `number` | `0` | 最小值 |
| `maxValue` | `number` | `100` | 最大值 |
| `isIndeterminate` | `boolean` | `false` | 是否为不确定进度 |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | 圆环尺寸 |
| `color` | `"default" \| "accent" \| "success" \| "warning" \| "danger"` | `"accent"` | 进度弧颜色 |
| `formatOptions` | `Intl.NumberFormatOptions` | `{style: 'percent'}` | 数值展示格式 |
| `children` | `ReactNode \| (values: ProgressBarRenderProps) => ReactNode` | - | 内容或渲染 prop |
### ProgressBarRenderProps
使用渲染 prop 模式时,会提供以下值:
| Prop | 类型 | 描述 |
| ----------------- | --------- | ------------ |
| `percentage` | `number` | 进度百分比(0–100) |
| `valueText` | `string` | 格式化后的数值文案 |
| `isIndeterminate` | `boolean` | 是否为不确定进度 |
## 相关组件
# Skeleton 骨架屏
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/skeleton
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(feedback)/skeleton.mdx
> Skeleton 用于展示加载状态,并预览组件的预期形状。
## 用法
```tsx
import { Skeleton } from '@heroui/react';
```
```tsx
import {Skeleton} from "@heroui/react";
export function Basic() {
return (
);
}
```
## 示例
### 文本内容
```tsx
import {Skeleton} from "@heroui/react";
export function TextContent() {
return (
);
}
```
### 用户资料
```tsx
import {Skeleton} from "@heroui/react";
export function UserProfile() {
return (
);
}
```
### 列表项
```tsx
import {Skeleton} from "@heroui/react";
export function List() {
return (
{Array.from({length: 3}).map((_, index) => (
))}
);
}
```
### 网格
```tsx
import {Skeleton} from "@heroui/react";
export function Grid() {
return (
);
}
```
### 单次闪烁
同步的 shimmer 效果会一次性扫过所有骨架元素。在父容器上应用 `skeleton--shimmer` 类,并将子骨架的 `animationType` 设为 `"none"`。
```tsx
import {Skeleton} from "@heroui/react";
export function SingleShimmer() {
return (
);
}
```
### 动画类型
```tsx
import {Skeleton} from "@heroui/react";
export function AnimationTypes() {
return (
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Skeleton} from "@heroui/react";
const bone = "animate-shine rounded-lg bg-neutral-200/90 dark:bg-neutral-800/90";
export function CustomStyles() {
return (
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
/* Base skeleton styles */
.skeleton {
@apply bg-surface-secondary/50; /* Change base background */
}
/* Shimmer animation gradient */
.skeleton--shimmer:before {
@apply viasurface; /* Change shimmer gradient color */
}
/* Pulse animation */
.skeleton--pulse {
@apply animate-pulse opacity-75; /* Customize pulse animation */
}
/* No animation variant */
.skeleton--none {
@apply opacity-50; /* Style for static skeleton */
}
}
```
### 全局动画配置
可在全局 CSS 中通过 `--skeleton-animation` 变量为所有 Skeleton 组件设置默认动画类型:
```css
/* 全局 CSS 文件 */
:root {
/* 可选值:shimmer、pulse、none */
--skeleton-animation: pulse;
}
/* 也可为浅色/深色主题设置不同值 */
.light, [data-theme="light"] {
--skeleton-animation: shimmer;
}
.dark, [data-theme="dark"] {
--skeleton-animation: pulse;
}
```
在单个组件上指定 `animationType` 属性会覆盖此全局设置。
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### 全局动画配置
你可以通过在应用中定义 `--skeleton-animation` CSS 变量,为所有 Skeleton 设置默认动画类型:
```css
/* In your global CSS file */
:root {
/* Possible values: shimmer, pulse, none */
--skeleton-animation: pulse;
}
/* You can also set different values for light/dark themes */
.light, [data-theme="light"] {
--skeleton-animation: shimmer;
}
.dark, [data-theme="dark"] {
--skeleton-animation: pulse;
}
```
在单个组件上指定 `animationType` 时,会覆盖上述全局设置。
### CSS 类
Skeleton 使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/skeleton.css)):
#### 基础类 \[!toc]
`.skeleton` - 包含背景与圆角等基础骨架样式
#### 动画变体类 \[!toc]
* `.skeleton--shimmer` - 添加带渐变效果的闪烁动画(默认)
* `.skeleton--pulse` - 使用 Tailwind 的 `animate-pulse` 添加脉冲动画
* `.skeleton--none` - 无动画的静态骨架
### 动画
Skeleton 支持三种动画类型,视觉效果各不相同:
#### 闪烁动画 \[!toc]
闪烁效果会在骨架元素上移动渐变:
```css
.skeleton--shimmer:before {
@apply animate-skeleton via-surface-3 absolute inset-0 -translate-x-full
bg-gradient-to-r from-transparent to-transparent content-[''];
}
```
闪烁动画在主题中通过以下方式定义:
```css
@theme inline {
--animate-skeleton: skeleton 2s linear infinite;
@keyframes skeleton {
100% {
transform: translateX(200%);
}
}
}
```
#### 脉冲动画 \[!toc]
脉冲动画使用 Tailwind 内置的 `animate-pulse` 工具类:
```css
.skeleton--pulse {
@apply animate-pulse;
}
```
#### 无动画 \[!toc]
用于不需要任何动画的静态骨架:
```css
.skeleton--none {
/* No animation styles applied */
}
```
## API 参考
### Skeleton
| Prop | 类型 | 默认值 | 描述 |
| --------------- | -------------------------------- | -------------------- | ------------------------------------------------------- |
| `animationType` | `"shimmer" \| "pulse" \| "none"` | `"shimmer"` 或 CSS 变量 | Skeleton 的动画类型;也可通过 `--skeleton-animation` CSS 变量进行全局配置 |
| `className` | `string` | - | 额外的 CSS 类名 |
## 相关组件
## Related Components
* **Card**: Content container with header, body, and footer
* **Avatar**: Display user profile images
# Spinner 加载指示器
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/spinner
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(feedback)/spinner.mdx
> 用于展示等待或处理中状态的加载指示组件。
## 用法
```tsx
import { Spinner } from '@heroui/react';
```
```tsx
import {Spinner} from "@heroui/react";
export function SpinnerBasic() {
return (
);
}
```
## 示例
### 颜色
```tsx
import {Spinner} from "@heroui/react";
const COLOR_LABELS = {
accent: "强调",
current: "当前",
danger: "危险",
success: "成功",
warning: "警告",
} as const;
const colors = ["current", "accent", "success", "warning", "danger"] as const;
export function SpinnerColors() {
return (
{colors.map((color) => (
{COLOR_LABELS[color]}
))}
);
}
```
### 尺寸
```tsx
import {Spinner} from "@heroui/react";
const SIZE_LABELS = {
lg: "大",
md: "中",
sm: "小",
xl: "特大",
} as const;
const sizes = ["sm", "md", "lg", "xl"] as const;
export function SpinnerSizes() {
return (
{sizes.map((size) => (
{SIZE_LABELS[size]}
))}
);
}
```
### 速度
为单个 Spinner 添加动画工具类即可调整其旋转速度。请同时加上 `motion-reduce:animate-none`,以便在用户开启“减少动态效果”时保持静止。
```tsx
import {Spinner} from "@heroui/react";
export function SpinnerSpeed() {
return (
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Spinner} from "@heroui/react";
export function CustomStyles() {
return (
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.spinner {
@apply animate-spin;
}
.spinner--accent {
color: var(--accent);
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Spinner 使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/spinner.css)):
#### 基础类与尺寸类 \[!toc]
* `.spinner` - 基础样式与默认尺寸
* `.spinner--sm` - 小尺寸变体
* `.spinner--md` - 中等尺寸变体(默认)
* `.spinner--lg` - 大尺寸变体
* `.spinner--xl` - 特大尺寸变体
#### 颜色类 \[!toc]
* `.spinner--current` - 继承当前文本颜色
* `.spinner--accent` - 强调色变体
* `.spinner--danger` - 危险色变体
* `.spinner--success` - 成功色变体
* `.spinner--warning` - 警告色变体
## API 参考
### Spinner
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------------------------------------------------------- | ---------- | ------------- |
| `size` | `"sm" \| "md" \| "lg" \| "xl"` | `"md"` | Spinner 的尺寸 |
| `color` | `"current" \| "accent" \| "success" \| "warning" \| "danger"` | `"accent"` | Spinner 的颜色变体 |
| `className` | `string` | - | 额外的 CSS 类名 |
## 相关组件
# Calendar 日历
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/calendar
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(date-and-time)/calendar.mdx
> 基于 React Aria Calendar 的可组合日期选择器,支持月网格、导航与年份选择
## 用法
```tsx
import { Calendar } from '@heroui/react';
```
```tsx
"use client";
import {Calendar} from "@heroui/react";
export function Basic() {
return (
{(day) => {day} }
{(date) => }
);
}
```
## 组件结构
```tsx
import {Calendar} from '@heroui/react';
export default () => (
{(day) => {day} }
{(date) => }
)
```
## 示例
### 禁用
```tsx
"use client";
import {Calendar, Description} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
export function Disabled() {
return (
{(day) => {day} }
{(date) => }
日历已禁用
);
}
```
### 只读
```tsx
"use client";
import {Calendar, Description} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
export function ReadOnly() {
return (
{(day) => {day} }
{(date) => }
日历为只读
);
}
```
### 默认值
```tsx
"use client";
import {Calendar} from "@heroui/react";
import {parseDate} from "@internationalized/date";
export function DefaultValue() {
return (
{(day) => {day} }
{(date) => }
);
}
```
### 年份选择
`Calendar.YearPickerTrigger`、`Calendar.YearPickerGrid` 及其 body/cell 子组件提供集成的年份导航模式。
```tsx
"use client";
import {Calendar} from "@heroui/react";
export function YearPicker() {
return (
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
### 受控组件
使用受控的 `value` 与 `focusedValue` 进行外部状态协调与自定义快捷操作。
```tsx
"use client";
import type {CalendarDate} from "@internationalized/date";
import {Button, ButtonGroup, Calendar, Description} from "@heroui/react";
import {
getLocalTimeZone,
parseDate,
startOfMonth,
startOfWeek,
today,
} from "@internationalized/date";
import {useState} from "react";
import {useLocale} from "react-aria-components";
export function Controlled() {
const [value, setValue] = useState(null);
const [focusedDate, setFocusedDate] = useState(parseDate("2025-12-25"));
const {locale} = useLocale();
return (
{
const todayDate = today(getLocalTimeZone());
setValue(todayDate);
setFocusedDate(todayDate);
}}
>
今天
{
const nextWeekStart = startOfWeek(today(getLocalTimeZone()), locale);
setValue(nextWeekStart);
setFocusedDate(nextWeekStart);
}}
>
本周
{
const nextMonthStart = startOfMonth(today(getLocalTimeZone()));
setValue(nextMonthStart);
setFocusedDate(nextMonthStart);
}}
>
本月
{(day) => {day} }
{(date) => }
已选日期:{value ? value.toString() : "(未选)"}
{
const todayDate = today(getLocalTimeZone());
setValue(todayDate);
setFocusedDate(todayDate);
}}
>
设为今天
{
const christmasDate = parseDate("2025-12-25");
setValue(christmasDate);
setFocusedDate(christmasDate);
}}
>
设为圣诞节
setValue(null)}>
清空
);
}
```
### 日期范围限制
```tsx
"use client";
import {Calendar, Description} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
export function MinMaxDates() {
const now = today(getLocalTimeZone());
const minDate = now;
const maxDate = now.add({months: 3});
return (
{(day) => {day} }
{(date) => }
请在今天与 {maxDate.toString()} 之间选择日期。
);
}
```
### 不可用日期
使用 `isDateUnavailable` 阻止周末、节假日或已预订时段等日期。
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {Calendar, Description} from "@heroui/react";
import {isWeekend} from "@internationalized/date";
import {useLocale} from "react-aria-components";
export function UnavailableDates() {
const {locale} = useLocale();
const isDateUnavailable = (date: DateValue) => isWeekend(date, locale);
return (
{(day) => {day} }
{(date) => }
周末不可选
);
}
```
### 月份周数
将 `weeksInMonth` 设为固定值(如 `6`)可在月份切换时保持网格高度稳定。在非公历 locale 中请谨慎使用,类似 `firstDayOfWeek`。
```tsx
"use client";
import {Calendar, Description} from "@heroui/react";
export function WeeksInMonth() {
return (
{(day) => {day} }
{(date) => }
每月固定显示 6 周,切换月份时避免布局跳动
);
}
```
### 周视图
设置 `visibleDuration={{ weeks: n }}` 可一次显示一周或多周。导航按可见周范围前进。显示多周时使用 `pageBehavior="single"` 可每次移动一周。
```tsx
"use client";
import {Calendar, Label, ListBox, Select} from "@heroui/react";
import {useState} from "react";
const weekOptions = [
{id: "1", name: "1 周"},
{id: "2", name: "2 周"},
{id: "3", name: "3 周"},
{id: "4", name: "4 周"},
{id: "5", name: "5 周"},
{id: "6", name: "6 周"},
{id: "8", name: "8 周"},
] as const;
export function WeekView() {
const [weeks, setWeeks] = useState(1);
return (
value && setWeeks(Number(value))}
>
可见周数
{weekOptions.map((option) => (
{option.name}
))}
{(day) => {day} }
{(date) => }
);
}
```
### 日视图
设置 `visibleDuration={{ days: n }}` 可显示连续日期的滚动窗口。导航按可见日范围前进。显示多天时使用 `pageBehavior="single"` 可每次移动一天。
```tsx
"use client";
import {Calendar, Label, ListBox, Select} from "@heroui/react";
import {useState} from "react";
const dayOptions = [
{id: "1", name: "1 天"},
{id: "5", name: "5 天"},
{id: "7", name: "7 天"},
{id: "8", name: "8 天"},
{id: "10", name: "10 天"},
{id: "14", name: "14 天"},
{id: "21", name: "21 天"},
] as const;
export function DayView() {
const [days, setDays] = useState(5);
return (
value && setDays(Number(value))}
>
可见天数
{dayOptions.map((option) => (
{option.name}
))}
{(day) => {day} }
{(date) => }
);
}
```
### 多选
设置 `selectionMode="multiple"` 允许选择多个日期。`value`、`defaultValue` 与 `onChange` 使用日期数组。
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {Calendar, Description} from "@heroui/react";
import {useState} from "react";
export function MultipleSelection() {
const [value, setValue] = useState([]);
return (
{(day) => {day} }
{(date) => }
{value?.length ? `已选择 ${value.length} 个日期` : "可选择多个日期"}
);
}
```
### 聚焦值
使用 `focusedValue` 与 `onFocusChange` 以编程方式控制聚焦日期。
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {Button, Calendar, Description} from "@heroui/react";
import {parseDate} from "@internationalized/date";
import {useState} from "react";
export function FocusedValue() {
const [focusedDate, setFocusedDate] = useState(parseDate("2025-06-15"));
return (
{(day) => {day} }
{(date) => }
聚焦:{focusedDate.toString()}
setFocusedDate(parseDate("2025-01-01"))}
>
跳转到一月
setFocusedDate(parseDate("2025-06-15"))}
>
跳转到六月
setFocusedDate(parseDate("2025-12-25"))}
>
跳转到圣诞节
);
}
```
### 单元格标记
可自定义 `Calendar.Cell` 子节点,并使用 `Calendar.CellIndicator` 显示事件等元数据。
```tsx
"use client";
import {Calendar} from "@heroui/react";
import {getLocalTimeZone, isToday} from "@internationalized/date";
const datesWithEvents = [3, 7, 12, 15, 21, 28];
export function WithIndicators() {
return (
{(day) => {day} }
{(date) => (
{({formattedDate}) => (
<>
{formattedDate}
{(isToday(date, getLocalTimeZone()) || datesWithEvents.includes(date.day)) && (
)}
>
)}
)}
);
}
```
### 自定义导航图标
向 `Calendar.NavButton` 传入子节点以替换默认 chevron 图标。
```tsx
"use client";
import {Calendar} from "@heroui/react";
export function CustomIcons() {
return (
{(day) => {day} }
{(date) => }
);
}
```
### 多月份展示
使用 `visibleDuration` 与 `offset` 渲染多个月份网格,适用于预订与规划场景。
```tsx
"use client";
import {Calendar} from "@heroui/react";
export function MultipleMonths() {
return (
{(day) => {day} }
{(date) => }
{(day) => {day} }
{(date) => }
);
}
```
### 典型场景
```tsx
"use client";
import type {CalendarDate, DateValue} from "@internationalized/date";
import {Button, Calendar} from "@heroui/react";
import {getLocalTimeZone, isWeekend, today} from "@internationalized/date";
import {useState} from "react";
import {useLocale} from "react-aria-components";
export function BookingCalendar() {
const [selectedDate, setSelectedDate] = useState(null);
const {locale} = useLocale();
const bookedDates = [5, 6, 12, 13, 14, 20];
const isDateUnavailable = (date: DateValue) => {
return isWeekend(date, locale) || bookedDates.includes(date.day);
};
return (
{(day) => {day} }
{(date) => (
{({formattedDate, isUnavailable}) => (
<>
{formattedDate}
{!isUnavailable &&
!isWeekend(date, locale) &&
bookedDates.includes(date.day) && }
>
)}
)}
已有预订
周末/不可用
{selectedDate ? (
预订 {selectedDate.toString()}
) : null}
);
}
```
### 国际化日历
默认情况下,Calendar 使用用户 locale 的历法系统显示日期。可用 `I18nProvider` 包裹 Calendar 并设置 [Unicode 历法 locale 扩展](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string) 来覆盖。
以下示例展示印度历法系统:
```tsx
"use client";
import {Calendar} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
import {I18nProvider} from "react-aria-components";
export function InternationalCalendar() {
return (
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
**Note:** `onChange` 事件始终返回与 `value` 或 `defaultValue` 相同历法系统的日期(未提供 value 时为公历),无论显示 locale 如何。这确保应用逻辑在单一历法系统下一致运行,同时仍以用户偏好的格式显示日期。
## 自定义样式
### Tailwind CSS
```tsx
"use client";
import {Calendar} from "@heroui/react";
export function CustomStyles() {
return (
{(day) => (
{day}
)}
{(date) => (
)}
);
}
```
### 全局 CSS
```css
@layer components {
.calendar {
@apply w-72 rounded-2xl border border-border bg-surface p-3 shadow-sm;
}
.calendar__heading {
@apply text-sm font-semibold text-default-700;
}
.calendar__cell[data-selected="true"] {
@apply bg-accent text-accent-foreground;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Calendar 在 `packages/styles/components/calendar.css` 与 `packages/styles/components/calendar-year-picker.css` 中使用以下类:
* `.calendar` - 根容器
* `.calendar__header` - 包含导航按钮与标题的头部行
* `.calendar__heading` - 当前月份标签
* `.calendar__nav-button` - 上/下月导航控件
* `.calendar__grid` - 主日期网格
* `.calendar__grid-header` - 星期标题行包装器
* `.calendar__grid-body` - 日期行包装器
* `.calendar__header-cell` - 星期标题单元格
* `.calendar__cell` - 可交互的日期单元格
* `.calendar__cell-indicator` - 日期单元格内的点指示器
* `.calendar-year-picker__trigger` - 年份选择器切换按钮
* `.calendar-year-picker__trigger-heading` - 年份选择器触发器内的标题文本
* `.calendar-year-picker__trigger-indicator` - 年份选择器触发器内的指示图标
* `.calendar-year-picker__year-grid` - 可选年份的覆盖网格
* `.calendar-year-picker__year-cell` - 单个年份选项
### 交互状态
Calendar 同时支持伪类与 React Aria data 属性:
* **Selected**:`[data-selected="true"]`
* **Today**:`[data-today="true"]`
* **Unavailable**:`[data-unavailable="true"]`
* **Outside month**:`[data-outside-month="true"]`
* **Hovered**:`:hover` 或 `[data-hovered="true"]`
* **Pressed**:`:active` 或 `[data-pressed="true"]`
* **Focus visible**:`:focus-visible` 或 `[data-focus-visible="true"]`
* **Disabled**:`:disabled` 或 `[data-disabled="true"]`
## API 参考
### Calendar
Calendar 继承 React Aria [Calendar](https://react-spectrum.adobe.com/react-aria/Calendar.html) 的所有属性。
| Prop | 类型 | 默认值 | 描述 |
| ------------------------ | --------------------------------------------------------------------- | ------------------ | ------------------------------------------------------------------ |
| `selectionMode` | `'single' \| 'multiple'` | `'single'` | 是否可选择单个或多个日期 |
| `value` | `DateValue \| null` 或 `DateValue[] \| null` | - | 受控选中日期。`selectionMode` 为 `multiple` 时使用数组 |
| `defaultValue` | `DateValue \| null` 或 `DateValue[] \| null` | - | 初始选中日期(非受控) |
| `onChange` | `(value: DateValue \| null)` 或 `(value: DateValue[] \| null) => void` | - | 选择变化时调用 |
| `focusedValue` | `DateValue` | - | 受控聚焦日期 |
| `onFocusChange` | `(value: DateValue) => void` | - | 焦点移至其他日期时调用 |
| `minValue` | `DateValue` | 历法感知的 `1900-01-01` | 最早可选日期 |
| `maxValue` | `DateValue` | 历法感知的 `2099-12-31` | 最晚可选日期 |
| `weeksInMonth` | `number` | - | 月份中的周数,覆盖 locale 默认值 |
| `isDateUnavailable` | `(date: DateValue) => boolean` | - | 标记日期为不可用 |
| `firstDayOfWeek` | `'sun' \| 'mon' \| 'tue' \| 'wed' \| 'thu' \| 'fri' \| 'sat'` | - | 覆盖 locale 默认的一周起始日 |
| `pageBehavior` | `'visible' \| 'single'` | `'visible'` | 翻页按可见时长还是单个单位前进 |
| `selectionAlignment` | `'start' \| 'center' \| 'end'` | `'center'` | 初始渲染时可见范围与选择的对齐方式 |
| `isDisabled` | `boolean` | `false` | 禁用交互与选择 |
| `isReadOnly` | `boolean` | `false` | 内容可读但不可更改选择 |
| `isInvalid` | `boolean` | `false` | 标记日历为无效以显示验证 UI |
| `visibleDuration` | `{months?: number; weeks?: number; days?: number}` | `{months: 1}` | 可见时间范围。月视图用 `{ months: n }`,周视图用 `{ weeks: n }`,日视图用 `{ days: n }` |
| `defaultYearPickerOpen` | `boolean` | `false` | 内部年份选择器初始打开状态 |
| `isYearPickerOpen` | `boolean` | - | 受控年份选择器打开状态 |
| `onYearPickerOpenChange` | `(isOpen: boolean) => void` | - | 年份选择器打开状态变化时调用 |
### Composition Parts
| Component | Description |
| ------------------------------------- | ----------------------------------------------- |
| `Calendar.Header` | 导航与标题的头部容器 |
| `Calendar.Heading` | 可见范围的格式化标题。支持 `offset`(多月布局)与 `format`(月/年/日选项) |
| `Calendar.NavButton` | 上/下月导航控件(`slot="previous"` 或 `slot="next"`) |
| `Calendar.Grid` | 单个月份的日期网格(多月布局支持 `offset`) |
| `Calendar.GridHeader` | 星期标题容器 |
| `Calendar.GridBody` | 日期单元格 body 容器 |
| `Calendar.HeaderCell` | 星期标签单元格 |
| `Calendar.Cell` | 单个日期单元格 |
| `Calendar.CellIndicator` | 自定义元数据的可选指示元素 |
| `Calendar.YearPickerTrigger` | 切换年份选择器模式的触发器 |
| `Calendar.YearPickerTriggerHeading` | 年份选择器触发器内的本地化标题内容 |
| `Calendar.YearPickerTriggerIndicator` | 年份选择器触发器内的切换图标 |
| `Calendar.YearPickerGrid` | 覆盖式年份选择网格容器 |
| `Calendar.YearPickerGridBody` | 年份网格单元格的 body 渲染器 |
| `Calendar.YearPickerCell` | 单个年份选项单元格 |
### Year Picker Parts
年份选择器子组件继承 React Aria [`useCalendarHeading`](https://react-aria.adobe.com/useCalendar#usecalendarheading) 与 [`useCalendarYearPicker`](https://react-aria.adobe.com/useCalendar#usecalendaryearpicker) 的格式化属性。
| Component | Prop | 类型 | 默认值 | 描述 |
| ----------------------------------- | -------------- | ---------------------- | ------------------- | ------------------------------------------------- |
| `Calendar.YearPickerTriggerHeading` | `format` | `DateFormatterOptions` | - | 自定义月/年标签(如 `{month: 'short'}`) |
| `Calendar.YearPickerTriggerHeading` | `offset` | `{months?: number}` | - | 相对聚焦日期偏移标题(多月布局) |
| `Calendar.YearPickerGrid` | `format` | `DateFormatterOptions` | `{year: 'numeric'}` | 自定义年份单元格标签(纪元、历法等) |
| `Calendar.YearPickerGrid` | `visibleYears` | `number` | min–max 跨度或 `20` | 滑动窗口中显示的年份数。同时设置 `minValue` 与 `maxValue` 时默认为完整范围 |
### Calendar.Cell Render
`Calendar.Cell` 子节点为函数时,可使用 React Aria render props:
| Prop | 类型 | 描述 |
| ---------------- | --------- | ----------- |
| `formattedDate` | `string` | 单元格的本地化日期标签 |
| `isSelected` | `boolean` | 日期是否选中 |
| `isUnavailable` | `boolean` | 日期是否不可用 |
| `isDisabled` | `boolean` | 单元格是否禁用 |
| `isOutsideMonth` | `boolean` | 日期是否属于相邻月份 |
有关支持的历法系统及其标识符的完整列表,请参阅:
* [React Aria Calendar Implementations](https://react-aria.adobe.com/internationalized/date/Calendar#implementations)
* [React Aria International Calendars](https://react-aria.adobe.com/Calendar#international-calendars)
### Related packages
* [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/) — 所有日期组件使用的日期类型(`CalendarDate`、`CalendarDateTime`、`ZonedDateTime`)与工具
* [`I18nProvider`](https://react-aria.adobe.com/I18nProvider) — 覆盖子树的 locale
* [`useLocale`](https://react-aria.adobe.com/useLocale) — 读取当前 locale 与布局方向
## 相关组件
## Related Components
* **RangeCalendar**: Interactive month grid for selecting date ranges
* **DateField**: Date input field with labels, descriptions, and validation
* **DatePicker**: Composable date picker with date field trigger and calendar popover
# DateField 日期字段
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/date-field
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(date-and-time)/date-field.mdx
> 基于 React Aria DateField 的日期输入字段,包含标签、说明与校验
## 用法
```tsx
import { DateField } from '@heroui/react';
```
```tsx
"use client";
import {DateField, Label} from "@heroui/react";
export function Basic() {
return (
日期
{(segment) => }
);
}
```
## 组件结构
```tsx
import {DateField, Label, Description, FieldError} from '@heroui/react';
export default () => (
{(segment) => }
)
```
> **DateField** 将标签、日期输入、说明与错误信息组合为单个无障碍组件。
## 示例
### 带图标
通过前缀或后缀图标增强日期输入。
```tsx
"use client";
import {Calendar} from "@gravity-ui/icons";
import {DateField, Label} from "@heroui/react";
export function WithPrefixIcon() {
return (
日期
{(segment) => }
);
}
```
```tsx
"use client";
import {Calendar} from "@gravity-ui/icons";
import {DateField, Label} from "@heroui/react";
export function WithSuffixIcon() {
return (
日期
{(segment) => }
);
}
```
```tsx
"use client";
import {Calendar, ChevronDown} from "@gravity-ui/icons";
import {DateField, Description, Label} from "@heroui/react";
export function WithPrefixAndSuffix() {
return (
日期
{(segment) => }
输入日期
);
}
```
### 变体
DateField.Group 组件支持两种视觉变体:
* **`primary`**(默认)- 标准样式带阴影,适用于大多数场景
* **`secondary`** - 低强调变体无阴影,适用于 Surface 组件内
```tsx
"use client";
import {DateField, Label} from "@heroui/react";
export function Variants() {
return (
主要变体
{(segment) => }
次要变体
{(segment) => }
);
}
```
### 表面样式
在 [Surface](/docs/components/surface) 内使用时,请在 DateField.Group 上使用 `variant="secondary"` 以应用适合 Surface 背景的低强调变体。
```tsx
"use client";
import {Calendar} from "@gravity-ui/icons";
import {DateField, Description, Label, Surface} from "@heroui/react";
export function OnSurface() {
return (
日期
{(segment) => }
输入日期
预约日期
{(segment) => }
输入预约日期
);
}
```
### 带描述
```tsx
"use client";
import {DateField, Description, Label} from "@heroui/react";
export function WithDescription() {
return (
出生日期
{(segment) => }
输入出生日期
预约日期
{(segment) => }
输入预约日期
);
}
```
### 必填字段
```tsx
"use client";
import {DateField, Description, Label} from "@heroui/react";
export function Required() {
return (
日期
{(segment) => }
开始日期
{(segment) => }
必填项
);
}
```
### 禁用
```tsx
"use client";
import {DateField, Description, Label} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
export function Disabled() {
return (
日期
{(segment) => }
该日期字段已禁用
日期
{(segment) => }
该日期字段已禁用
);
}
```
### 宽度充满
```tsx
"use client";
import {Calendar, ChevronDown} from "@gravity-ui/icons";
import {DateField, Label} from "@heroui/react";
export function FullWidth() {
return (
日期
{(segment) => }
日期
{(segment) => }
);
}
```
### 表单校验
配合 `FieldError` 使用 `isInvalid` 展示校验消息。
```tsx
"use client";
import {DateField, FieldError, Label} from "@heroui/react";
export function Invalid() {
return (
日期
{(segment) => }
请输入有效日期
日期
{(segment) => }
日期须为将来
);
}
```
### 时间粒度
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {CircleQuestion} from "@gravity-ui/icons";
import {DateField, Label, ListBox, Select, Tooltip} from "@heroui/react";
import {parseDate, parseZonedDateTime} from "@internationalized/date";
import {useState} from "react";
export function Granularity() {
const granularityOptions = [
{id: "day", label: "日"},
{id: "hour", label: "时"},
{id: "minute", label: "分"},
{id: "second", label: "秒"},
] as const;
const [granularity, setGranularity] = useState<"day" | "hour" | "minute" | "second">("day");
// Determine appropriate default value based on granularity
let defaultValue: DateValue;
if (granularity === "day") {
defaultValue = parseDate("2025-02-03");
} else {
// hour, minute, second
defaultValue = parseZonedDateTime("2025-02-03T08:45:00[America/Los_Angeles]");
}
return (
预约日期
{(segment) => }
粒度
决定日期选择器显示的最小单位。默认情况下,日期为「日」,时间为「分」。
setGranularity(value as typeof granularity)}
>
{granularityOptions.map((option) => (
{option.label}
))}
);
}
```
### 受控组件
控制 value 以与其他组件或状态管理同步。
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {Button, DateField, Description, Label} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
import {useState} from "react";
export function Controlled() {
const [value, setValue] = useState(null);
return (
日期
{(segment) => }
当前值:{value ? value.toString() : "(空)"}
setValue(today(getLocalTimeZone()))}>
设为今天
setValue(null)}>
清空
);
}
```
### 表单示例
包含校验与提交的完整表单示例。
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {Calendar} from "@gravity-ui/icons";
import {Button, DateField, Description, FieldError, Form, Label} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
import {useState} from "react";
export function FormExample() {
const [value, setValue] = useState(null);
const [isSubmitting, setIsSubmitting] = useState(false);
const todayDate = today(getLocalTimeZone());
const isInvalid = value !== null && value.compare(todayDate) < 0;
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!value || isInvalid) {
return;
}
setIsSubmitting(true);
// Simulate API call
setTimeout(() => {
console.log("已提交日期:", {date: value});
setValue(null);
setIsSubmitting(false);
}, 1500);
};
return (
预约日期
{(segment) => }
{isInvalid ? (
日期须为今天或将来
) : (
输入日期 from today onwards
)}
{isSubmitting ? "提交中…" : "Submit"}
);
}
```
### 带校验
DateField 支持 `minValue`、`maxValue` 与自定义校验逻辑。
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {DateField, Description, FieldError, Label} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
import {useState} from "react";
export function WithValidation() {
const [value, setValue] = useState(null);
const todayDate = today(getLocalTimeZone());
const isInvalid = value !== null && value.compare(todayDate) < 0;
return (
日期
{(segment) => }
{isInvalid ? (
日期须为今天或将来
) : (
输入日期 from today onwards
)}
);
}
```
### 渲染函数
```tsx
"use client";
import {DateField, Label} from "@heroui/react";
export function RenderFunction() {
return (
}
>
}>日期
}>
}>
{(segment) => }
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
"use client";
import {DateField, Label} from "@heroui/react";
export function CustomStyles() {
return (
截止日期
{(segment) => }
);
}
```
### 全局 CSS
DateField 默认样式较轻量。覆盖 `.date-field` 类可自定义容器样式。
```css
@layer components {
.date-field {
@apply flex flex-col gap-1;
&[data-invalid="true"],
&[aria-invalid="true"] {
[data-slot="description"] {
@apply hidden;
}
}
[data-slot="label"] {
@apply w-fit;
}
[data-slot="description"] {
@apply px-1;
}
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
* `.date-field` – 轻量样式的根容器(`flex flex-col gap-1`)
> **Note:** 子组件([Label](/docs/components/label)、[Description](/docs/components/description)、[FieldError](/docs/components/field-error))拥有各自的 CSS 类与样式。自定义方式请参阅对应文档。DateField.Group 样式见下文 API 参考。
### 交互状态
DateField 会根据状态自动设置以下 data 属性:
* **Invalid**:`[data-invalid="true"]` 或 `[aria-invalid="true"]` - 无效时自动隐藏 description slot
* **Required**:`[data-required="true"]` - 当 `isRequired` 为 true 时应用
* **Disabled**:`[data-disabled="true"]` - 当 `isDisabled` 为 true 时应用
* **Focus Within**:`[data-focus-within="true"]` - 任一子输入聚焦时应用
## API 参考
### DateField
DateField 继承 React Aria [DateField](https://react-aria.adobe.com/DateField.md) 的全部 props。
#### Base Props
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------------------------------------------------------------------------ | ------- | ---------------------------------- |
| `children` | `React.ReactNode \| (values: DateFieldRenderProps) => React.ReactNode` | - | 子组件(Label、DateField.Group 等)或渲染函数。 |
| `className` | `string \| (values: DateFieldRenderProps) => string` | - | 用于样式的 CSS 类,支持渲染 prop。 |
| `style` | `React.CSSProperties \| (values: DateFieldRenderProps) => React.CSSProperties` | - | 内联样式,支持渲染 prop。 |
| `fullWidth` | `boolean` | `false` | 日期字段是否占满容器宽度。 |
| `id` | `string` | - | 元素的唯一 id。 |
| `render` | `DOMRenderFunction` | - | 使用自定义渲染函数覆盖默认 DOM 元素。 |
#### Value Props
| Prop | 类型 | 默认值 | 描述 |
| ------------------ | ------------------------------------ | --- | ----------------------------------------------------------------------------------------------- |
| `value` | `DateValue \| null` | - | 当前值(受控)。类型见 [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/)。 |
| `defaultValue` | `DateValue \| null` | - | 默认值(非受控)。类型见 [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/)。 |
| `onChange` | `(value: DateValue \| null) => void` | - | 值变化时触发的事件处理函数。 |
| `placeholderValue` | `DateValue \| null` | - | 影响占位符格式的占位日期。 |
#### Validation Props
| Prop | 类型 | 默认值 | 描述 |
| -------------------- | -------------------------------------------------------------------- | ---------- | ------------------------------------------------------------------------------------------------ |
| `isRequired` | `boolean` | `false` | 是否在提交表单前要求用户输入。 |
| `isInvalid` | `boolean` | - | 值是否无效。 |
| `minValue` | `DateValue \| null` | - | 用户可选择最早日期。类型见 [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/)。 |
| `maxValue` | `DateValue \| null` | - | 用户可选择最晚日期。类型见 [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/)。 |
| `isDateUnavailable` | `(date: DateValue) => boolean` | - | 针对每个日期调用;返回 true 表示该日期不可用。 |
| `validate` | `(value: DateValue) => ValidationError \| true \| null \| undefined` | - | 自定义校验函数。 |
| `validationBehavior` | `'native' \| 'aria'` | `'native'` | 使用原生 HTML 表单校验还是 ARIA 属性。 |
#### Format Props
| Prop | 类型 | 默认值 | 描述 |
| ------------------------- | ------------- | ------- | --------------------------------------- |
| `granularity` | `Granularity` | - | 显示的最小单位。日期默认为 `"day"`,时间默认为 `"minute"`。 |
| `hourCycle` | `12 \| 24` | - | 以 12 或 24 小时制显示时间;默认由语言环境决定。 |
| `hideTimeZone` | `boolean` | `false` | 是否隐藏时区缩写。 |
| `shouldForceLeadingZeros` | `boolean` | - | 是否始终为月、日、小时等显示前导零。 |
#### State Props
| Prop | 类型 | 默认值 | 描述 |
| ------------ | --------- | --- | ----------- |
| `isDisabled` | `boolean` | - | 是否禁用输入。 |
| `isReadOnly` | `boolean` | - | 是否可选中但不可修改。 |
#### Form Props
| Prop | 类型 | 默认值 | 描述 |
| -------------- | --------- | --- | ----------------------------------------- |
| `name` | `string` | - | 输入元素的 name,用于 HTML 表单提交;以 ISO 8601 字符串提交。 |
| `autoFocus` | `boolean` | - | 是否在渲染后自动聚焦该元素。 |
| `autoComplete` | `string` | - | 输入应提供的自动完成类型。 |
#### Accessibility Props
| Prop | 类型 | 默认值 | 描述 |
| ------------------ | -------- | --- | ------------- |
| `aria-label` | `string` | - | 无可见标签时的无障碍标签。 |
| `aria-labelledby` | `string` | - | 标注该字段的元素 id。 |
| `aria-describedby` | `string` | - | 描述该字段的元素 id。 |
| `aria-details` | `string` | - | 包含额外详情的元素 id。 |
### Composition Components
DateField 与以下独立组件配合使用,请分别导入并直接使用:
* **Label** – 来自 `@heroui/react` 的字段标签
* **DateField.Group** – 日期输入分组(详见下文)
* **DateField.Input** – 来自 `@heroui/react` 的分段位编辑输入
* **DateField.InputContainer** – 可横向滚动的容器,用于组合多个输入(例如开始/结束范围)
* **DateField.Segment** – 单个日期段位(年、月、日等)
* **DateField.Prefix** / **DateField.Suffix** – 输入组的前缀与后缀插槽
* **Description** – 来自 `@heroui/react` 的辅助说明
* **FieldError** – 来自 `@heroui/react` 的校验错误信息
这些组件各自有独立的 props API。在 DateField 中直接组合使用:
```tsx
import {parseDate} from '@internationalized/date';
import {DateField, Label, Description, FieldError} from '@heroui/react';
Appointment Date
{(segment) => }
Select a date from today onwards.
Please select a valid date.
```
### DateValue Types
DateField 使用 [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/) 中的类型:
* `CalendarDate` – 不含时间与时区的日期
* `CalendarDateTime` – 含时间、不含时区
* `ZonedDateTime` – 含时间与时区
* `Time` – 仅时间
示例:
```tsx
import {parseDate, today, getLocalTimeZone} from '@internationalized/date';
// Parse from string
const date = parseDate('2024-01-15');
// Today's date
const todayDate = today(getLocalTimeZone());
// Use in DateField
{/* ... */}
```
> **说明:** DateField 依赖 [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/) 进行解析、运算与类型定义。更多类型与函数见 [Internationalized Date 文档](https://react-aria.adobe.com/internationalized/date/)。
### Render Props
对 `className`、`style` 或 `children` 使用渲染 prop 时,可使用以下值:
| Prop | 类型 | 描述 |
| ---------------- | --------- | ------------- |
| `isDisabled` | `boolean` | 字段是否禁用。 |
| `isInvalid` | `boolean` | 字段当前是否无效。 |
| `isReadOnly` | `boolean` | 字段是否只读。 |
| `isRequired` | `boolean` | 字段是否必填。 |
| `isFocused` | `boolean` | 字段是否聚焦。 |
| `isFocusWithin` | `boolean` | 是否有子元素聚焦。 |
| `isFocusVisible` | `boolean` | 焦点是否可见(键盘导航)。 |
### DateField.Group
DateField.Group 继承 React Aria `Group` 的全部 props,并额外支持:
| Prop | 类型 | 默认值 | 描述 |
| ----------- | -------------------------- | ----------- | ---------------------------------------------------------- |
| `className` | `string` | - | 与组件样式合并的 Tailwind CSS 类。 |
| `fullWidth` | `boolean` | `false` | 日期输入组是否占满容器宽度。 |
| `variant` | `"primary" \| "secondary"` | `"primary"` | 视觉变体。`primary` 为默认带阴影样式;`secondary` 为低强调、无阴影,适合用于 Surface。 |
### DateField.Input
DateField.Input 继承 React Aria `DateInput` 的全部 props,并额外支持:
| Prop | 类型 | 默认值 | 描述 |
| ----------- | -------------------------- | ----------- | ------------------------------------------------------------- |
| `className` | `string` | - | 与组件样式合并的 Tailwind CSS 类。 |
| `variant` | `"primary" \| "secondary"` | `"primary"` | 输入的视觉变体。`primary` 为默认带阴影样式;`secondary` 为低强调、无阴影,适合用于 Surface。 |
`DateField.Input` 接受渲染函数作为子节点,函数参数为日期段位;每个段位对应日期的一部分(年、月、日等)。
### DateField.Segment
DateField.Segment 继承 React Aria `DateSegment` 的全部 props:
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------- | --- | ------------------------------------------ |
| `segment` | `DateSegment` | - | 来自 DateField.Input 渲染函数的 `DateSegment` 对象。 |
| `className` | `string` | - | 与组件样式合并的 Tailwind CSS 类。 |
### DateField.InputContainer
DateField.InputContainer 接受标准 HTML `div` 属性:
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | ---------------------------------- |
| `className` | `string` | - | 与组件样式合并的 Tailwind CSS 类。 |
| `children` | `ReactNode` | - | 滚动容器中的内容(通常为多个 `DateField.Input`)。 |
### DateField.Prefix
DateField.Prefix 接受标准 HTML `div` 属性:
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | ------------------------ |
| `className` | `string` | - | 与组件样式合并的 Tailwind CSS 类。 |
| `children` | `ReactNode` | - | 前缀插槽中要显示的内容。 |
### DateField.Suffix
DateField.Suffix 接受标准 HTML `div` 属性:
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | ------------------------ |
| `className` | `string` | - | 与组件样式合并的 Tailwind CSS 类。 |
| `children` | `ReactNode` | - | 后缀插槽中要显示的内容。 |
## DateField.Group Styling
### Customizing the component classes
基础类作用于所有实例,可通过 `@layer components` 一次性覆盖。
```css
@layer components {
.date-input-group {
@apply inline-flex h-9 items-center overflow-hidden rounded-field border bg-field text-sm text-field-foreground shadow-field outline-none;
&:hover,
&[data-hovered="true"] {
@apply bg-field-hover;
}
&[data-focus-within="true"],
&:focus-within {
@apply status-focused-field;
}
&[data-invalid="true"] {
@apply status-invalid-field;
}
&[data-disabled="true"],
&[aria-disabled="true"] {
@apply status-disabled;
}
}
.date-input-group__input {
@apply flex flex-1 items-center gap-px rounded-none border-0 bg-transparent px-3 py-2 shadow-none outline-none;
}
.date-input-group__segment {
@apply inline-block rounded-md px-0.5 text-end tabular-nums outline-none;
&:focus,
&[data-focused="true"] {
@apply bg-accent-soft text-accent-soft-foreground;
}
}
.date-input-group__input-container {
@apply flex flex-1 items-center;
overflow-x: auto;
overflow-y: clip;
scrollbar-width: none;
}
.date-input-group__prefix,
.date-input-group__suffix {
@apply pointer-events-none shrink-0 text-field-placeholder flex items-center;
}
}
```
### DateField.Group CSS Classes
* `.date-input-group` – 根容器样式
* `.date-input-group__input` – 输入包裹层样式
* `.date-input-group__input-container` – 用于组合多个输入的滚动容器
* `.date-input-group__segment` – 单个日期段位样式
* `.date-input-group__prefix` – 前缀元素样式
* `.date-input-group__suffix` – 后缀元素样式
### DateField.Group Interactive States
* **Hover**:`:hover` 或 `[data-hovered="true"]`
* **Focus Within**:`[data-focus-within="true"]` 或 `:focus-within`
* **Invalid**:`[data-invalid="true"]`(与 `aria-invalid` 同步)
* **Disabled**:`[data-disabled="true"]` 或 `[aria-disabled="true"]`
* **Segment Focus**:段位上 `:focus` 或 `[data-focused="true"]`
* **Segment Placeholder**:段位上 `[data-placeholder="true"]`
## 相关组件
## Related Components
* **DatePicker**: Composable date picker with date field trigger and calendar popover
* **Calendar**: Interactive month grid for selecting dates
* **Label**: Accessible label for form controls
# DatePicker 日期选择器
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/date-picker
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(date-and-time)/date-picker.mdx
> 基于 React Aria DatePicker,通过 DateField 与 Calendar 组合的可组合日期选择器
## 用法
```tsx
import { DatePicker, DateField, Calendar, Label } from '@heroui/react';
```
```tsx
"use client";
import {Calendar, DateField, DatePicker, Label} from "@heroui/react";
export function Basic() {
return (
日期
{(segment) => }
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
## 组件结构
`DatePicker` 采用组合优先 API。显式组合 `DateField` 与 `Calendar` 以控制结构与样式。
```tsx
import {Calendar, DateField, DatePicker, Label} from '@heroui/react';
export default () => (
{(segment) => }
{(day) => {day} }
{(date) => }
)
```
## 示例
### 禁用
```tsx
"use client";
import {Calendar, DateField, DatePicker, Description, Label} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
export function Disabled() {
return (
日期
{(segment) => }
该日期选择器已禁用。
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
### 受控组件
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {Button, Calendar, DateField, DatePicker, Description, Label} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
import {useState} from "react";
export function Controlled() {
const [value, setValue] = useState(today(getLocalTimeZone()));
return (
日期
{(segment) => }
{(day) => {day} }
{(date) => }
{({year}) => }
当前值:{value ? value.toString() : "(空)"}
setValue(today(getLocalTimeZone()))}>
设为今天
setValue(null)}>
清空
);
}
```
### 表单校验
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {Calendar, DateField, DatePicker, FieldError, Label} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
import {useState} from "react";
export function WithValidation() {
const [value, setValue] = useState(null);
const currentDate = today(getLocalTimeZone());
const isInvalid = value != null && value.compare(currentDate) < 0;
return (
预约日期
{(segment) => }
日期须为今天或将来。
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
### 格式选项
使用 `granularity`、`hourCycle`、`hideTimeZone`、`shouldForceLeadingZeros` 等 props 控制 DatePicker 值的显示方式。
```tsx
"use client";
import type {TimeValue} from "@heroui/react";
import type {DateValue} from "@internationalized/date";
import {
Calendar,
DateField,
DatePicker,
Label,
ListBox,
Select,
Switch,
TimeField,
} from "@heroui/react";
import {getLocalTimeZone, parseDate, parseZonedDateTime} from "@internationalized/date";
import {useMemo, useState} from "react";
type Granularity = "day" | "hour" | "minute" | "second";
type HourCycle = 12 | 24;
const granularityOptions: {label: string; value: Granularity}[] = [
{label: "日", value: "day"},
{label: "时", value: "hour"},
{label: "分", value: "minute"},
{label: "秒", value: "second"},
];
const hourCycleOptions: {label: string; value: HourCycle}[] = [
{label: "12 小时制", value: 12},
{label: "24 小时制", value: 24},
];
export function FormatOptions() {
const [granularity, setGranularity] = useState("minute");
const [hourCycle, setHourCycle] = useState(12);
const [hideTimeZone, setHideTimeZone] = useState(false);
const [shouldForceLeadingZeros, setShouldForceLeadingZeros] = useState(false);
const timeGranularity = granularity !== "day" ? granularity : undefined;
const showTimeField = !!timeGranularity;
const defaultValue = useMemo(() => {
const localTimeZone = getLocalTimeZone();
if (granularity === "day") {
return parseDate("2026-02-03");
}
return parseZonedDateTime(`2026-02-03T08:45:00[${localTimeZone}]`);
}, [granularity]);
return (
{({state}) => (
<>
日期和时间
{(segment) => }
{(day) => {day} }
{(date) => }
{({year}) => }
{!!showTimeField && (
时间
state.setTimeValue(v as TimeValue)}
>
{(segment) => }
)}
>
)}
setGranularity(value as Granularity)}
>
粒度
{granularityOptions.map((option) => (
{option.label}
))}
setHourCycle(Number(value) as HourCycle)}
>
小时制
{hourCycleOptions.map((option) => (
{option.label}
))}
隐藏时区
强制前导零
);
}
```
### 表单示例
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {
Button,
Calendar,
DateField,
DatePicker,
Description,
FieldError,
Form,
Label,
} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
import {useState} from "react";
export function FormExample() {
const [value, setValue] = useState(null);
const [isSubmitting, setIsSubmitting] = useState(false);
const currentDate = today(getLocalTimeZone());
const isInvalid = value != null && value.compare(currentDate) < 0;
const handleSubmit = (event: React.FormEvent) => {
event.preventDefault();
if (!value || isInvalid) {
return;
}
setIsSubmitting(true);
setTimeout(() => {
setValue(null);
setIsSubmitting(false);
}, 1200);
};
return (
预约日期
{(segment) => }
{isInvalid ? (
日期须为今天或将来。
) : (
请选择有效的预约日期。
)}
{(day) => {day} }
{(date) => }
{({year}) => }
{isSubmitting ? "提交中…" : "提交"}
);
}
```
### 自定义指示器
未提供 children 时,`DatePicker.TriggerIndicator` 渲染默认 `IconCalendar`。传入 children 可替换。
```tsx
"use client";
import {Calendar, DateField, DatePicker, Description, Label} from "@heroui/react";
import {Icon} from "@iconify/react";
export function WithCustomIndicator() {
return (
日期
{(segment) => }
通过传入自定义子元素替换默认日历图标。
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
### 渲染函数
```tsx
"use client";
import {Calendar, DateField, DatePicker, Label} from "@heroui/react";
export function RenderFunction() {
return (
}
>
}>日期
}
>
}>
{(segment) => (
}
segment={segment}
/>
)}
}
>
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
### 国际化日历
默认情况下,DatePicker 使用用户 locale 的日历系统显示日期。可用 `I18nProvider` 包裹并设置 [Unicode 日历 locale 扩展](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string) 覆盖。
以下示例展示印度日历系统:
```tsx
"use client";
import {Calendar, DateField, DatePicker, Label} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
import {I18nProvider} from "react-aria-components";
export function InternationalCalendar() {
return (
活动日期
{(segment) => }
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
**Note:** 无论显示的 locale 如何,`onChange` 事件始终返回与 `value` 或 `defaultValue` 相同日历系统的日期(未提供 value 时为 Gregorian)。这确保应用逻辑在单一日历系统下一致运行,同时仍可按用户偏好格式显示日期。
完整支持的日历系统及其标识符列表请参阅:
* [React Aria Calendar Implementations](https://react-aria.adobe.com/internationalized/date/Calendar#implementations)
* [React Aria International Calendars](https://react-aria.adobe.com/Calendar#international-calendars)
## 自定义样式
### Tailwind CSS
```tsx
"use client";
import {Calendar, DateField, DatePicker, Label} from "@heroui/react";
export function CustomStyles() {
return (
活动日期
{(segment) => }
{(day) => (
{day}
)}
{(date) => (
)}
);
}
```
### 全局 CSS
使用 `@layer components` 自定义 DatePicker 基础类。
```css
@layer components {
.date-picker {
@apply inline-flex flex-col gap-1;
}
.date-picker__trigger {
@apply inline-flex items-center justify-between;
}
.date-picker__trigger-indicator {
@apply text-muted;
}
.date-picker__popover {
@apply min-w-[var(--trigger-width)] p-0;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 命名以便复用自定义。
### CSS 类
DatePicker 在 `packages/styles/components/date-picker.css` 中使用以下类:
* `.date-picker` - 根包裹层
* `.date-picker__trigger` - 打开 popover 的触发器部分
* `.date-picker__trigger-indicator` - 默认/自定义指示器 slot
* `.date-picker__popover` - Popover 内容包裹层
### 交互状态
DatePicker 支持 React Aria data 属性与伪状态:
* **Open**:触发器上 `[data-open="true"]`
* **Disabled**:触发器上 `[data-disabled="true"]` 或 `[aria-disabled="true"]`
* **Focus visible**:触发器上 `:focus-visible` 或 `[data-focus-visible="true"]`
* **Hover**:触发器上 `:hover` 或 `[data-hovered="true"]`
## API 参考
### DatePicker
DatePicker 继承 React Aria [DatePicker](https://react-aria.adobe.com/DatePicker.md) 的所有 props。
| Prop | 类型 | 默认值 | 描述 |
| -------------- | ----------------------------------------------------------------------------- | ------- | -------------------------- |
| `value` | `DateValue \| null` | - | 受控选中日期值 |
| `defaultValue` | `DateValue \| null` | - | 非受控模式下的默认选中值 |
| `onChange` | `(value: DateValue \| null) => void` | - | 选中日期变化时调用 |
| `isOpen` | `boolean` | - | 受控 popover 打开状态 |
| `defaultOpen` | `boolean` | `false` | 初始 popover 打开状态 |
| `onOpenChange` | `(isOpen: boolean) => void` | - | popover 打开状态变化时调用 |
| `isDisabled` | `boolean` | `false` | 禁用日期选择与触发器交互 |
| `isInvalid` | `boolean` | - | 标记字段为无效以显示校验状态 |
| `minValue` | `DateValue` | - | 最小可选日期 |
| `maxValue` | `DateValue` | - | 最大可选日期 |
| `name` | `string` | - | HTML 表单提交时使用的 name |
| `children` | `ReactNode \| (values: DatePickerRenderProps) => ReactNode` | - | 组合内容或 render 函数 |
| `render` | `DOMRenderFunction` | - | 使用自定义 render 函数覆盖默认 DOM 元素 |
### Composition Parts
| Component | Description |
| ----------------------------- | ------------------------------- |
| `DatePicker.Root` | 根 date picker 容器与状态所有者 |
| `DatePicker.Trigger` | 触发按钮,通常渲染在 `DateField.Suffix` 内 |
| `DatePicker.TriggerIndicator` | 带默认日历图标的指示器 slot |
| `DatePicker.Popover` | `Calendar` 内容的 Popover 包裹层 |
### Related packages
* [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/) — 所有日期组件使用的日期类型(`CalendarDate`、`CalendarDateTime`、`ZonedDateTime`)与工具
* [`I18nProvider`](https://react-aria.adobe.com/I18nProvider) — 为子树覆盖 locale
* [`useLocale`](https://react-aria.adobe.com/useLocale) — 读取当前 locale 与布局方向
## 相关组件
## Related Components
* **Calendar**: Interactive month grid for selecting dates
* **RangeCalendar**: Interactive month grid for selecting date ranges
* **DateField**: Date input field with labels, descriptions, and validation
# DateRangePicker 日期范围选择器
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/date-range-picker
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(date-and-time)/date-range-picker.mdx
> 基于 React Aria DateRangePicker,通过 DateField 与 RangeCalendar 组合的可组合日期范围选择器
## 用法
```tsx
import { DateField, DateRangePicker, Label, RangeCalendar } from '@heroui/react';
```
```tsx
"use client";
import {DateField, DateRangePicker, Label, RangeCalendar} from "@heroui/react";
export function Basic() {
return (
出行日期
{(segment) => }
{(segment) => }
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
## 组件结构
`DateRangePicker` 采用组合优先 API。显式组合 `DateField` 与 `RangeCalendar` 以控制结构与样式。
```tsx
import {DateField, DateRangePicker, Label, RangeCalendar} from '@heroui/react';
export default () => (
{(segment) => }
{(segment) => }
{(day) => {day} }
{(date) => }
)
```
## 示例
### 禁用
```tsx
"use client";
import {DateField, DateRangePicker, Description, Label, RangeCalendar} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
export function Disabled() {
const start = today(getLocalTimeZone());
return (
出行日期
{(segment) => }
{(segment) => }
该日期范围选择器已禁用。
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
### 受控组件
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {Button, DateField, DateRangePicker, Description, Label, RangeCalendar} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
import {useState} from "react";
type DateRange = {
start: DateValue;
end: DateValue;
};
export function Controlled() {
const start = today(getLocalTimeZone());
const [value, setValue] = useState({end: start.add({days: 4}), start});
return (
出行日期
{(segment) => }
{(segment) => }
{(day) => {day} }
{(date) => }
{({year}) => }
当前值:{value ? `${value.start.toString()} 至 ${value.end.toString()}` : "(空)"}
{
const nextStart = today(getLocalTimeZone());
setValue({end: nextStart.add({days: 6}), start: nextStart});
}}
>
设为一周
setValue(null)}>
清空
);
}
```
### 表单校验
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {DateField, DateRangePicker, FieldError, Label, RangeCalendar} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
import {useState} from "react";
type DateRange = {
start: DateValue;
end: DateValue;
};
export function WithValidation() {
const [value, setValue] = useState(null);
const currentDate = today(getLocalTimeZone());
const isInvalid =
value != null && (value.start.compare(currentDate) < 0 || value.end.compare(value.start) < 0);
return (
预订时段
{(segment) => }
{(segment) => }
请选择从今天起的有效日期范围。
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
### 格式选项
使用 `granularity`、`hourCycle`、`hideTimeZone`、`shouldForceLeadingZeros` 等 props 控制 DateRangePicker 值的显示方式。
```tsx
"use client";
import type {TimeValue} from "@heroui/react";
import type {DateValue} from "@internationalized/date";
import {
DateField,
DateRangePicker,
Label,
ListBox,
RangeCalendar,
Select,
Separator,
Switch,
TimeField,
useLocale,
} from "@heroui/react";
import {
DateFormatter,
getLocalTimeZone,
parseDate,
parseZonedDateTime,
} from "@internationalized/date";
import {useMemo, useState} from "react";
type Granularity = "day" | "hour" | "minute" | "second";
type HourCycle = 12 | 24;
type DateRange = {
start: DateValue;
end: DateValue;
};
const granularityOptions: {label: string; value: Granularity}[] = [
{label: "日", value: "day"},
{label: "时", value: "hour"},
{label: "分", value: "minute"},
{label: "秒", value: "second"},
];
const hourCycleOptions: {label: string; value: HourCycle}[] = [
{label: "12 小时制", value: 12},
{label: "24 小时制", value: 24},
];
export function FormatOptions() {
const [granularity, setGranularity] = useState("minute");
const [hourCycle, setHourCycle] = useState(12);
const [hideTimeZone, setHideTimeZone] = useState(false);
const [shouldForceLeadingZeros, setShouldForceLeadingZeros] = useState(false);
const {locale} = useLocale();
const dateFormatter = new DateFormatter(locale, {
day: "numeric",
month: "short",
year: "numeric",
});
const formatDate = (date: DateRange) => {
const localTimeZone = getLocalTimeZone();
const start = date.start.toDate(localTimeZone);
const end = date.end.toDate(localTimeZone);
return dateFormatter.formatRange(start, end);
};
const defaultValue = useMemo(() => {
const localTimeZone = getLocalTimeZone();
if (granularity === "day") {
return {
end: parseDate("2025-02-10"),
start: parseDate("2025-02-03"),
};
}
return {
end: parseZonedDateTime(`2026-02-10T18:45:00[${localTimeZone}]`),
start: parseZonedDateTime(`2026-02-03T08:45:00[${localTimeZone}]`),
};
}, [granularity]);
const timeGranularity = granularity !== "day" ? granularity : undefined;
const showTimeField = !!timeGranularity;
return (
{({state}) => (
<>
日期范围
{(segment) => }
{(segment) => }
{(day) => {day} }
{(date) => }
{({year}) => }
{!!showTimeField && (
开始时间
state.setTimeRange({
end: state.timeRange?.end as TimeValue,
start: v as TimeValue,
})
}
>
{(segment) => }
结束时间
state.setTimeRange({
end: v as TimeValue,
start: state.timeRange?.start as TimeValue,
})
}
>
{(segment) => }
)}
已选:{" "}
{state.value && state.value.start && state.value.end
? formatDate({end: state.value.end, start: state.value.start})
: "未选择日期"}
>
)}
格式选项
setGranularity(value as Granularity)}
>
粒度
{granularityOptions.map((option) => (
{option.label}
))}
setHourCycle(Number(value) as HourCycle)}
>
小时制
{hourCycleOptions.map((option) => (
{option.label}
))}
隐藏时区
强制前导零
);
}
```
### 表单示例
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {
Button,
DateField,
DateRangePicker,
Description,
FieldError,
Form,
Label,
RangeCalendar,
} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
import {useState} from "react";
type DateRange = {
start: DateValue;
end: DateValue;
};
export function FormExample() {
const [value, setValue] = useState(null);
const [isSubmitting, setIsSubmitting] = useState(false);
const currentDate = today(getLocalTimeZone());
const isInvalid =
value != null && (value.start.compare(currentDate) < 0 || value.end.compare(value.start) < 0);
const handleSubmit = (event: React.FormEvent) => {
event.preventDefault();
if (!value || isInvalid) return;
setIsSubmitting(true);
setTimeout(() => {
setValue(null);
setIsSubmitting(false);
}, 1200);
};
return (
出行日期
{(segment) => }
{(segment) => }
{isInvalid ? (
请选择从今天起的有效日期范围。
) : (
选择入住与退房日期。
)}
{(day) => {day} }
{(date) => }
{({year}) => }
{isSubmitting ? "提交中…" : "提交"}
);
}
```
### 自定义指示器
未提供 children 时,`DateRangePicker.TriggerIndicator` 渲染默认 `IconCalendar`。传入 children 可替换。
```tsx
"use client";
import {DateField, DateRangePicker, Description, Label, RangeCalendar} from "@heroui/react";
import {Icon} from "@iconify/react";
export function WithCustomIndicator() {
return (
出行日期
{(segment) => }
{(segment) => }
通过传入自定义子元素替换默认日历图标。
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
### 渲染函数
```tsx
"use client";
import {DateField, DateRangePicker, Label, RangeCalendar} from "@heroui/react";
export function RenderFunction() {
return (
}
startName="startDate"
>
出行日期
{(segment) => }
{(segment) => }
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
### 国际化日历
默认情况下,DateRangePicker 使用用户 locale 的日历系统显示日期。可用 `I18nProvider` 包裹并设置 [Unicode 日历 locale 扩展](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string) 覆盖。
以下示例展示印度日历系统:
```tsx
"use client";
import {DateField, DateRangePicker, Label, RangeCalendar} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
import {I18nProvider} from "react-aria-components";
export function InternationalCalendar() {
const start = today(getLocalTimeZone());
return (
出行日期
{(segment) => }
{(segment) => }
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
**Note:** 无论显示的 locale 如何,`onChange` 事件始终返回与 `value` 或 `defaultValue` 相同日历系统的日期(未提供 value 时为 Gregorian)。
完整支持的日历系统及其标识符列表请参阅:
* [React Aria Calendar Implementations](https://react-aria.adobe.com/internationalized/date/Calendar#implementations)
* [React Aria International Calendars](https://react-aria.adobe.com/Calendar#international-calendars)
## 自定义样式
### Tailwind CSS
```tsx
"use client";
import {DateField, DateRangePicker, Label, RangeCalendar} from "@heroui/react";
export function CustomStyles() {
return (
入住日期
{(segment) => }
{(segment) => }
{(day) => (
{day}
)}
{(date) => }
);
}
```
### 全局 CSS
使用 `@layer components` 自定义 DateRangePicker 基础类。
```css
@layer components {
.date-range-picker {
@apply inline-flex flex-col gap-1;
}
.date-range-picker__trigger {
@apply inline-flex items-center justify-between;
}
.date-range-picker__trigger-indicator {
@apply text-muted;
}
.date-range-picker__range-separator {
@apply px-2 text-default;
}
.date-range-picker__popover {
@apply min-w-[var(--trigger-width)] p-0;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
DateRangePicker 在 `packages/styles/components/date-range-picker.css` 中使用以下类:
* `.date-range-picker` - 根包裹层
* `.date-range-picker__trigger` - 打开 popover 的触发器部分
* `.date-range-picker__trigger-indicator` - 默认/自定义指示器 slot
* `.date-range-picker__range-separator` - 开始与结束日期输入之间的分隔符
* `.date-range-picker__popover` - Popover 内容包裹层
### 交互状态
DateRangePicker 支持 React Aria data 属性与伪状态:
* **Open**:触发器上 `[data-open="true"]`
* **Disabled**:触发器上 `[data-disabled="true"]` 或 `[aria-disabled="true"]`
* **Focus visible**:触发器上 `:focus-visible` 或 `[data-focus-visible="true"]`
* **Hover**:触发器上 `:hover` 或 `[data-hovered="true"]`
## API 参考
### DateRangePicker
DateRangePicker 继承 React Aria [DateRangePicker](https://react-aria.adobe.com/DateRangePicker) 的所有 props。
| Prop | 类型 | 默认值 | 描述 |
| -------------- | ---------------------------------------------------------------------------------- | ------- | -------------------------- |
| `value` | `{ start: DateValue; end: DateValue } \| null` | - | 受控选中日期范围值 |
| `defaultValue` | `{ start: DateValue; end: DateValue } \| null` | - | 非受控模式下的默认选中范围 |
| `onChange` | `(value: { start: DateValue; end: DateValue } \| null) => void` | - | 选中范围变化时调用 |
| `isOpen` | `boolean` | - | 受控 popover 打开状态 |
| `defaultOpen` | `boolean` | `false` | 初始 popover 打开状态 |
| `onOpenChange` | `(isOpen: boolean) => void` | - | popover 打开状态变化时调用 |
| `isDisabled` | `boolean` | `false` | 禁用范围选择与触发器交互 |
| `isInvalid` | `boolean` | - | 标记字段为无效以显示校验状态 |
| `minValue` | `DateValue` | - | 最小可选日期 |
| `maxValue` | `DateValue` | - | 最大可选日期 |
| `startName` | `string` | - | HTML 表单提交时开始日期的 name |
| `endName` | `string` | - | HTML 表单提交时结束日期的 name |
| `children` | `ReactNode \| (values: DateRangePickerRenderProps) => ReactNode` | - | 组合内容或 render 函数 |
| `render` | `DOMRenderFunction` | - | 使用自定义 render 函数覆盖默认 DOM 元素 |
### Composition Parts
| Component | Description |
| ---------------------------------- | ------------------------------- |
| `DateRangePicker.Root` | 根 date range picker 容器与状态所有者 |
| `DateRangePicker.Trigger` | 触发按钮,通常渲染在 `DateField.Suffix` 内 |
| `DateRangePicker.TriggerIndicator` | 带默认日历图标的指示器 slot |
| `DateRangePicker.RangeSeparator` | 开始与结束日期输入之间的分隔符部分 |
| `DateRangePicker.Popover` | `RangeCalendar` 内容的 Popover 包裹层 |
### Related packages
* [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/) — 所有日期组件使用的日期类型(`CalendarDate`、`CalendarDateTime`、`ZonedDateTime`)与工具
* [`I18nProvider`](https://react-aria.adobe.com/I18nProvider) — 为子树覆盖 locale
* [`useLocale`](https://react-aria.adobe.com/useLocale) — 读取当前 locale 与布局方向
## 相关组件
## Related Components
* **RangeCalendar**: Interactive month grid for selecting date ranges
* **Calendar**: Interactive month grid for selecting dates
* **DateField**: Date input field with labels, descriptions, and validation
# RangeCalendar 范围日历
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/range-calendar
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(date-and-time)/range-calendar.mdx
> 基于 React Aria RangeCalendar 的可组合日期范围选择器,包含月份网格、导航与年份选择支持。
## 用法
```tsx
import { RangeCalendar } from '@heroui/react';
```
```tsx
"use client";
import {RangeCalendar} from "@heroui/react";
export function Basic() {
return (
{(day) => {day} }
{(date) => }
);
}
```
## 组件结构
```tsx
import {RangeCalendar} from '@heroui/react';
export default () => (
{(day) => {day} }
{(date) => }
)
```
## 示例
### 禁用
```tsx
"use client";
import {Description, RangeCalendar} from "@heroui/react";
export function Disabled() {
return (
{(day) => {day} }
{(date) => }
区间日历已禁用
);
}
```
### 年份选择
`RangeCalendar.YearPickerTrigger`, `RangeCalendar.YearPickerGrid`, and their body/cell subcomponents provide an integrated year navigation pattern.
```tsx
"use client";
import {RangeCalendar} from "@heroui/react";
export function YearPicker() {
return (
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
### 默认值
```tsx
"use client";
import {RangeCalendar} from "@heroui/react";
import {parseDate} from "@internationalized/date";
export function DefaultValue() {
return (
{(day) => {day} }
{(date) => }
);
}
```
### 受控组件
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {Button, ButtonGroup, Description, RangeCalendar} from "@heroui/react";
import {
getLocalTimeZone,
parseDate,
startOfMonth,
startOfWeek,
today,
} from "@internationalized/date";
import {useState} from "react";
import {useLocale} from "react-aria-components";
type DateRange = {
start: DateValue;
end: DateValue;
};
export function Controlled() {
const [value, setValue] = useState(null);
const [focusedDate, setFocusedDate] = useState(parseDate("2025-12-25"));
const {locale} = useLocale();
return (
{
const start = today(getLocalTimeZone());
setFocusedDate(start);
}}
>
本周
{
const nextWeekStart = startOfWeek(today(getLocalTimeZone()).add({weeks: 1}), locale);
setFocusedDate(nextWeekStart);
}}
>
下周
{
const nextMonthStart = startOfMonth(today(getLocalTimeZone()).add({months: 1}));
setFocusedDate(nextMonthStart);
}}
>
下月
{(day) => {day} }
{(date) => }
已选区间: {value ? `${value.start.toString()} -> ${value.end.toString()}` : "(无)"}
{
const start = today(getLocalTimeZone());
setValue({end: start.add({days: 6}), start});
setFocusedDate(start);
}}
>
设为 1 周
{
const start = parseDate("2025-12-20");
setValue({end: parseDate("2025-12-31"), start});
setFocusedDate(start);
}}
>
设为节假日
setValue(null)}>
清空
);
}
```
### 日期范围限制
```tsx
"use client";
import {Description, RangeCalendar} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
export function MinMaxDates() {
const now = today(getLocalTimeZone());
const minDate = now;
const maxDate = now.add({months: 3});
return (
{(day) => {day} }
{(date) => }
请在今天与 {maxDate.toString()} 之间选择日期。
);
}
```
### 不可用日期
使用 `isDateUnavailable` 屏蔽周末、节假日或已预订等不可用日期。
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {Description, RangeCalendar} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
export function UnavailableDates() {
const now = today(getLocalTimeZone());
const blockedRanges = [
[now.add({days: 2}), now.add({days: 5})],
[now.add({days: 12}), now.add({days: 13})],
] as const;
const isDateUnavailable = (date: DateValue) => {
return blockedRanges.some(([start, end]) => date.compare(start) >= 0 && date.compare(end) <= 0);
};
return (
{(day) => {day} }
{(date) => }
部分日期不可选
);
}
```
### 基于锚点的不可用日期
选择范围时,`isDateUnavailable` 会收到第二个参数 `anchorDate`(首个选中日期)。可用它限制哪些结束日期有效(例如起始日期后 7 天内)。
```tsx
"use client";
import type {CalendarDate, DateValue} from "@internationalized/date";
import {Description, RangeCalendar} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
export function AnchorUnavailableDates() {
const now = today(getLocalTimeZone());
const isDateUnavailable = (date: DateValue, anchorDate: CalendarDate | null) => {
return anchorDate != null && Math.abs(date.compare(anchorDate)) > 7;
};
return (
{(day) => {day} }
{(date) => }
选择开始日期后,仅前后 7 天内的日期可选
);
}
```
### 月份周数
将 `weeksInMonth` 设为固定值(例如 `6`),在月份切换时保持网格高度稳定。
```tsx
"use client";
import {Description, RangeCalendar} from "@heroui/react";
export function WeeksInMonth() {
return (
{(day) => {day} }
{(date) => }
每月固定显示 6 周,切换月份时避免布局跳动
);
}
```
### 周视图
设置 `visibleDuration={{ weeks: n }}` 一次显示一个或多个周。导航按可见周范围前进。显示多周时,使用 `pageBehavior="single"` 每次移动一周。
```tsx
"use client";
import {Label, ListBox, RangeCalendar, Select} from "@heroui/react";
import {useState} from "react";
const weekOptions = [
{id: "1", name: "1 周"},
{id: "2", name: "2 周"},
{id: "3", name: "3 周"},
{id: "4", name: "4 周"},
{id: "5", name: "5 周"},
{id: "6", name: "6 周"},
{id: "8", name: "8 周"},
] as const;
export function WeekView() {
const [weeks, setWeeks] = useState(1);
return (
value && setWeeks(Number(value))}
>
可见周数
{weekOptions.map((option) => (
{option.name}
))}
{(day) => {day} }
{(date) => }
);
}
```
### 日视图
设置 `visibleDuration={{ days: n }}` 显示连续日期的滚动窗口。导航按可见日范围前进。显示多天时,使用 `pageBehavior="single"` 每次移动一天。
```tsx
"use client";
import {Label, ListBox, RangeCalendar, Select} from "@heroui/react";
import {useState} from "react";
const dayOptions = [
{id: "1", name: "1 天"},
{id: "5", name: "5 天"},
{id: "7", name: "7 天"},
{id: "8", name: "8 天"},
{id: "10", name: "10 天"},
{id: "14", name: "14 天"},
{id: "21", name: "21 天"},
] as const;
export function DayView() {
const [days, setDays] = useState(5);
return (
value && setDays(Number(value))}
>
可见天数
{dayOptions.map((option) => (
{option.name}
))}
{(day) => {day} }
{(date) => }
);
}
```
### 非连续范围
启用 `allowsNonContiguousRanges` 以允许跨越不可用日期进行选择。
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {Description, RangeCalendar} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
export function AllowsNonContiguousRanges() {
const now = today(getLocalTimeZone());
const blockedRanges = [
[now.add({days: 2}), now.add({days: 5})],
[now.add({days: 12}), now.add({days: 13})],
] as const;
const isDateUnavailable = (date: DateValue) => {
return blockedRanges.some(([start, end]) => date.compare(start) >= 0 && date.compare(end) <= 0);
};
return (
{(day) => {day} }
{(date) => }
允许跨不可选日期选择非连续区间
);
}
```
### 只读
```tsx
"use client";
import {Description, RangeCalendar} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
export function ReadOnly() {
return (
{(day) => {day} }
{(date) => }
区间日历为只读
);
}
```
### 无效状态
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {Description, RangeCalendar} from "@heroui/react";
import {getLocalTimeZone, today} from "@internationalized/date";
import {useState} from "react";
type DateRange = {
start: DateValue;
end: DateValue;
};
export function Invalid() {
const now = today(getLocalTimeZone());
const [value, setValue] = useState({
end: now.add({days: 14}),
start: now.add({days: 6}),
});
const isInvalid = value.end.compare(value.start) > 7;
return (
{(day) => {day} }
{(date) => }
{isInvalid ? (
最长入住时间为 1 周
) : (
请选择最多 7 天的入住区间
)}
);
}
```
### 聚焦值
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {Button, Description, RangeCalendar} from "@heroui/react";
import {parseDate} from "@internationalized/date";
import {useState} from "react";
export function FocusedValue() {
const [focusedDate, setFocusedDate] = useState(parseDate("2025-06-15"));
return (
{(day) => {day} }
{(date) => }
聚焦: {focusedDate.toString()}
setFocusedDate(parseDate("2025-01-01"))}
>
跳转到一月
setFocusedDate(parseDate("2025-06-15"))}
>
跳转到六月
setFocusedDate(parseDate("2025-12-25"))}
>
跳转到圣诞节
);
}
```
### 单元格标记
可自定义 `RangeCalendar.Cell` 的子内容,并使用 `RangeCalendar.CellIndicator` 展示事件等元数据。
```tsx
"use client";
import {RangeCalendar} from "@heroui/react";
import {getLocalTimeZone, isToday} from "@internationalized/date";
const datesWithEvents = [3, 7, 12, 15, 21, 28];
export function WithIndicators() {
return (
{(day) => {day} }
{(date) => (
{({formattedDate}) => (
<>
{formattedDate}
{(isToday(date, getLocalTimeZone()) || datesWithEvents.includes(date.day)) && (
)}
>
)}
)}
);
}
```
### 典型场景
```tsx
"use client";
import type {DateValue} from "@internationalized/date";
import {Button, RangeCalendar} from "@heroui/react";
import {getLocalTimeZone, isWeekend, today} from "@internationalized/date";
import {useState} from "react";
import {useLocale} from "react-aria-components";
type DateRange = {
start: DateValue;
end: DateValue;
};
export function BookingCalendar() {
const [selectedRange, setSelectedRange] = useState(null);
const {locale} = useLocale();
const blockedDates = [5, 6, 12, 13, 14, 20];
const isDateUnavailable = (date: DateValue) => {
return isWeekend(date, locale) || blockedDates.includes(date.day);
};
return (
{(day) => {day} }
{(date) => (
{({formattedDate, isUnavailable}) => (
<>
{formattedDate}
{!isUnavailable &&
!isWeekend(date, locale) &&
blockedDates.includes(date.day) && }
>
)}
)}
不可订日期
周末/不可用
{selectedRange ? (
预订 {selectedRange.start.toString()} → {selectedRange.end.toString()}
) : null}
);
}
```
### 多月份展示
结合 `visibleDuration` 与 `offset` 渲染多个网格,适用于预订与规划场景。
```tsx
"use client";
import {RangeCalendar} from "@heroui/react";
export function MultipleMonths() {
return (
{(day) => {day} }
{(date) => }
{(day) => {day} }
{(date) => }
);
}
```
### 国际化日历
默认情况下,RangeCalendar 使用用户 locale 的历法系统显示日期。可用 `I18nProvider` 包裹组件,并设置 [Unicode 历法 locale 扩展](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string) 覆盖。
以下示例展示印度历法系统:
```tsx
"use client";
import {RangeCalendar} from "@heroui/react";
import {I18nProvider} from "react-aria-components";
export function InternationalCalendar() {
return (
{(day) => {day} }
{(date) => }
{({year}) => }
);
}
```
**注意:** 无论显示 locale 如何,`onChange` 事件始终返回与 `value` 或 `defaultValue` 相同历法系统的日期(未提供 value 时为公历)。
## 自定义样式
### Tailwind CSS
```tsx
"use client";
import {RangeCalendar} from "@heroui/react";
import {parseDate} from "@internationalized/date";
const cellClassName = [
"rounded-md",
"**:data-[slot=range-calendar-cell-button]:rounded-md",
"data-[outside-month=true]:text-muted data-[outside-month=true]:opacity-50",
"data-[hovered=true]:not-data-[selected=true]:**:data-[slot=range-calendar-cell-button]:bg-default",
"data-[today=true]:**:data-[slot=range-calendar-cell-button]:bg-success-soft",
"data-[today=true]:**:data-[slot=range-calendar-cell-button]:text-success-soft-foreground",
"data-[today=true]:data-[hovered=true]:not-data-[selected=true]:**:data-[slot=range-calendar-cell-button]:bg-success-soft-hover",
"data-[selected=true]:rounded-none data-[selected=true]:bg-success-soft",
"data-[outside-month=true]:data-[selected=true]:bg-default/20",
"data-[selection-start=true]:rounded-tl-md data-[selection-start=true]:rounded-bl-md",
"data-[selection-end=true]:rounded-tr-md data-[selection-end=true]:rounded-br-md",
"data-[selection-start=true]:**:data-[slot=range-calendar-cell-button]:bg-success",
"data-[selection-start=true]:**:data-[slot=range-calendar-cell-button]:text-success-foreground",
"data-[selection-start=true]:data-[pressed=true]:**:data-[slot=range-calendar-cell-button]:bg-success-hover",
"data-[selection-end=true]:**:data-[slot=range-calendar-cell-button]:bg-success",
"data-[selection-end=true]:**:data-[slot=range-calendar-cell-button]:text-success-foreground",
"data-[selection-end=true]:data-[pressed=true]:**:data-[slot=range-calendar-cell-button]:bg-success-hover",
].join(" ");
export function CustomStyles() {
return (
{(day) => (
{day}
)}
{(date) => }
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.range-calendar {
@apply w-80 rounded-2xl border border-border bg-surface p-3 shadow-sm;
}
.range-calendar__heading {
@apply text-sm font-semibold text-default;
}
.range-calendar__cell[data-selected="true"] .range-calendar__cell-button {
@apply bg-accent text-accent-foreground;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
RangeCalendar 在 `packages/styles/components/range-calendar.css` 与 `packages/styles/components/calendar-year-picker.css` 中使用以下类:
* `.range-calendar` - 根容器。
* `.range-calendar__header` - 含导航按钮与标题的头部行。
* `.range-calendar__heading` - 当前月份标签。
* `.range-calendar__nav-button` - 上一月/下一月导航控件。
* `.range-calendar__grid` - 主体日期网格。
* `.range-calendar__grid-header` - 星期标题行外层。
* `.range-calendar__grid-body` - 日期行外层。
* `.range-calendar__header-cell` - 星期标题单元格。
* `.range-calendar__cell` - 可交互日期单元格外层。
* `.range-calendar__cell-button` - 单元格内的可交互日期按钮。
* `.range-calendar__cell-indicator` - 日期单元格内的圆点指示器。
* `.calendar-year-picker__trigger` - 年份选择器切换按钮。
* `.calendar-year-picker__trigger-heading` - 年份选择触发器内的标题文案。
* `.calendar-year-picker__trigger-indicator` - 年份选择触发器内的指示图标。
* `.calendar-year-picker__year-grid` - 可选年份的覆盖网格。
* `.calendar-year-picker__year-cell` - 单个年份选项。
### 交互状态
RangeCalendar 同时支持伪类与 React Aria 的 data 属性:
* **已选中**:`[data-selected="true"]`
* **范围起点**:`[data-selection-start="true"]`
* **范围终点**:`[data-selection-end="true"]`
* **范围内**:`[data-selection-in-range="true"]`
* **今天**:`[data-today="true"]`
* **不可用**:`[data-unavailable="true"]`
* **跨月**:`[data-outside-month="true"]`
* **悬停**:`:hover` 或 `[data-hovered="true"]`
* **按下**:`:active` 或 `[data-pressed="true"]`
* **焦点可见**:`:focus-visible` 或 `[data-focus-visible="true"]`
* **禁用**:`:disabled` 或 `[data-disabled="true"]`
## API 参考
### RangeCalendar
RangeCalendar 继承 React Aria [RangeCalendar](https://react-spectrum.adobe.com/react-aria/RangeCalendar.html) 的全部 props。
| Prop | 类型 | 默认值 | 描述 |
| --------------------------- | ---------------------------------------------------------------- | ------------------ | ---------------------------------------------------------------------- |
| `value` | `RangeValue \| null` | - | 受控的选中范围。 |
| `defaultValue` | `RangeValue \| null` | - | 初始选中范围(非受控)。 |
| `onChange` | `(value: RangeValue) => void` | - | 选中变化时调用。 |
| `focusedValue` | `DateValue` | - | 受控的焦点日期。 |
| `onFocusChange` | `(value: DateValue) => void` | - | 焦点移动到其它日期时调用。 |
| `minValue` | `DateValue` | 历法感知的 `1900-01-01` | 可选的最早日期。 |
| `maxValue` | `DateValue` | 历法感知的 `2099-12-31` | 可选的最晚日期。 |
| `weeksInMonth` | `number` | - | 一个月的周数。该值会覆盖区域设置的默认值。 |
| `isDateUnavailable` | `(date: DateValue, anchorDate: CalendarDate \| null) => boolean` | - | 将日期标记为不可用。`anchorDate` 为当前范围选择中的首个日期。 |
| `firstDayOfWeek` | `'sun' \| 'mon' \| 'tue' \| 'wed' \| 'thu' \| 'fri' \| 'sat'` | - | 覆盖区域设置的一周起始日。 |
| `pageBehavior` | `'visible' \| 'single'` | `'visible'` | 翻页按可见范围或单步前进。 |
| `selectionAlignment` | `'start' \| 'center' \| 'end'` | `'center'` | 初始渲染时按选中项对齐可见范围。 |
| `allowsNonContiguousRanges` | `boolean` | `false` | 允许范围跨越不可用日期。 |
| `isDisabled` | `boolean` | `false` | 禁用交互与选择。 |
| `isReadOnly` | `boolean` | `false` | 内容只读,不可更改选中。 |
| `isInvalid` | `boolean` | `false` | 标记为无效以配合校验样式。 |
| `visibleDuration` | `{months?: number; weeks?: number; days?: number}` | `{months: 1}` | 可见时间范围。使用 `{ months: n }` 为月视图,`{ weeks: n }` 为周视图,`{ days: n }` 为日视图。 |
| `defaultYearPickerOpen` | `boolean` | `false` | 内置年份选择器的初始展开状态。 |
| `isYearPickerOpen` | `boolean` | - | 受控的年份选择器展开状态。 |
| `onYearPickerOpenChange` | `(isOpen: boolean) => void` | - | 年份选择器展开状态变化时调用。 |
### 组合部件
| 组件 | 描述 |
| ------------------------------------------ | --------------------------------------------------- |
| `RangeCalendar.Header` | 导航与标题的头部容器。 |
| `RangeCalendar.Heading` | 可见范围的格式化标题。支持 `offset`(多月份布局)与 `format`(月/年/日格式选项)。 |
| `RangeCalendar.NavButton` | 上一页/下一页导航(`slot="previous"` 或 `slot="next"`)。 |
| `RangeCalendar.Grid` | 单个月的日期网格(多月份布局支持 `offset`)。 |
| `RangeCalendar.GridHeader` | 星期标题容器。 |
| `RangeCalendar.GridBody` | 日期单元格主体容器。 |
| `RangeCalendar.HeaderCell` | 星期标签单元格。 |
| `RangeCalendar.Cell` | 单个日期单元格。 |
| `RangeCalendar.CellIndicator` | 用于自定义元数据的可选指示元素。 |
| `RangeCalendar.YearPickerTrigger` | 切换年份选择模式的触发器。 |
| `RangeCalendar.YearPickerTriggerHeading` | 年份选择触发器内的本地化标题内容。 |
| `RangeCalendar.YearPickerTriggerIndicator` | 年份选择触发器内的切换图标。 |
| `RangeCalendar.YearPickerGrid` | 年份选择覆盖网格容器。 |
| `RangeCalendar.YearPickerGridBody` | 年份网格单元格的 body 渲染器。 |
| `RangeCalendar.YearPickerCell` | 单个年份选项单元格。 |
### 年份选择器子组件
年份选择器子组件继承 React Aria [`useCalendarHeading`](https://react-aria.adobe.com/useCalendar#usecalendarheading) 与 [`useCalendarYearPicker`](https://react-aria.adobe.com/useCalendar#usecalendaryearpicker) 的格式化属性。
| 组件 | 属性 | 类型 | 默认值 | 描述 |
| ---------------------------------------- | -------------- | ---------------------- | ------------------- | ---------------------------------------------------------- |
| `RangeCalendar.YearPickerTriggerHeading` | `format` | `DateFormatterOptions` | - | 自定义月/年标题(如 `{month: 'short'}`)。 |
| `RangeCalendar.YearPickerTriggerHeading` | `offset` | `{months?: number}` | - | 相对聚焦日期偏移标题(多月布局)。 |
| `RangeCalendar.YearPickerGrid` | `format` | `DateFormatterOptions` | `{year: 'numeric'}` | 自定义年份单元格标签(纪元、历法系统等)。 |
| `RangeCalendar.YearPickerGrid` | `visibleYears` | `number` | min–max 跨度或 `20` | 滑动窗口中显示的年份数量。当同时设置 `minValue` 与 `maxValue` 时,默认为二者之间的完整范围。 |
### RangeCalendar.Cell Render
当 `RangeCalendar.Cell` 的 `children` 为函数时,可使用 React Aria 的渲染参数:
| Prop | 类型 | 描述 |
| ------------------ | --------- | ------------ |
| `formattedDate` | `string` | 单元格日期的本地化文案。 |
| `isSelected` | `boolean` | 该日期是否已选中。 |
| `isSelectionStart` | `boolean` | 是否为选中范围的起点。 |
| `isSelectionEnd` | `boolean` | 是否为选中范围的终点。 |
| `isUnavailable` | `boolean` | 该日期是否不可用。 |
| `isDisabled` | `boolean` | 单元格是否禁用。 |
| `isOutsideMonth` | `boolean` | 是否属于相邻月份。 |
支持的历法系统及其标识符完整列表见:
* [React Aria Calendar Implementations](https://react-aria.adobe.com/internationalized/date/Calendar#implementations)
* [React Aria International Calendars](https://react-aria.adobe.com/Calendar#international-calendars)
### Related packages
* [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/) — 各日期组件共用的日期类型(`CalendarDate`、`CalendarDateTime`、`ZonedDateTime`)与工具函数
* [`I18nProvider`](https://react-aria.adobe.com/I18nProvider) — 为子树覆盖语言环境
* [`useLocale`](https://react-aria.adobe.com/useLocale) — 读取当前语言环境与书写方向
## 相关组件
## Related Components
* **Calendar**: Interactive month grid for selecting dates
* **DateField**: Date input field with labels, descriptions, and validation
* **DatePicker**: Composable date picker with date field trigger and calendar popover
# TimeField 时间字段
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/time-field
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(date-and-time)/time-field.mdx
> 基于 React Aria TimeField 的时间输入字段,包含标签、说明与校验。
## 用法
```tsx
import { TimeField } from '@heroui/react';
```
```tsx
"use client";
import {Label, TimeField} from "@heroui/react";
export function Basic() {
return (
时间
{(segment) => }
);
}
```
## 组件结构
```tsx
import {TimeField, Label, Description, FieldError} from '@heroui/react';
export default () => (
{(segment) => }
)
```
> **TimeField** 将标签、时间输入、说明与错误信息组合为单个无障碍组件。
## 示例
### 带图标
添加前缀或后缀图标以增强时间字段。
```tsx
"use client";
import {Clock} from "@gravity-ui/icons";
import {Label, TimeField} from "@heroui/react";
export function WithPrefixIcon() {
return (
时间
{(segment) => }
);
}
```
```tsx
"use client";
import {Clock} from "@gravity-ui/icons";
import {Label, TimeField} from "@heroui/react";
export function WithSuffixIcon() {
return (
时间
{(segment) => }
);
}
```
```tsx
"use client";
import {ChevronDown, Clock} from "@gravity-ui/icons";
import {Description, Label, TimeField} from "@heroui/react";
export function WithPrefixAndSuffix() {
return (
时间
{(segment) => }
输入时间
);
}
```
### 表面样式
在 [Surface](/docs/components/surface) 内使用时,请在 `TimeField.Group` 上使用 `variant="secondary"`,以应用适合表面背景的低强调变体。
```tsx
"use client";
import {Clock} from "@gravity-ui/icons";
import {Description, Label, Surface, TimeField} from "@heroui/react";
export function OnSurface() {
return (
时间
{(segment) => }
输入时间
预约时间
{(segment) => }
输入预约时间
);
}
```
### 带描述
```tsx
"use client";
import {Description, Label, TimeField} from "@heroui/react";
export function WithDescription() {
return (
开始时间
{(segment) => }
输入开始时间
结束时间
{(segment) => }
输入结束时间
);
}
```
### 必填字段
```tsx
"use client";
import {Description, Label, TimeField} from "@heroui/react";
export function Required() {
return (
时间
{(segment) => }
预约时间
{(segment) => }
必填项
);
}
```
### 禁用
```tsx
"use client";
import {Description, Label, TimeField} from "@heroui/react";
import {Time, getLocalTimeZone, now} from "@internationalized/date";
export function Disabled() {
const currentTime = now(getLocalTimeZone());
const timeValue = new Time(currentTime.hour, currentTime.minute, currentTime.second);
return (
时间
{(segment) => }
此时间字段已禁用
时间
{(segment) => }
此时间字段已禁用
);
}
```
### 宽度充满
```tsx
"use client";
import {ChevronDown, Clock} from "@gravity-ui/icons";
import {Label, TimeField} from "@heroui/react";
export function FullWidth() {
return (
时间
{(segment) => }
时间
{(segment) => }
);
}
```
### 表单校验
将 `isInvalid` 与 `FieldError` 配合使用,以展示校验消息。
```tsx
"use client";
import {FieldError, Label, TimeField} from "@heroui/react";
export function Invalid() {
return (
时间
{(segment) => }
请输入有效时间
时间
{(segment) => }
时间须在工作时间内
);
}
```
### 受控组件
控制 value 以与其他组件或状态管理同步。
```tsx
"use client";
import type {TimeValue} from "@heroui/react";
import {Button, Description, Label, TimeField} from "@heroui/react";
import {Time, getLocalTimeZone, now} from "@internationalized/date";
import {useState} from "react";
export function Controlled() {
const [value, setValue] = useState(null);
return (
时间
{(segment) => }
当前值:{value ? value.toString() : "(空)"}
{
const currentTime = now(getLocalTimeZone());
setValue(new Time(currentTime.hour, currentTime.minute, currentTime.second));
}}
>
设为当前时间
setValue(null)}>
清空
);
}
```
### 表单示例
包含校验与提交处理的完整表单示例。
```tsx
"use client";
import type {Time} from "@internationalized/date";
import {Clock} from "@gravity-ui/icons";
import {Button, Description, FieldError, Form, Label, TimeField} from "@heroui/react";
import {parseTime} from "@internationalized/date";
import {useState} from "react";
export function FormExample() {
const [value, setValue] = useState(null);
const [isSubmitting, setIsSubmitting] = useState(false);
const minTime = parseTime("09:00");
const maxTime = parseTime("17:00");
const isInvalid = value !== null && (value.compare(minTime) < 0 || value.compare(maxTime) > 0);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!value || isInvalid) {
return;
}
setIsSubmitting(true);
// Simulate API call
setTimeout(() => {
console.log("Time submitted:", {time: value});
setValue(null);
setIsSubmitting(false);
}, 1500);
};
return (
预约时间
{(segment) => }
{isInvalid ? (
时间须在上午 9:00 至下午 5:00 之间
) : (
输入上午 9:00 至下午 5:00 之间的时间
)}
{isSubmitting ? "提交中…" : "提交"}
);
}
```
### 带校验
TimeField 支持通过 `minValue`、`maxValue` 及自定义校验逻辑进行验证。
```tsx
"use client";
import type {Time} from "@internationalized/date";
import {Description, FieldError, Label, TimeField} from "@heroui/react";
import {parseTime} from "@internationalized/date";
import {useState} from "react";
export function WithValidation() {
const [value, setValue] = useState(null);
const minTime = parseTime("09:00");
const maxTime = parseTime("17:00");
const isInvalid = value !== null && (value.compare(minTime) < 0 || value.compare(maxTime) > 0);
return (
时间
{(segment) => }
{isInvalid ? (
时间须在上午 9:00 至下午 5:00 之间
) : (
输入上午 9:00 至下午 5:00 之间的时间
)}
);
}
```
### 渲染函数
```tsx
"use client";
import {Label, TimeField} from "@heroui/react";
export function RenderFunction() {
return (
}
>
时间
{(segment) => }
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
"use client";
import {Description, Label, TimeField} from "@heroui/react";
export function CustomStyles() {
return (
提醒时间
每日签到通知。
{(segment) => }
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.time-field {
@apply flex flex-col gap-1;
&[data-invalid="true"],
&[aria-invalid="true"] {
[data-slot="description"] {
@apply hidden;
}
}
[data-slot="label"] {
@apply w-fit;
}
[data-slot="description"] {
@apply px-1;
}
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
* `.time-field` – 轻量样式的根容器(`flex flex-col gap-1`)
> **说明:** 子组件([Label](/docs/components/label)、[Description](/docs/components/description)、[FieldError](/docs/components/field-error))拥有各自的 CSS 类与样式。自定义方式请参阅对应文档。`TimeField.Group` 的样式见下文 API 参考。
### 交互状态
TimeField 会根据状态自动设置以下 data 属性:
* **无效**:`[data-invalid="true"]` 或 `[aria-invalid="true"]` – 无效时自动隐藏 description 插槽
* **必填**:`[data-required="true"]` – 当 `isRequired` 为 true 时添加
* **禁用**:`[data-disabled="true"]` – 当 `isDisabled` 为 true 时添加
* **焦点在内**:`[data-focus-within="true"]` – 任一子输入聚焦时添加
## API 参考
### TimeField
TimeField 继承 React Aria [TimeField](https://react-aria.adobe.com/TimeField) 的全部 props。
#### Base Props
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------------------------------------------------------------------------ | ------- | ---------------------------------- |
| `children` | `React.ReactNode \| (values: TimeFieldRenderProps) => React.ReactNode` | - | 子组件(Label、TimeField.Group 等)或渲染函数。 |
| `className` | `string \| (values: TimeFieldRenderProps) => string` | - | 用于样式的 CSS 类,支持渲染 prop。 |
| `style` | `React.CSSProperties \| (values: TimeFieldRenderProps) => React.CSSProperties` | - | 内联样式,支持渲染 prop。 |
| `fullWidth` | `boolean` | `false` | 时间字段是否占满容器宽度。 |
| `id` | `string` | - | 元素的唯一 id。 |
| `render` | `DOMRenderFunction` | - | 使用自定义渲染函数覆盖默认 DOM 元素。 |
#### Value Props
| Prop | 类型 | 默认值 | 描述 |
| ------------------ | ------------------------------------ | --- | ----------------------------------------------------------------------------------------------- |
| `value` | `TimeValue \| null` | - | 当前值(受控)。类型见 [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/)。 |
| `defaultValue` | `TimeValue \| null` | - | 默认值(非受控)。类型见 [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/)。 |
| `onChange` | `(value: TimeValue \| null) => void` | - | 值变化时触发的事件处理函数。 |
| `placeholderValue` | `TimeValue \| null` | - | 影响占位符格式的占位时间;默认随小时制为 12:00 AM 或 00:00。 |
#### Validation Props
| Prop | 类型 | 默认值 | 描述 |
| -------------------- | -------------------------------------------------------------------- | ---------- | ------------------------------------------------------------------------------------------------ |
| `isRequired` | `boolean` | `false` | 是否在提交表单前要求用户输入。 |
| `isInvalid` | `boolean` | - | 值是否无效。 |
| `minValue` | `TimeValue \| null` | - | 用户可选择最早时间。类型见 [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/)。 |
| `maxValue` | `TimeValue \| null` | - | 用户可选择最晚时间。类型见 [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/)。 |
| `validate` | `(value: TimeValue) => ValidationError \| true \| null \| undefined` | - | 自定义校验函数。 |
| `validationBehavior` | `'native' \| 'aria'` | `'native'` | 使用原生 HTML 表单校验还是 ARIA 属性。 |
#### Format Props
| Prop | 类型 | 默认值 | 描述 |
| ------------------------- | -------------------------------- | ---------- | ---------------------------- |
| `granularity` | `'hour' \| 'minute' \| 'second'` | `'minute'` | 时间选择器显示的最小单位。 |
| `hourCycle` | `12 \| 24` | - | 以 12 或 24 小时制显示时间;默认由语言环境决定。 |
| `hideTimeZone` | `boolean` | `false` | 是否隐藏时区缩写。 |
| `shouldForceLeadingZeros` | `boolean` | - | 是否始终为小时字段显示前导零;默认由语言环境决定。 |
#### State Props
| Prop | 类型 | 默认值 | 描述 |
| ------------ | --------- | --- | ----------- |
| `isDisabled` | `boolean` | - | 是否禁用输入。 |
| `isReadOnly` | `boolean` | - | 是否可选中但不可修改。 |
#### Form Props
| Prop | 类型 | 默认值 | 描述 |
| ----------- | --------- | --- | ----------------------------------------- |
| `name` | `string` | - | 输入元素的 name,用于 HTML 表单提交;以 ISO 8601 字符串提交。 |
| `autoFocus` | `boolean` | - | 是否在渲染后自动聚焦该元素。 |
#### Accessibility Props
| Prop | 类型 | 默认值 | 描述 |
| ------------------ | -------- | --- | ------------- |
| `aria-label` | `string` | - | 无可见标签时的无障碍标签。 |
| `aria-labelledby` | `string` | - | 标注该字段的元素 id。 |
| `aria-describedby` | `string` | - | 描述该字段的元素 id。 |
| `aria-details` | `string` | - | 包含额外详情的元素 id。 |
### 组合组件
TimeField 与以下独立组件配合使用,请分别导入并直接使用:
* **Label** – 来自 `@heroui/react` 的字段标签
* **TimeField.Group** – 时间输入分组(详见下文)
* **TimeField.Input** – 来自 `@heroui/react` 的分段位编辑输入
* **TimeField.Segment** – 单个时间段位(时、分、秒等)
* **TimeField.Prefix** / **TimeField.Suffix** – 输入组的前缀与后缀插槽
* **Description** – 来自 `@heroui/react` 的辅助说明
* **FieldError** – 来自 `@heroui/react` 的校验错误信息
这些组件各自有独立的 props API。在 TimeField 中直接组合使用:
```tsx
import {parseTime} from '@internationalized/date';
import {TimeField, Label, Description, FieldError} from '@heroui/react';
Appointment Time
{(segment) => }
Select a time between 9:00 AM and 5:00 PM.
Please select a valid time.
```
### TimeValue 类型
TimeField 使用 [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/) 中的类型:
* `Time` – 仅时间(时、分、秒)
* `CalendarDateTime` – 含日期与时间、不含时区(TimeField 仅展示时间部分)
* `ZonedDateTime` – 含日期、时间与时区(TimeField 仅展示时间部分)
示例:
```tsx
import {parseTime, Time, getLocalTimeZone, now} from '@internationalized/date';
// Parse from string
const time = parseTime('14:30');
// Create from current time
const currentTime = now(getLocalTimeZone());
const timeValue = new Time(currentTime.hour, currentTime.minute, currentTime.second);
// Use in TimeField
{/* ... */}
```
> **说明:** TimeField 使用 [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/) 进行时间处理、解析与类型定义。更多类型与函数见 [Internationalized Date 文档](https://react-aria.adobe.com/internationalized/date/)。
### TimeFieldRenderProps
对 `className`、`style` 或 `children` 使用渲染 prop 时,可使用以下值:
| Prop | 类型 | 描述 |
| ---------------- | --------- | ------------- |
| `isDisabled` | `boolean` | 字段是否禁用。 |
| `isInvalid` | `boolean` | 字段当前是否无效。 |
| `isReadOnly` | `boolean` | 字段是否只读。 |
| `isRequired` | `boolean` | 字段是否必填。 |
| `isFocused` | `boolean` | 字段是否聚焦。 |
| `isFocusWithin` | `boolean` | 是否有子元素聚焦。 |
| `isFocusVisible` | `boolean` | 焦点是否可见(键盘导航)。 |
### TimeField.Group
TimeField.Group 继承 React Aria `Group` 的全部 props,并额外支持:
| Prop | 类型 | 默认值 | 描述 |
| ----------- | -------------------------- | ----------- | ---------------------------------------------------------- |
| `className` | `string` | - | 与组件样式合并的 Tailwind CSS 类。 |
| `variant` | `"primary" \| "secondary"` | `"primary"` | 视觉变体。`primary` 为默认带阴影样式;`secondary` 为低强调、无阴影,适合用于 Surface。 |
### TimeField.Input
TimeField.Input 继承 React Aria `DateInput` 的全部 props,并额外支持:
| Prop | 类型 | 默认值 | 描述 |
| ----------- | -------------------------- | ----------- | ------------------------------------------------------------- |
| `className` | `string` | - | 与组件样式合并的 Tailwind CSS 类。 |
| `variant` | `"primary" \| "secondary"` | `"primary"` | 输入的视觉变体。`primary` 为默认带阴影样式;`secondary` 为低强调、无阴影,适合用于 Surface。 |
`TimeField.Input` 接受渲染函数作为子节点,函数接收日期段位;每个段位表示时间的一部分(时、分、秒等)。
### TimeField.Segment
TimeField.Segment 继承 React Aria `DateSegment` 的全部 props:
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------- | --- | ------------------------------------------ |
| `segment` | `DateSegment` | - | 来自 TimeField.Input 渲染函数的 `DateSegment` 对象。 |
| `className` | `string` | - | 与组件样式合并的 Tailwind CSS 类。 |
### TimeField.Prefix
TimeField.Prefix 接受标准 HTML `div` 属性:
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | ------------------------ |
| `className` | `string` | - | 与组件样式合并的 Tailwind CSS 类。 |
| `children` | `ReactNode` | - | 前缀插槽中要显示的内容。 |
### TimeField.Suffix
TimeField.Suffix 接受标准 HTML `div` 属性:
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | ------------------------ |
| `className` | `string` | - | 与组件样式合并的 Tailwind CSS 类。 |
| `children` | `ReactNode` | - | 后缀插槽中要显示的内容。 |
## TimeField.Group 样式
### 全局 CSS
基础类作用于所有实例,可通过 `@layer components` 一次性覆盖。
```css
@layer components {
.date-input-group {
@apply inline-flex h-9 items-center overflow-hidden rounded-field border bg-field text-sm text-field-foreground shadow-field outline-none;
&:hover,
&[data-hovered="true"] {
@apply bg-field-hover;
}
&[data-focus-within="true"],
&:focus-within {
@apply status-focused-field;
}
&[data-invalid="true"] {
@apply status-invalid-field;
}
&[data-disabled="true"],
&[aria-disabled="true"] {
@apply status-disabled;
}
}
.date-input-group__input {
@apply flex flex-1 items-center gap-px rounded-none border-0 bg-transparent px-3 py-2 shadow-none outline-none;
}
.date-input-group__segment {
@apply inline-block rounded-md px-0.5 text-end tabular-nums outline-none;
&:focus,
&[data-focused="true"] {
@apply bg-accent-soft text-accent-soft-foreground;
}
}
.date-input-group__prefix,
.date-input-group__suffix {
@apply pointer-events-none shrink-0 text-field-placeholder flex items-center;
}
}
```
### TimeField.Group CSS 类
* `.date-input-group` – 根容器样式
* `.date-input-group__input` – 输入包裹层样式
* `.date-input-group__segment` – 单个时间段位样式
* `.date-input-group__prefix` – 前缀元素样式
* `.date-input-group__suffix` – 后缀元素样式
### TimeField.Group 交互状态
* **悬停**:`:hover` 或 `[data-hovered="true"]`
* **焦点在内**:`[data-focus-within="true"]` 或 `:focus-within`
* **无效**:`[data-invalid="true"]`(同时与 `aria-invalid` 同步)
* **禁用**:`[data-disabled="true"]` 或 `[aria-disabled="true"]`
* **段位聚焦**:段位上的 `:focus` 或 `[data-focused="true"]`
* **段位占位符**:段位上的 `[data-placeholder="true"]`
## 相关组件
## Related Components
* **Label**: Accessible label for form controls
* **FieldError**: Inline validation messages for form fields
* **Description**: Helper text for form fields
# Avatar 头像
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/avatar
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(media)/avatar.mdx
> 显示用户头像,支持自定义 fallback 内容
## 用法
```tsx
import { Avatar } from '@heroui/react';
```
```tsx
import {Avatar} from "@heroui/react";
export function Basic() {
return (
);
}
```
## 组件结构
```tsx
import { Avatar } from '@heroui/react';
export default () => (
)
```
## 示例
### 尺寸
```tsx
import {Avatar} from "@heroui/react";
export function Sizes() {
return (
);
}
```
### 颜色
```tsx
import {Avatar} from "@heroui/react";
export function Colors() {
return (
);
}
```
### 变体
```tsx
import {Person} from "@gravity-ui/icons";
import {Avatar, Separator} from "@heroui/react";
const colors = ["accent", "default", "success", "warning", "danger"] as const;
const COLOR_LABELS: Record<(typeof colors)[number], string> = {
accent: "强调",
danger: "危险",
default: "默认",
success: "成功",
warning: "警告",
};
const variants = [
{content: "AG", label: "字母", type: "letter"},
{content: "AG", label: "柔和字母", type: "letter-soft"},
{content: , label: "图标", type: "icon"},
{content: , label: "柔和图标", type: "icon-soft"},
{
content: [
"https://img.heroui.chat/image/avatar?w=400&h=400&u=3",
"https://img.heroui.chat/image/avatar?w=400&h=400&u=4",
"https://img.heroui.chat/image/avatar?w=400&h=400&u=5",
"https://img.heroui.chat/image/avatar?w=400&h=400&u=8",
"https://img.heroui.chat/image/avatar?w=400&h=400&u=16",
],
label: "图片",
type: "img",
},
] as const;
export function Variants() {
return (
{/* 颜色列标题 */}
{colors.map((color) => (
{COLOR_LABELS[color]}
))}
{/* 变体行 */}
{variants.map((variant) => (
{variant.label}
{colors.map((color, colorIndex) => (
{variant.type === "img" ? (
<>
{COLOR_LABELS[color].charAt(0)}
>
) : (
{variant.content}
)}
))}
))}
);
}
```
### 回退内容
```tsx
import {Person} from "@gravity-ui/icons";
import {Avatar} from "@heroui/react";
export function Fallback() {
return (
{/* 文字回退 */}
JD
{/* 图标回退 */}
{/* 延迟显示回退 */}
NA
{/* 自定义样式回退 */}
GB
);
}
```
### 头像组
```tsx
import {Avatar} from "@heroui/react";
const users = [
{
id: 1,
image: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/blue.jpg",
name: "张明",
},
{
id: 2,
image: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/green.jpg",
name: "李华",
},
{
id: 3,
image: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/purple.jpg",
name: "王芳",
},
{
id: 4,
image: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/orange.jpg",
name: "刘洋",
},
{
id: 5,
image: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/red.jpg",
name: "陈静",
},
];
function initialsFromName(name: string) {
const parts = name.split(/\s+/).filter(Boolean);
if (parts.length >= 2) {
return parts.map((n) => n[0]).join("");
}
return name.slice(0, 2);
}
export function Group() {
return (
{/* 基础头像组 */}
{users.slice(0, 4).map((user) => (
{initialsFromName(user.name)}
))}
{/* 带头像数量提示的组合 */}
{users.slice(0, 3).map((user) => (
{initialsFromName(user.name)}
))}
+{users.length - 3}
);
}
```
## 自定义样式
### 自定义图片组件
在 `Avatar.Image` 上使用 `asChild`,即可与自定义图片组件组合。以下示例使用 Next.js `Image` 以实现优化加载。请将 `src` 传给 `Avatar.Image`,以便跟踪加载状态,并在图片就绪前显示回退内容。
```tsx
import {Avatar} from "@heroui/react";
import Image from "next/image";
const SRC = "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/blue.jpg";
export function CustomImageComponent() {
return (
JD
);
}
```
### Tailwind CSS
```tsx
import {Avatar} from "@heroui/react";
export function CustomStyles() {
return (
张三
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 Avatar 组件类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.avatar {
@apply size-16 border-2 border-accent;
}
.avatar__fallback {
@apply bg-gradient-to-br from-purple-500 to-pink-500;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Avatar 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/avatar.css)):
#### 基础类 \[!toc]
* `.avatar` - 基础容器,默认尺寸(size-10)
* `.avatar__image` - 图片元素,aspect-square 尺寸
* `.avatar__fallback` - 居中内容的 fallback 容器
#### 尺寸修饰符 \[!toc]
* `.avatar--sm` - 小头像(size-8)
* `.avatar--md` - 中头像(默认,无额外样式)
* `.avatar--lg` - 大头像(size-12)
#### 变体修饰符 \[!toc]
* `.avatar--soft` - 浅色背景的 soft 变体
#### 颜色修饰符 \[!toc]
* `.avatar__fallback--default` - 默认文字颜色
* `.avatar__fallback--accent` - 强调色文字
* `.avatar__fallback--success` - 成功色文字
* `.avatar__fallback--warning` - 警告色文字
* `.avatar__fallback--danger` - 危险色文字
## API 参考
### Avatar
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------------------------------------------------------- | ----------- | ------------- |
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | 头像尺寸 |
| `color` | `'default' \| 'accent' \| 'success' \| 'warning' \| 'danger'` | `'default'` | Fallback 颜色主题 |
| `variant` | `'default' \| 'soft'` | `'default'` | 视觉样式变体 |
| `className` | `string` | - | 附加 CSS 类 |
### Avatar.Image
| Prop | 类型 | 默认值 | 描述 |
| ------------- | --------------------------------------------------- | ------- | ----------------------------------------- |
| `src` | `string` | - | 图片 URL |
| `srcSet` | `string` | - | 响应式图片的 `srcset` 属性 |
| `sizes` | `string` | - | 响应式图片的 `sizes` 属性 |
| `alt` | `string` | - | 图片替代文本 |
| `asChild` | `boolean` | `false` | 将属性合并到子元素上(例如 `next/image`),而不是渲染原生 `img` |
| `onLoad` | `(event: SyntheticEvent) => void` | - | 图片加载成功时的回调 |
| `onError` | `(event: SyntheticEvent) => void` | - | 图片加载失败时的回调 |
| `crossOrigin` | `'anonymous' \| 'use-credentials'` | - | 图片请求的 CORS 设置 |
| `loading` | `'eager' \| 'lazy'` | - | 原生懒加载属性 |
| `className` | `string` | - | 附加 CSS 类 |
### Avatar.Fallback
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------------------------------------------------------- | --- | ---------------------- |
| `delayMs` | `number` | - | 显示 fallback 前的延迟(防止闪烁) |
| `color` | `'default' \| 'accent' \| 'success' \| 'warning' \| 'danger'` | - | 覆盖父级颜色 |
| `className` | `string` | - | 附加 CSS 类 |
## 相关组件
## Related Components
* **Separator**: Visual divider between content
* **Badge**: Small indicator positioned relative to another element
# Card 卡片
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/card
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(layout)/card.mdx
> 灵活容器组件,用于分组相关内容与操作
## 用法
```tsx
import { Card } from "@heroui/react";
```
```tsx
import {CircleDollar} from "@gravity-ui/icons";
import {Card, Link} from "@heroui/react";
export function Default() {
return (
成为 Acme 创作者!
前往 Acme 创作者中心立即注册,开始从粉丝与支持者处获得积分奖励。
创作者中心
);
}
```
## 组件结构
```tsx
import { Card } from "@heroui/react";
export default () => (
);
```
## 示例
### 变体
Card 提供语义变体,描述 prominence 级别而非具体视觉样式,允许主题以不同方式解读:
```tsx
import {Card} from "@heroui/react";
export function Variants() {
return (
透明
背景透明,视觉层级较低(transparent)
适合次要内容或嵌套在其它容器中的卡片
默认
标准外观(bg-surface)
大多数场景的默认卡片变体
次要
中等强调(bg-surface-secondary)
用于需要适度吸引注意力的内容
第三
更高强调(bg-surface-tertiary)
适合主要内容或需要突出的展示位
);
}
```
* **`transparent`** - 最低 prominence,透明背景(适合嵌套卡片)
* **`default`** - 大多数场景的标准卡片(surface-secondary)
* **`secondary`** - 中等 prominence 以吸引适度注意(surface-tertiary)
* **`tertiary`** - 更高 prominence 用于重要内容(surface-tertiary)
### 水平布局
```tsx
import {Button, Card, CloseButton} from "@heroui/react";
export function Horizontal() {
return (
成为 ACME 创作者!
这是一段占位说明文字,用于展示横向卡片布局、配图与右上角关闭按钮的排版效果。
仅剩 10 个名额
报名截止:10 月 10 日
立即申请
);
}
```
### 带头像
```tsx
import {Avatar, Card} from "@heroui/react";
export function WithAvatar() {
return (
Indie Hackers
148 位成员
IH
创建者:玛莎
AI Builders
362 位成员
B
创建者:约翰
);
}
```
### 带图片
```tsx
import {CircleDollar} from "@gravity-ui/icons";
import {Avatar, Button, Card, CloseButton, Link} from "@heroui/react";
export function WithImages() {
return (
{/* 第 1 行:大图商品卡 */}
成为 ACME 创作者!
这是一段占位说明文字,用于展示横向卡片布局、配图与右上角关闭按钮的排版效果。
仅剩 10 个名额
报名截止:10 月 10 日
立即申请
{/* 第 2 行 */}
{/* 左栏 */}
{/* 上方卡片 */}
支付
现已支持加密货币提现
在设置中添加钱包即可提现
前往设置
{/* 下方小卡 */}
{/* 左卡 */}
JK
Indie Hackers
148 位成员
JK
创建者:约翰
{/* 右卡 */}
AB
AI Builders
362 位成员
M
创建者:玛莎
{/* 右栏 */}
{/* 背景图 */}
{/* 标题区 */}
NEO
家用机器人
{/* 底部 */}
通知我
{/* 第 3 行 */}
{/* 左:大图卡 */}
立即购买
{/* 右:堆叠小卡 */}
{/* 1 */}
连接未来
今天 18:30
{/* 2 */}
牛油果黑客松
周三 16:30
{/* 3 */}
Sound Electro|超越艺术
周五 20:00
);
}
```
### 搭配表单
```tsx
"use client";
import {Button, Card, Form, Input, Label, Link, TextField} from "@heroui/react";
export function WithForm() {
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const data: Record = {};
// Convert FormData to plain object
formData.forEach((value, key) => {
data[key] = value.toString();
});
alert("表单提交成功!");
};
return (
登录
输入账号信息以访问您的账户
邮箱
密码
登录
忘记密码?
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Check, Star} from "@gravity-ui/icons";
import {Button, Card} from "@heroui/react";
const PRO_FEATURES = ["无限项目与协作者", "优先支持,24 小时响应", "高级分析与导出"] as const;
export function CustomStyles() {
return (
推荐
升级到 Pro
解锁面向成长型产品的团队工作流与洞察。
{PRO_FEATURES.map((feature) => (
{feature}
))}
立即升级
对比方案
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 Card 组件类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.card--secondary {
@apply bg-gradient-to-br from-blue-50 to-purple-50;
}
.card__title {
@apply text-xl font-bold;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Card 使用 [BEM](https://getbem.com/) 命名以实现可预测的样式([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/card.css)):
#### 基础类 \[!toc]
* `.card` - 带 padding 与边框的基础容器
* `.card__header` - 头部区域容器
* `.card__title` - 基础字号与字重的标题
* `.card__description` - 弱化描述文本
* `.card__content` - 灵活内容容器
* `.card__footer` - 行布局的页脚
#### 变体类 \[!toc]
* `.card--transparent` - 最低 prominence,透明背景(对应 `transparent` 变体)
* `.card--default` - 标准外观,surface-secondary(默认)
* `.card--secondary` - 中等 prominence,surface-tertiary(对应 `secondary` 变体)
* `.card--tertiary` - 更高 prominence,surface-tertiary(对应 `tertiary` 变体)
## API 参考
### Card
| Prop | 类型 | 默认值 | 描述 |
| ----------- | --------------------------------------------------------- | ----------- | --------------------- |
| `variant` | `"transparent" \| "default" \| "secondary" \| "tertiary"` | `"default"` | 表示 prominence 级别的语义变体 |
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `React.ReactNode` | - | 卡片内容 |
### Card.Header
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --- | -------- |
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `React.ReactNode` | - | 头部内容 |
### Card.Title
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --- | -------------- |
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `React.ReactNode` | - | 标题内容(渲染为 `h3`) |
### Card.Description
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --- | ------------- |
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `React.ReactNode` | - | 描述内容(渲染为 `p`) |
### Card.Content
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --- | -------- |
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `React.ReactNode` | - | 主要内容 |
### Card.Footer
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --- | -------- |
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `React.ReactNode` | - | 页脚内容 |
## 无障碍
```tsx
import { Card } from '@heroui/react';
import { cardVariants } from '@heroui/styles';
// Semantic markup
Article Title
// Interactive cards
Product Name
```
## 相关组件
## Related Components
* **Surface**: Base container surface
* **Avatar**: Display user profile images
* **Form**: Form validation and submission handling
# Separator 分隔符
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/separator
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(layout)/separator.mdx
> 在内容区块之间进行视觉分隔。
## 用法
```tsx
import { Separator } from '@heroui/react';
```
```tsx
import {Separator} from "@heroui/react";
export function Basic() {
return (
HeroUI v3 组件
美观、快速、现代的 React UI 库。
);
}
```
## 示例
### 变体
```tsx
import {Separator} from "@heroui/react";
export function Variants() {
return (
);
}
```
### 与 Surface 组合
Separator 组件会根据不同的表面背景自动适配,以获得更好的可见性。
```tsx
import {Separator, Surface} from "@heroui/react";
export function WithSurface() {
return (
);
}
```
### 垂直方向
```tsx
import {Separator} from "@heroui/react";
export function Vertical() {
return (
);
}
```
### 带内容
```tsx
import {Separator} from "@heroui/react";
const items = [
{
iconUrl: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/docs/3dicons/bell-small.png",
subtitle: "接收账户活动更新",
title: "设置通知",
},
{
iconUrl: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/docs/3dicons/compass-small.png",
subtitle: "将浏览器连接到你的账户",
title: "设置浏览器扩展",
},
{
iconUrl:
"https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/docs/3dicons/mint-collective-small.png",
subtitle: "创建你的第一件收藏品",
title: "铸造收藏品",
},
];
export function WithContent() {
return (
{items.map((item, index) => (
{item.title}
{item.subtitle}
{index < items.length - 1 &&
}
))}
);
}
```
### 渲染函数
```tsx
"use client";
import {Separator} from "@heroui/react";
export function RenderFunction() {
return (
HeroUI v3 组件
美观、快速、现代的 React UI 库。
} />
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Separator} from "@heroui/react";
export function CustomStyles() {
return (
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.separator {
@apply bg-accent h-[2px];
}
.separator--vertical {
@apply bg-accent w-[2px];
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Separator 使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/separator.css)):
#### 基础类与方向类 \[!toc]
* `.separator` - 基础 Separator 样式,默认水平方向
* `.separator--horizontal` - 水平方向(全宽,高度 1px)
* `.separator--vertical` - 垂直方向(全高,宽度 1px)
#### 变体类 \[!toc]
* `.separator--default` - 默认变体,标准对比度
* `.separator--secondary` - 次要变体,中等对比度
* `.separator--tertiary` - 第三级变体,较弱对比度
## API 参考
### Separator
| Prop | 类型 | 默认值 | 描述 |
| ------------- | ----------------------------------------------------------------- | -------------- | ---------------------- |
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Separator 的方向 |
| `variant` | `'default' \| 'secondary' \| 'tertiary'` | `'default'` | Separator 的视觉变体 |
| `className` | `string` | - | 额外的 CSS 类名 |
| `render` | `DOMRenderFunction` | - | 通过自定义渲染函数覆盖默认的 DOM 元素。 |
## 相关组件
## Related Components
* **Card**: Content container with header, body, and footer
* **Chip**: Compact elements for tags and filters
* **Avatar**: Display user profile images
# Surface 表面
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/surface
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(layout)/surface.mdx
> 提供表面级样式与子组件上下文的容器组件。
## 用法
```tsx
import { Surface } from '@heroui/react';
```
```tsx
import {Surface} from "@heroui/react";
export function Basic() {
return (
表面内容
这是默认表面变体,使用 bg-surface 样式。
);
}
```
## 示例
### 变体
Surface 提供描述 prominence 层级的语义变体:
* **`default`** - 标准表面外观(bg-surface)
* **`secondary`** - 中等 prominence(bg-surface-secondary)
* **`tertiary`** - 较高 prominence(bg-surface-tertiary)
```tsx
import {Surface} from "@heroui/react";
export function Variants() {
return (
默认
表面内容
这是默认表面变体,使用 bg-surface 样式。
次要
表面内容
这是次要表面变体,使用 bg-surface-secondary 样式。
第三
表面内容
这是第三表面变体,使用 bg-surface-tertiary 样式。
透明
表面内容
这是透明表面变体,无背景,适用于遮罩层和自定义背景的卡片。
);
}
```
### 搭配表单
在 Surface 内使用表单组件时,请使用 `variant="secondary"` 以应用适合表面背景的低强调变体。
```tsx
"use client";
import {Input, Surface, TextArea} from "@heroui/react";
export function WithFormComponents() {
return (
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Surface} from "@heroui/react";
export function CustomStyles() {
return (
账单概览
在此查看发票和支付方式。
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.surface {
@apply rounded-2xl border border-border;
}
.surface--secondary {
@apply bg-gradient-to-br from-blue-50 to-purple-50;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Surface 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/surface.css)):
#### 基础类 \[!toc]
* `.surface` - Surface 根容器
#### 变体类 \[!toc]
* `.surface--default` - 默认 Surface 变体(bg-surface)
* `.surface--secondary` - Secondary Surface 变体(bg-surface-secondary)
* `.surface--tertiary` - Tertiary Surface 变体(bg-surface-tertiary)
## API 参考
### Surface
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ---------------------------------------------------------- | ----------- | -------------- |
| `variant` | ` "transparent" \| "default" \| "secondary" \| "tertiary"` | `"default"` | Surface 的视觉变体。 |
| `className` | `string` | - | 额外的 CSS 类。 |
| `children` | `ReactNode` | - | Surface 内容。 |
## Context API
### SurfaceContext
子组件可通过 Surface 上下文读取当前变体:
```tsx
import { useContext } from 'react';
import { SurfaceContext } from '@heroui/react';
function MyComponent() {
const { variant } = useContext(SurfaceContext);
// variant 为 "transparent" | "default" | "secondary" | "tertiary" | undefined
}
```
## 相关组件
## Related Components
* **CheckboxGroup**: Group of checkboxes with shared state
* **Fieldset**: Group related form controls with legends
* **InputOTP**: One-time password input
# Toolbar 工具栏
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/toolbar
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(layout)/toolbar.mdx
> 用于承载可交互控件的容器,并支持方向键导航。
## 用法
```tsx
import { Toolbar } from '@heroui/react';
```
```tsx
import {Bold, Copy, Italic, Scissors, Underline} from "@gravity-ui/icons";
import {
Button,
ButtonGroup,
Separator,
ToggleButton,
ToggleButtonGroup,
Toolbar,
} from "@heroui/react";
export function Basic() {
return (
);
}
```
## 示例
### 垂直方向
```tsx
import {ArrowUturnCcwLeft, ArrowUturnCwRight, Bold, Italic, Underline} from "@gravity-ui/icons";
import {
Button,
ButtonGroup,
Separator,
ToggleButton,
ToggleButtonGroup,
Toolbar,
} from "@heroui/react";
export function Vertical() {
return (
);
}
```
### 组合模式
```tsx
import {Bold, Copy, Italic, Scissors, Underline} from "@gravity-ui/icons";
import {
Button,
ButtonGroup,
Separator,
ToggleButton,
ToggleButtonGroup,
Toolbar,
} from "@heroui/react";
export function Attached() {
return (
);
}
```
### 与 ButtonGroup 组合
```tsx
import {
ArrowUturnCcwLeft,
ArrowUturnCwRight,
Bold,
Italic,
TextAlignCenter,
TextAlignLeft,
TextAlignRight,
Underline,
} from "@gravity-ui/icons";
import {
Button,
ButtonGroup,
Separator,
ToggleButton,
ToggleButtonGroup,
Toolbar,
} from "@heroui/react";
export function WithButtonGroup() {
return (
撤销
重做
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Bold, Italic, Underline} from "@gravity-ui/icons";
import {ToggleButton, ToggleButtonGroup, Toolbar} from "@heroui/react";
const toggleClass =
"rounded-lg data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground";
export function CustomStyles() {
return (
);
}
```
### 全局 CSS
若要自定义组件类,可使用 `@layer components` 指令。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.toolbar {
@apply gap-4 rounded-lg bg-surface p-3;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Toolbar 使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/toolbar.css)):
* `.toolbar` - 基础容器
* `.toolbar--horizontal` - 水平方向(默认)
* `.toolbar--vertical` - 垂直方向
* `.toolbar--attached` - Attached 变体:surface 背景与完全圆角
## API 参考
### Toolbar
继承 [React Aria Toolbar](https://react-spectrum.adobe.com/react-aria/Toolbar.html)。
| Prop | 类型 | 默认值 | 描述 |
| ----------------- | -------------------------------------------------------------------- | -------------- | ----------------------------- |
| `isAttached` | `boolean` | `false` | Toolbar 是否使用带完全圆角的 surface 背景 |
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Toolbar 的方向 |
| `aria-label` | `string` | - | Toolbar 的无障碍标签 |
| `aria-labelledby` | `string` | - | 用于标注该 Toolbar 的元素 id |
| `children` | `React.ReactNode \| (values: ToolbarRenderProps) => React.ReactNode` | - | 内容或渲染 prop |
| `className` | `string \| (values: ToolbarRenderProps) => string` | - | 额外的 CSS 类名 |
### ToolbarRenderProps
使用渲染 prop 模式时,会提供以下值:
| Prop | 类型 | 描述 |
| ------------- | ---------------------------- | -------------- |
| `orientation` | `"horizontal" \| "vertical"` | 当前 Toolbar 的方向 |
## 相关组件
## Related Components
* **ButtonGroup**: Group related buttons together
* **ToggleButtonGroup**: Group multiple toggle buttons into a unified control
* **Separator**: Visual divider between content
# CheckboxGroup 复选框组
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/checkbox-group
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(forms)/checkbox-group.mdx
> 用于管理多个复选框选择的复选框组组件
## 用法
```tsx
import { CheckboxGroup, Checkbox, Label, Description } from '@heroui/react';
```
```tsx
import {Checkbox, CheckboxGroup, Description, Label} from "@heroui/react";
export function Basic() {
return (
选择你的兴趣
可多选
编程
热爱构建软件
设计
喜欢打造精美界面
写作
热衷于内容创作
);
}
```
## 组件结构
```tsx
import {CheckboxGroup, Checkbox, Label, Description, FieldError} from '@heroui/react';
export default () => (
{/* 可选 */}
Label {/* 纯文本 — 可点击标签 */}
{/* 可选 — 单个 Checkbox 的帮助文本 */}
{/* 可选 */}
);
```
## 示例
### 表面样式
在 [Surface](/docs/components/surface) 组件内使用时,请使用 `variant="secondary"` 以应用适合 Surface 背景的低强调变体。
```tsx
import {Checkbox, CheckboxGroup, Description, Label, Surface} from "@heroui/react";
export function OnSurface() {
return (
选择你的兴趣
可多选
编程
热爱构建软件
设计
喜欢打造精美界面
写作
热衷于内容创作
);
}
```
### 禁用
```tsx
import {Checkbox, CheckboxGroup, Description, Label} from "@heroui/react";
export function Disabled() {
return (
功能
功能选择暂时不可用
功能一
该功能即将推出
功能二
该功能即将推出
);
}
```
### 半选状态
```tsx
"use client";
import {Checkbox, CheckboxGroup} from "@heroui/react";
import {useState} from "react";
export function Indeterminate() {
const [selected, setSelected] = useState(["coding"]);
const allOptions = ["coding", "design", "writing"];
return (
0 && selected.length < allOptions.length}
isSelected={selected.length === allOptions.length}
name="select-all"
onChange={(isSelected: boolean) => {
setSelected(isSelected ? allOptions : []);
}}
>
全选
编程
设计
写作
);
}
```
### 受控组件
```tsx
"use client";
import {Checkbox, CheckboxGroup, Label} from "@heroui/react";
import {useState} from "react";
export function Controlled() {
const [selected, setSelected] = useState(["coding", "design"]);
return (
你的技能
编程
设计
写作
已选:{selected.join(", ") || "无"}
);
}
```
### 表单校验
```tsx
"use client";
import {Button, Checkbox, CheckboxGroup, FieldError, Form, Label} from "@heroui/react";
export function Validation() {
return (
{
e.preventDefault();
const formData = new FormData(e.currentTarget);
const values = formData.getAll("preferences");
alert(`已选偏好:${values.join(", ")}`);
}}
>
偏好设置
邮件通知
短信通知
推送通知
请至少选择一种通知方式。
提交
);
}
```
### 功能扩展示例
```tsx
import {Bell, Comment, Envelope} from "@gravity-ui/icons";
import {Checkbox, CheckboxGroup, Description, Label} from "@heroui/react";
import clsx from "clsx";
export function FeaturesAndAddOns() {
const addOns = [
{
description: "通过邮件接收更新",
icon: Envelope,
title: "邮件通知",
value: "email",
},
{
description: "即时短信通知",
icon: Comment,
title: "短信提醒",
value: "sms",
},
{
description: "浏览器与移动端推送提醒",
icon: Bell,
title: "推送通知",
value: "push",
},
];
return (
通知偏好
选择接收更新的方式
{addOns.map((addon) => (
{addon.title}
{addon.description}
))}
);
}
```
### 自定义指示器
```tsx
"use client";
import {Checkbox, CheckboxGroup, Description, Label} from "@heroui/react";
export function WithCustomIndicator() {
return (
功能
选择你需要的功能
{({isSelected}) =>
isSelected ? (
) : null
}
邮件通知
通过邮件接收更新
{({isSelected}) =>
isSelected ? (
) : null
}
邮件通讯
每周接收邮件简报
);
}
```
### 渲染函数
```tsx
"use client";
import {Checkbox, CheckboxGroup, Description, Label} from "@heroui/react";
export function RenderFunction() {
return (
}>
选择你的兴趣
可多选
编程
热爱构建软件
设计
喜欢打造精美界面
写作
热衷于内容创作
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Checkbox, CheckboxGroup, Description, Label} from "@heroui/react";
const controlClassName = "bg-success-soft before:bg-success";
const indicatorClassName =
"**:data-[slot=checkbox-default-indicator--checkmark]:text-success-foreground";
const channels = [
{label: "电子邮件", value: "email"},
{label: "短信", value: "sms"},
{label: "推送", value: "push"},
] as const;
export function CustomStyles() {
return (
通知渠道
选择我们通过何种方式向您发送账户更新。
{channels.map(({label, value}) => (
{label}
))}
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 CheckboxGroup 组件类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.checkbox-group {
@apply flex flex-col gap-2;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
CheckboxGroup 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/checkbox-group.css)):
#### 基础类 \[!toc]
* `.checkbox-group` - 复选框组根容器
## API 参考
### CheckboxGroup
继承自 [React Aria CheckboxGroup](https://react-spectrum.adobe.com/react-aria/CheckboxGroup.html)。
| Prop | 类型 | 默认值 | 描述 |
| -------------- | -------------------------------------------------------------------------------- | ------- | -------------------------- |
| `value` | `string[]` | - | 当前选中值(受控) |
| `defaultValue` | `string[]` | - | 默认选中值(非受控) |
| `onChange` | `(value: string[]) => void` | - | 选中值变化时的回调 |
| `isDisabled` | `boolean` | `false` | 是否禁用 |
| `isRequired` | `boolean` | `false` | 是否必填 |
| `isReadOnly` | `boolean` | `false` | 是否只读 |
| `isInvalid` | `boolean` | `false` | 是否处于无效状态 |
| `name` | `string` | - | 提交 HTML 表单时复选框组的名称 |
| `children` | `React.ReactNode \| (values: CheckboxGroupRenderProps) => React.ReactNode` | - | 内容或 render prop |
| `render` | `DOMRenderFunction` | - | 使用自定义 render 函数覆盖默认 DOM 元素 |
### Render Props
使用 render prop 模式时,提供以下值:
| Prop | 类型 | 描述 |
| ------------ | ---------- | -------- |
| `value` | `string[]` | 当前选中值 |
| `isDisabled` | `boolean` | 是否禁用 |
| `isReadOnly` | `boolean` | 是否只读 |
| `isInvalid` | `boolean` | 是否处于无效状态 |
| `isRequired` | `boolean` | 是否必填 |
## 相关组件
## Related Components
* **Checkbox**: Binary choice input control
* **Label**: Accessible label for form controls
* **Fieldset**: Group related form controls with legends
# Checkbox 复选框
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/checkbox
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(forms)/checkbox.mdx
> 复选框允许用户从列表中选择多项,或标记单个项目为选中状态
## 用法
```tsx
import { Checkbox } from '@heroui/react';
```
```tsx
import {Checkbox} from "@heroui/react";
export function Basic() {
return (
接受条款与条件
);
}
```
## 组件结构
```tsx
import { Checkbox, Description, FieldError } from '@heroui/react';
export default () => (
Label {/* 纯文本 — 可点击标签与无障碍名称 */}
{/* 可选 — 字段级帮助文本 */}
{/* 可选 — 校验消息 */}
);
```
## 示例
### 变体
Checkbox 组件支持两种视觉变体:
* **`primary`**(默认)- 标准样式与默认背景,适用于大多数场景
* **`secondary`** - 低强调变体,适用于 Surface 组件内
```tsx
import {Checkbox, Description} from "@heroui/react";
export function Variants() {
return (
);
}
```
### 全圆角
```tsx
import {Checkbox, Label} from "@heroui/react";
export function FullRounded() {
return (
);
}
```
### 禁用
```tsx
import {Checkbox, Description} from "@heroui/react";
export function Disabled() {
return (
高级功能
该功能即将推出
);
}
```
### 外部标签
```tsx
import {Checkbox, Label} from "@heroui/react";
export function ExternalLabel() {
return (
给我发送营销邮件
);
}
```
### 带描述
```tsx
import {Checkbox, Description} from "@heroui/react";
export function WithDescription() {
return (
邮件通知
当有人在评论中提及您时收到通知
);
}
```
### 默认选中
```tsx
import {Checkbox} from "@heroui/react";
export function DefaultSelected() {
return (
启用邮件通知
);
}
```
### 无效状态
```tsx
import {Checkbox, FieldError} from "@heroui/react";
export function Invalid() {
return (
我同意条款
您必须接受条款才能继续
);
}
```
### 受控组件
```tsx
"use client";
import {Checkbox} from "@heroui/react";
import {useState} from "react";
export function Controlled() {
const [isSelected, setIsSelected] = useState(true);
return (
邮件通知
状态:{isSelected ? "已勾选" : "未勾选"}
);
}
```
### 半选状态
```tsx
"use client";
import {Checkbox, Description} from "@heroui/react";
import {useState} from "react";
export function Indeterminate() {
const [isIndeterminate, setIsIndeterminate] = useState(true);
const [isSelected, setIsSelected] = useState(false);
return (
{
setIsSelected(selected);
setIsIndeterminate(false);
}}
>
全选
展示部分选中状态(短横线图标)
);
}
```
### 表单集成
```tsx
"use client";
import {Button, Checkbox} from "@heroui/react";
import React from "react";
export function Form() {
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
alert(
`表单提交数据:\n${Array.from(formData.entries())
.map(([key, value]) => `${key}: ${value}`)
.join("\n")}`,
);
};
return (
启用通知
订阅新闻通讯
接收营销更新
提交
);
}
```
### 渲染属性
```tsx
"use client";
import {Checkbox, Description} from "@heroui/react";
export function RenderProps() {
return (
{({isSelected}) => (
<>
{isSelected ? "已同意条款" : "接受条款"}
{isSelected ? "感谢您的确认" : "请先阅读并接受条款"}
>
)}
);
}
```
### 渲染函数
```tsx
"use client";
import {Checkbox} from "@heroui/react";
export function RenderFunction() {
return (
}>
接受条款与条件
);
}
```
### 自定义指示器
```tsx
"use client";
import {Checkbox} from "@heroui/react";
export function CustomIndicator() {
return (
{({isSelected}) =>
isSelected ? (
) : null
}
心形
{({isSelected}) =>
isSelected ? (
) : null
}
加号
{({isIndeterminate}) =>
isIndeterminate ? (
) : null
}
部分选中
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {Checkbox} from "@heroui/react";
export function CustomStyles() {
return (
自定义样式复选框
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 Checkbox 组件类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.checkbox {
@apply inline-flex gap-3 items-center;
}
.checkbox__control {
@apply size-5 border-2 border-gray-400 rounded data-[selected=true]:bg-blue-500 data-[selected=true]:border-blue-500;
/* Animated background indicator */
&::before {
@apply bg-accent pointer-events-none absolute inset-0 z-0 origin-center scale-50 rounded-md opacity-0 content-[''];
transition:
scale 200ms linear,
opacity 200ms linear,
background-color 200ms ease-out;
}
/* Show indicator when selected */
&[data-selected="true"]::before {
@apply scale-100 opacity-100;
}
}
.checkbox__indicator {
@apply text-white;
}
.checkbox__content {
@apply items-center gap-3;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Checkbox 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/checkbox.css)):
#### 基础类 \[!toc]
* `.checkbox` - 基础复选框容器(字段)
* `.checkbox__content` - 包裹控件与标签文本的可点击 label
* `.checkbox__control` - 复选框控件框
* `.checkbox__indicator` - 复选框勾选指示器
### 交互状态
复选框同时支持 CSS 伪类与 data 属性:
* **Selected**:`[data-selected="true"]` 或 `[aria-checked="true"]`(显示勾选与背景色变化)
* **Indeterminate**:`[data-indeterminate="true"]`(显示不确定状态的短横线)
* **Invalid**:`[data-invalid="true"]` 或 `[aria-invalid="true"]`(显示 danger 色错误状态)
* **Hover**:`Checkbox.Control`(按钮)上的 `:hover` 或 `[data-hovered="true"]`
* **Focus**:按钮上的 `:focus-visible` 或 `[data-focus-visible="true"]`(控件上显示焦点环)
* **Disabled**:字段上的 `[data-disabled="true"]`(降低透明度,包括帮助文本)
* **Pressed**:`:active` 或 `[data-pressed="true"]`
## API 参考
### Checkbox
继承自 [React Aria CheckboxField](https://react-spectrum.adobe.com/react-aria/Checkbox.html)。
| Prop | 类型 | 默认值 | 描述 |
| -------------------- | -------------------------------------------------------------------------------- | ----------- | --------------------------------------------------------- |
| `isSelected` | `boolean` | `false` | 是否选中 |
| `defaultSelected` | `boolean` | `false` | 默认是否选中(非受控) |
| `isIndeterminate` | `boolean` | `false` | 是否处于不确定状态 |
| `isDisabled` | `boolean` | `false` | 是否禁用 |
| `isInvalid` | `boolean` | `false` | 是否无效 |
| `isReadOnly` | `boolean` | `false` | 是否只读 |
| `isRequired` | `boolean` | `false` | 是否必须选中 |
| `validate` | `(value: boolean) => ValidationError \| true \| null \| undefined` | - | 自定义验证函数 |
| `validationBehavior` | `'native' \| 'aria'` | `'native'` | 使用原生 HTML 表单验证还是 ARIA |
| `variant` | `"primary" \| "secondary"` | `"primary"` | 视觉变体。`primary` 为默认带阴影样式;`secondary` 为低强调无阴影,适用于 Surface 内 |
| `name` | `string` | - | 提交 HTML 表单时 input 元素的名称 |
| `value` | `string` | - | 提交 HTML 表单时 input 元素的值 |
| `onChange` | `(isSelected: boolean) => void` | - | 值变化时的回调 |
| `children` | `React.ReactNode \| (values: CheckboxFieldRenderProps) => React.ReactNode` | - | 内容或字段 render prop |
| `render` | `DOMRenderFunction` | - | 使用自定义 render 函数覆盖默认 DOM 元素 |
### Checkbox.Content
可点击的 ``,包裹控件与标签文本。将 `Checkbox.Control` 与 `Label` 放在其中;`Description`/`FieldError` 作为 `Checkbox.Content` 的兄弟节点。无标签的复选框可省略 `Label`,并在 `Checkbox` 上传递 `aria-label`。
| Prop | 类型 | 默认值 | 描述 |
| ----------- | --------------------------------------------------------------------------- | --- | ---------------------------- |
| `children` | `React.ReactNode \| (values: CheckboxButtonRenderProps) => React.ReactNode` | - | 按钮内容(控件 + 标签)或按钮 render prop |
| `className` | `string \| (values: CheckboxButtonRenderProps) => string` | - | 应用于可点击 label 的类 |
### CheckboxFieldRenderProps
在根 `Checkbox` 上使用 render prop 时,提供以下字段级值:
| Prop | 类型 | 描述 |
| ----------------- | --------- | --------- |
| `isSelected` | `boolean` | 是否当前选中 |
| `isIndeterminate` | `boolean` | 是否处于不确定状态 |
| `isDisabled` | `boolean` | 是否禁用 |
| `isReadOnly` | `boolean` | 是否只读 |
| `isInvalid` | `boolean` | 是否无效 |
| `isRequired` | `boolean` | 是否必填 |
### CheckboxButtonRenderProps
`Checkbox.Control` 与 `Checkbox.Indicator` 使用按钮级 render props(`isHovered`、`isPressed`、`isFocusVisible` 等)。将函数作为 `Checkbox.Control` 子节点或传给 `Checkbox.Indicator` 以访问它们。
## 相关组件
## Related Components
* **Label**: Accessible label for form controls
* **CheckboxGroup**: Group of checkboxes with shared state
* **Description**: Helper text for form fields
# Description 描述
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/description
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(forms)/description.mdx
> 为表单字段及其他组件提供补充说明文本
## 用法
```tsx
import { Description } from '@heroui/react';
```
```tsx
import {Description, Input, Label} from "@heroui/react";
export function Basic() {
return (
邮箱
我们不会将你的邮箱分享给任何人。
);
}
```
## 示例
### 搭配表单字段
```tsx
Password
至少 8 个字符,且包含一个大写字母
```
### 与 TextField 配合
```tsx
import {TextField, Label, Input, Description} from '@heroui/react';
Email
We'll never share your email
```
使用 [TextField](./text-field) 组件时,无障碍属性会自动应用到标签与描述。
## 自定义样式
### Tailwind CSS
```tsx
import {Description, Input, Label} from "@heroui/react";
export function CustomStyles() {
return (
工作区 URL
仅支持小写字母和连字符。将用于 app.heroui.com/acme
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 Description 组件类。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.description {
@apply text-muted;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Description 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/description.css)):
#### 基础类 \[!toc]
* `.description` - 基础描述样式,使用 `muted` 文本颜色
## API 参考
### Description
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | -------- |
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `ReactNode` | - | 描述内容 |
## 无障碍
Description 组件通过以下方式增强无障碍性:
* 使用屏幕阅读器可识别的语义化 HTML
* 提供 `slot="description"` 属性以集成 React Aria
* 支持适当的文本对比度
## 相关组件
## Related Components
* **TextField**: Composition-friendly fields with labels and validation
* **Input**: Single-line text input built on React Aria
* **TextArea**: Multiline text input with focus management
# ErrorMessage 错误消息
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/error-message
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(forms)/error-message.mdx
> 用于展示错误的底层错误消息组件
## 用法
```tsx
import { ErrorMessage } from '@heroui/react';
```
```tsx
"use client";
import type {Key} from "@heroui/react";
import {Description, ErrorMessage, Label, Tag, TagGroup} from "@heroui/react";
import {useMemo, useState} from "react";
export function ErrorMessageBasic() {
const [selected, setSelected] = useState>(new Set());
const isInvalid = useMemo(() => Array.from(selected).length === 0, [selected]);
return (
setSelected(keys)}
>
必选分类
新闻
旅游
游戏
购物
请至少选择一个分类
{!!isInvalid && <>请至少选择一个分类>}
);
}
```
`ErrorMessage` 是基于 React Aria `Text` 组件、`errorMessage` slot 的底层组件,用于在 **非表单组件**(如 `TagGroup`、`Calendar` 及其他集合类组件)中展示错误消息。
## 组件结构
```tsx
import { TagGroup, Tag, Label, Description, ErrorMessage } from '@heroui/react';
```
## 何时使用
`ErrorMessage` **不绑定表单**,是用于非表单上下文的通用错误展示组件。
* **推荐用于** 非表单组件(如 `TagGroup`、`Calendar`、集合类组件)
* **表单字段** 建议使用 [`FieldError`](/docs/components/field-error),它提供表单专用校验特性与自动错误处理,遵循标准化表单校验模式。
## ErrorMessage 与 FieldError
| 组件 | 使用场景 | 表单集成 | 示例组件 |
| -------------- | -------- | ---- | ---------------------------------- |
| `ErrorMessage` | 非表单组件 | 否 | `TagGroup`、`Calendar` |
| `FieldError` | 表单字段(推荐) | 是 | `TextField`、`NumberField`、`Select` |
表单校验建议使用 `FieldError`,它遵循标准化表单校验模式并提供表单专用特性。参见 [FieldError 文档](/docs/components/field-error) 与 [Form 指南](/docs/components/form)。
## 自定义样式
### Tailwind CSS
```tsx
"use client";
import type {Key} from "@heroui/react";
import {Description, ErrorMessage, Label, Tag, TagGroup} from "@heroui/react";
import {useMemo, useState} from "react";
export function CustomStyles() {
const [selected, setSelected] = useState>(new Set());
const isInvalid = useMemo(() => Array.from(selected).length === 0, [selected]);
return (
主题
API
设计
文档
请至少选择一个主题
{!!isInvalid && <>请至少选择一个主题>}
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 ErrorMessage 组件类。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.error-message {
@apply text-sm font-medium text-danger;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
ErrorMessage 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/error-message.css)):
#### 基础类 \[!toc]
* `.error-message` - 基础错误消息样式,danger 色与文本截断
#### 插槽类 \[!toc]
* `[slot="errorMessage"]` - 用于 React Aria 集成的 ErrorMessage slot 样式
## API 参考
### ErrorMessage
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------- | --- | -------- |
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `ReactNode` | - | 错误消息内容 |
## 说明
`ErrorMessage` 基于 React Aria 的 `Text` 组件,`slot="errorMessage"`。可通过 `[slot=errorMessage]` CSS 选择器定位。
## 无障碍
ErrorMessage 组件通过以下方式增强无障碍性:
* 使用屏幕阅读器可识别的语义化 HTML
* 提供 `slot="errorMessage"` 属性以集成 React Aria
* 错误状态支持适当的文本对比度
* 遵循 WAI-ARIA 错误消息最佳实践
## 相关组件
## Related Components
* **TagGroup**: Focusable list of tags with selection and removal support
# FieldError 字段错误
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/field-error
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(forms)/field-error.mdx
> 展示表单字段校验错误消息
## 用法
```tsx
import { FieldError } from '@heroui/react';
```
```tsx
"use client";
import {FieldError, Input, Label, TextField} from "@heroui/react";
import {useState} from "react";
export function Basic() {
const [value, setValue] = useState("jr");
const isInvalid = value.length > 0 && value.length < 3;
return (
用户名
setValue(e.target.value)}
/>
用户名至少需要 3 个字符
);
}
```
FieldError 组件展示表单字段的校验错误消息。当父字段标记为无效时自动显示,并提供平滑的透明度过渡。
## 示例
### 基础校验
```tsx
export function Basic() {
const [value, setValue] = useState("");
const isInvalid = value.length > 0 && value.length < 3;
return (
Username
setValue(e.target.value)}
/>
Username must be at least 3 characters
);
}
```
### 动态错误信息
```tsx
0}>
Password
{(validation) => validation.validationErrors.join(', ')}
```
### 自定义校验逻辑
```tsx
function EmailField() {
const [email, setEmail] = useState('');
const isInvalid = email.length > 0 && !email.includes('@');
return (
Email
setEmail(e.target.value)}
/>
Email must include @ symbol
);
}
```
### 多条错误信息
```tsx
Username
{errors.map((error, i) => (
{error}
))}
```
## 自定义样式
### Tailwind CSS
```tsx
"use client";
import {FieldError, Input, Label, TextField} from "@heroui/react";
import {useState} from "react";
export function CustomStyles() {
const [value, setValue] = useState("jr");
const isInvalid = value.length > 0 && value.length < 3;
return (
用户名
setValue(e.target.value)}
/>
用户名至少需要 3 个字符
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 FieldError 组件类。[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.field-error {
@apply font-medium text-danger;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
FieldError 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/field-error.css)):
#### 基础类 \[!toc]
* `.field-error` - 基础错误样式,danger 色
* 仅在存在 `data-visible` 属性时显示
* 长消息以省略号截断
## API 参考
### FieldError
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ------------------------------------------------------------ | --- | ----------------- |
| `className` | `string` | - | 附加 CSS 类 |
| `children` | `ReactNode \| ((validation: ValidationResult) => ReactNode)` | - | 错误消息内容或 render 函数 |
## 无障碍
FieldError 组件通过以下方式确保无障碍性:
* 使用适当的 ARIA 属性播报错误
* 语义化 HTML 支持屏幕阅读器
* 提供视觉与程序化错误指示
* 根据校验状态自动管理可见性
## 相关组件
## Related Components
* **TextField**: Composition-friendly fields with labels and validation
* **Input**: Single-line text input built on React Aria
* **TextArea**: Multiline text input with focus management
# Fieldset 字段组
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/fieldset
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(forms)/fieldset.mdx
> 将相关表单控件与图例、描述和操作组合在一起
## 用法
```tsx
import { Fieldset } from '@heroui/react';
```
```tsx
"use client";
import {FloppyDisk} from "@gravity-ui/icons";
import {
Button,
Description,
FieldError,
FieldGroup,
Fieldset,
Form,
Input,
Label,
TextArea,
TextField,
} from "@heroui/react";
export function Basic() {
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const data: Record = {};
// Convert FormData to plain object
formData.forEach((value, key) => {
data[key] = value.toString();
});
alert("表单提交成功!");
};
return (
个人资料设置
更新你的个人资料信息。
{
if (value.length < 3) {
return "姓名至少需要 3 个字符";
}
return null;
}}
>
姓名
邮箱
{
if (value.length < 10) {
return "简介至少需要 10 个字符";
}
return null;
}}
>
简介
至少 10 个字符
保存更改
取消
);
}
```
## 组件结构
```tsx
import { Fieldset } from '@heroui/react';
export default () => (
{/* form fields go here */}
{/* action buttons go here */}
)
```
## 示例
### 表面样式
在 [Surface](/docs/components/surface) 内使用时,请在表单控件(Input、TextArea 等)上使用 `variant="secondary"`,以应用适合 Surface 背景的低强调变体。
```tsx
"use client";
import {FloppyDisk} from "@gravity-ui/icons";
import {
Button,
Description,
FieldError,
Fieldset,
Form,
Input,
Label,
Surface,
TextArea,
TextField,
} from "@heroui/react";
import React from "react";
export function OnSurface() {
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const data: Record = {};
// Convert FormData to plain object
formData.forEach((value, key) => {
data[key] = value.toString();
});
alert("表单提交成功!");
};
return (
个人资料设置
更新你的个人资料信息。
{
if (value.length < 3) {
return "姓名至少需要 3 个字符";
}
return null;
}}
>
姓名
邮箱
{
if (value.length < 10) {
return "简介至少需要 10 个字符";
}
return null;
}}
>
简介
至少 10 个字符
保存更改
取消
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
"use client";
import {FloppyDisk} from "@gravity-ui/icons";
import {
Button,
Description,
FieldError,
FieldGroup,
Fieldset,
Form,
Input,
Label,
TextArea,
TextField,
} from "@heroui/react";
const shell =
"rounded-xl border border-border/70 bg-linear-to-b from-neutral-50/90 to-white p-4 ring-1 ring-black/5 dark:from-neutral-900/80 dark:to-neutral-900 dark:ring-white/10";
const field =
"rounded-xl border border-border/80 bg-surface shadow-sm ring-1 ring-black/5 transition-[box-shadow,border-color] focus-visible:ring-2 focus-visible:ring-neutral-400/25 dark:ring-white/10 dark:focus-visible:ring-neutral-500/30";
export function CustomStyles() {
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
alert("表单提交成功!");
};
return (
个人资料设置
更新你的个人资料信息。
{
if (value.length < 3) {
return "姓名至少需要 3 个字符";
}
return null;
}}
>
姓名
邮箱
{
if (value.length < 10) {
return "简介至少需要 10 个字符";
}
return null;
}}
>
简介
至少 10 个字符
保存更改
取消
);
}
```
### 全局 CSS
使用 `@layer components` 指令定位 Fieldset 的 [BEM](https://getbem.com/) 风格类。
```css
@layer components {
.fieldset {
@apply gap-5 rounded-xl border border-border/60 bg-surface p-6 shadow-field;
}
.fieldset__legend {
@apply text-lg font-semibold;
}
.fieldset__field_group {
@apply gap-3 md:grid md:grid-cols-2;
}
.fieldset__actions {
@apply flex justify-end gap-2 pt-2;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
Fieldset 复合组件暴露以下 CSS 选择器:
#### 基础类 \[!toc]
* `.fieldset` – 根容器
* `.fieldset__legend` – 图例元素
* `.fieldset__field_group` – 分组字段包裹层
* `.fieldset__actions` – 字段下方的操作栏
## API 参考
### Fieldset
| Prop | 类型 | 默认值 | 描述 |
| ------------- | ------------------------------------------- | ------------------- | ------------------------ |
| `className` | `string` | - | 应用于根元素的 Tailwind CSS 类 |
| `children` | `React.ReactNode` | - | Fieldset 内容(图例、分组、描述、操作) |
| `nativeProps` | `React.HTMLAttributes` | 支持原生 fieldset 属性与事件 | |
### Fieldset.Legend
| Prop | 类型 | 默认值 | 描述 |
| ------------- | ----------------------------------------- | --- | ---------------- |
| `className` | `string` | - | 图例元素的 Tailwind 类 |
| `children` | `React.ReactNode` | - | 图例内容,通常为纯文本 |
| `nativeProps` | `React.HTMLAttributes` | - | 原生 legend 属性 |
### Fieldset.Group
| Prop | 类型 | 默认值 | 描述 |
| ------------- | -------------------------------------- | --- | ------------------ |
| `className` | `string` | - | 分组字段的布局与间距类 |
| `children` | `React.ReactNode` | - | fieldset 内要分组的表单控件 |
| `nativeProps` | `React.HTMLAttributes` | - | 原生 div 属性 |
### Fieldset.Actions
| Prop | 类型 | 默认值 | 描述 |
| ------------- | -------------------------------------- | --- | --------------------- |
| `className` | `string` | - | 对齐操作按钮或文本的 Tailwind 类 |
| `children` | `React.ReactNode` | - | 操作按钮或辅助文本 |
| `nativeProps` | `React.HTMLAttributes` | - | 原生 div 属性 |
## 相关案例
## 相关组件
## Related Components
* **TextField**: Composition-friendly fields with labels and validation
* **Label**: Accessible label for form controls
* **CheckboxGroup**: Group of checkboxes with shared state
# Form 表单
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/form
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(forms)/form.mdx
> 用于表单校验与提交处理的包裹组件
## 用法
```tsx
import { Form } from '@heroui/react';
```
```tsx
"use client";
import {Check} from "@gravity-ui/icons";
import {Button, Description, FieldError, Form, Input, Label, TextField} from "@heroui/react";
export function Basic() {
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const data: Record = {};
// Convert FormData to plain object
formData.forEach((value, key) => {
data[key] = value.toString();
});
alert(`表单提交数据:${JSON.stringify(data, null, 2)}`);
};
return (
{
if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(value)) {
return "请输入有效的邮箱地址";
}
return null;
}}
>
邮箱
{
if (value.length < 8) {
return "密码至少需要 8 个字符";
}
if (!/[A-Z]/.test(value)) {
return "密码至少需要包含一个大写字母";
}
if (!/[0-9]/.test(value)) {
return "密码至少需要包含一个数字";
}
return null;
}}
>
密码
至少 8 个字符,且包含 1 个大写字母和 1 个数字
提交
重置
);
}
```
## 组件结构
```tsx
import {Form, Button} from '@heroui/react';
export default () => (
{/* Form fields go here */}
)
```
## 示例
### 渲染函数
```tsx
"use client";
import {Check} from "@gravity-ui/icons";
import {Button, Description, FieldError, Form, Input, Label, TextField} from "@heroui/react";
export function RenderFunction() {
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const data: Record = {};
// Convert FormData to plain object
formData.forEach((value, key) => {
data[key] = value.toString();
});
alert(`表单提交数据:${JSON.stringify(data, null, 2)}`);
};
return (
}
onSubmit={onSubmit}
>
{
if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(value)) {
return "请输入有效的邮箱地址";
}
return null;
}}
>
邮箱
{
if (value.length < 8) {
return "密码至少需要 8 个字符";
}
if (!/[A-Z]/.test(value)) {
return "密码至少需要包含一个大写字母";
}
if (!/[0-9]/.test(value)) {
return "密码至少需要包含一个数字";
}
return null;
}}
>
密码
至少 8 个字符,且包含 1 个大写字母和 1 个数字
提交
重置
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
"use client";
import {Button, Form, Input, Label, TextField} from "@heroui/react";
export function CustomStyles() {
return (
e.preventDefault()}
>
工作邮箱
继续
);
}
```
### 全局 CSS
要自定义表单布局与间距,可在 `` 上使用 `className` prop,或通过 `@layer components` 添加项目级类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
`Form` 渲染原生 ` ` 元素,聚焦校验与提交。`@heroui/styles` 中无专用 BEM 类——从全局 CSS 应用容器样式,控件级自定义请使用字段组件。
```css
@layer components {
.form-layout {
@apply flex flex-col gap-4 rounded-xl border border-border bg-surface p-4 shadow-sm;
}
}
```
```tsx
{/* TextField, Input, Button, etc. */}
```
分组字段与共享布局请使用 [Fieldset](./fieldset),并定位 `.fieldset`、`.fieldset__legend` 等相关类。单个控件请参阅 [TextField](./text-field)、[Input](./input)、[Label](./label)、[FieldError](./field-error) 的 **Global CSS** 部分。
## 样式参考
HeroUI 对在 `@heroui/styles` 中提供样式的组件遵循 [BEM](https://getbem.com/) 方法论。
`Form` 渲染原生 `` 元素,无专用 BEM 类。通过 `className` 应用布局、间距与表面样式。字段外观与校验状态来自 `TextField`、`Input`、`Label`、`Description`、`FieldError` 等子组件。结构化多字段布局请与 [Fieldset](./fieldset) 组合使用。
## API 参考
### Form
Form 组件是 React Aria Form 原语的包裹层,提供表单校验与提交处理能力。
| Prop | 类型 | 默认值 | 描述 |
| -------------------- | ------------------------------------------------------------------------------ | ---------- | ---------------------------------------------------- |
| `action` | `string \| FormHTMLAttributes['action']` | - | 提交表单数据的 URL |
| `className` | `string` | - | 应用于 form 元素的 Tailwind CSS 类 |
| `children` | `React.ReactNode` | - | 表单内容(字段、按钮等) |
| `encType` | `'application/x-www-form-urlencoded' \| 'multipart/form-data' \| 'text/plain'` | - | 表单数据提交的编码类型 |
| `method` | `'get' \| 'post'` | - | 提交表单时使用的 HTTP 方法 |
| `onInvalid` | `(event: FormEvent) => void` | - | 表单校验失败时调用。默认聚焦第一个无效字段。使用 `preventDefault()` 可自定义聚焦行为 |
| `onReset` | `(event: FormEvent) => void` | - | 表单重置时调用 |
| `onSubmit` | `(event: FormEvent) => void` | - | 表单提交时调用 |
| `target` | `'_self' \| '_blank' \| '_parent' \| '_top'` | - | 提交后显示响应的位置 |
| `validationBehavior` | `'native' \| 'aria'` | `'native'` | 使用原生 HTML 校验还是 ARIA 校验。`native` 阻止提交,`aria` 实时显示错误 |
| `validationErrors` | `ValidationErrors` | - | 按字段名映射的服务端校验错误。立即显示,用户修改字段时清除 |
| `aria-label` | `string` | - | 表单的无障碍标签 |
| `aria-labelledby` | `string` | - | 标注表单的元素 ID。提供时创建 form landmark |
| `render` | `DOMRenderFunction` | - | 使用自定义 render 函数覆盖默认 DOM 元素 |
### Form Validation
Form 组件集成 React Aria 校验系统,支持:
* 使用内置 HTML5 校验属性(`required`、`minLength`、`pattern` 等)
* 在 TextField 组件上提供自定义校验函数
* 使用 FieldError 组件展示校验错误
* 在正确校验后处理表单提交
* 通过 `validationErrors` prop 提供服务端校验错误
#### Validation Behavior
`validationBehavior` prop 控制校验展示方式:
* **`native`**(默认):使用原生 HTML 校验,有错误时阻止提交
* **`aria`**:使用 ARIA 属性校验,用户输入时实时显示错误,不阻止提交
可在表单级或单个字段级设置此行为。
### Form Submission
表单可通过多种方式提交:
* **传统提交**:设置 `action` prop 提交到 URL
* **JavaScript 处理**:使用 `onSubmit` 处理表单数据
* **FormData API**:在 submit 处理函数中使用 FormData API 访问表单数据
FormData 示例:
```tsx
function handleSubmit(e: FormEvent) {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const data = Object.fromEntries(formData);
console.log('Form data:', data);
}
```
### Integration with Form Fields
Form 组件与 HeroUI 表单字段组件无缝协作:
* **TextField**:带标签与校验的文本输入
* **Checkbox**:布尔选择
* **RadioGroup**:多选一
* **Switch**:开关控件
* **Button**:提交与重置操作
所有字段组件放在 Form 内时会自动集成 Form 的校验与提交行为。
### Advanced Usage
更高级用法包括:
* 自定义校验上下文
* 表单 context provider
* 与第三方库集成
* 校验错误时的自定义焦点管理
请参阅 [React Aria Form 文档](https://react-spectrum.adobe.com/react-aria/Form.html)。
## 无障碍
使用 React Aria 组件时,表单默认可访问。主要特性包括:
* 原生 `` 元素语义
* 使用 `aria-label` 或 `aria-labelledby` 创建 form landmark
* 校验错误时自动焦点管理
* 使用 `validationBehavior="aria"` 时的 ARIA 校验属性
## 相关案例
## 相关组件
## Related Components
* **Button**: Allows a user to perform an action
* **Fieldset**: Group related form controls with legends
* **TextField**: Composition-friendly fields with labels and validation
# InputGroup 输入框组
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/input-group
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(forms)/input-group.mdx
> 将相关输入控件与前后缀元素组合,以增强表单字段
## 用法
```tsx
import { InputGroup } from '@heroui/react';
```
```tsx
"use client";
import {Envelope} from "@gravity-ui/icons";
import {InputGroup, Label, TextField} from "@heroui/react";
export function Default() {
return (
邮箱地址
);
}
```
## 组件结构
```tsx
import {InputGroup, TextField, Label} from '@heroui/react';
export default () => (
{/* Or use InputGroup.TextArea for multiline input */}
)
```
> **InputGroup** 使用可选的前缀与后缀包裹输入框,形成视觉上统一的组合。通常放在 **[TextField](/docs/components/text-field)** 内,用于在输入前后添加图标、文字、按钮等元素。单行输入请使用 **InputGroup.Input**,多行输入请使用 **InputGroup.TextArea**。
## 示例
### 变体
InputGroup 组件支持两种视觉变体:
* **`primary`**(默认)- 标准样式带阴影,适用于大多数场景
* **`secondary`** - 低强调变体无阴影,适用于 Surface 组件内
```tsx
import {Envelope} from "@gravity-ui/icons";
import {InputGroup, Label, TextField} from "@heroui/react";
export function Variants() {
return (
主要变体
次要变体
);
}
```
### 表面样式
在 [Surface](/docs/components/surface) 内使用时,请使用 `variant="secondary"` 以应用适合 Surface 背景的低强调变体。
```tsx
"use client";
import {Envelope} from "@gravity-ui/icons";
import {Description, InputGroup, Label, Surface, TextField} from "@heroui/react";
export function OnSurface() {
return (
邮箱地址
我们不会将此邮箱分享给任何人
);
}
```
### 后缀加载状态
在后缀显示加载 spinner 以表示正在处理。
```tsx
"use client";
import {InputGroup, Spinner, TextField} from "@heroui/react";
export function WithLoadingSuffix() {
return (
);
}
```
### 必填字段
InputGroup 会遵循父级 TextField 的必填状态。
```tsx
"use client";
import {Envelope} from "@gravity-ui/icons";
import {Description, InputGroup, Label, TextField} from "@heroui/react";
export function Required() {
return (
邮箱地址
设置价格
$
USD
客户将支付的价格
);
}
```
### 禁用状态
InputGroup 会遵循父级 TextField 的禁用状态。
```tsx
"use client";
import {Envelope} from "@gravity-ui/icons";
import {InputGroup, Label, TextField} from "@heroui/react";
export function Disabled() {
return (
邮箱地址
设置价格
$
USD
);
}
```
### 宽度充满
```tsx
import {Envelope, Eye} from "@gravity-ui/icons";
import {InputGroup, Label, TextField} from "@heroui/react";
export function FullWidth() {
return (
邮箱地址
密码
);
}
```
### 文字前缀
使用文字作为前缀,例如货币符号或协议前缀。
```tsx
"use client";
import {InputGroup, Label, TextField} from "@heroui/react";
export function WithTextPrefix() {
return (
网站
https://
);
}
```
### 文字后缀
使用文字作为后缀,例如域名后缀或单位。
```tsx
"use client";
import {InputGroup, Label, TextField} from "@heroui/react";
export function WithTextSuffix() {
return (
网站
.com
);
}
```
### 图标前缀与文字后缀
组合图标前缀与文字后缀。
```tsx
"use client";
import {Globe} from "@gravity-ui/icons";
import {InputGroup, Label, TextField} from "@heroui/react";
export function WithIconPrefixAndTextSuffix() {
return (
网站
.com
);
}
```
### 复制按钮后缀
在后缀中加入交互按钮,例如复制按钮。
```tsx
"use client";
import {Copy} from "@gravity-ui/icons";
import {Button, InputGroup, Label, TextField} from "@heroui/react";
export function WithCopySuffix() {
return (
网站
);
}
```
### 图标前缀与复制按钮
组合图标前缀与交互式后缀按钮。
```tsx
"use client";
import {Copy, Globe} from "@gravity-ui/icons";
import {Button, InputGroup, Label, TextField} from "@heroui/react";
export function WithIconPrefixAndCopySuffix() {
return (
网站
);
}
```
### 密码可见性切换
在后缀中使用按钮切换密码可见性。
```tsx
"use client";
import {Eye, EyeSlash} from "@gravity-ui/icons";
import {Button, InputGroup, Label, TextField} from "@heroui/react";
import {useState} from "react";
export function PasswordWithToggle() {
const [isVisible, setIsVisible] = useState(false);
return (
密码
setIsVisible(!isVisible)}
>
{isVisible ? : }
);
}
```
### 键盘快捷键
使用 [Kbd](/docs/components/kbd) 组件展示键盘快捷键。
```tsx
"use client";
import {InputGroup, Kbd, TextField} from "@heroui/react";
export function WithKeyboardShortcut() {
return (
K
);
}
```
### 徽章后缀
在后缀中加入徽章或 chip,用于展示状态或标签。
```tsx
"use client";
import {Chip, InputGroup, TextField} from "@heroui/react";
export function WithBadgeSuffix() {
return (
Pro
);
}
```
### 表单校验
InputGroup 会自动反映父级 TextField 的无效状态。
```tsx
"use client";
import {Envelope} from "@gravity-ui/icons";
import {FieldError, InputGroup, Label, TextField} from "@heroui/react";
export function Invalid() {
return (
邮箱地址
请输入有效的邮箱地址
设置价格
$
USD
价格必须大于 0
);
}
```
### 前缀图标
在输入框前添加图标。
```tsx
"use client";
import {Envelope} from "@gravity-ui/icons";
import {Description, InputGroup, Label, TextField} from "@heroui/react";
export function WithPrefixIcon() {
return (
邮箱地址
我们不会将此邮箱分享给任何人
);
}
```
### 后缀图标
在输入框后添加图标。
```tsx
"use client";
import {Envelope} from "@gravity-ui/icons";
import {Description, InputGroup, Label, TextField} from "@heroui/react";
export function WithSuffixIcon() {
return (
邮箱地址
我们不会发送垃圾邮件
);
}
```
### 前缀与后缀
同时组合前缀与后缀。
```tsx
"use client";
import {Description, InputGroup, Label, TextField} from "@heroui/react";
export function WithPrefixAndSuffix() {
return (
设置价格
$
USD
客户将支付的价格
);
}
```
### 文本域
多行输入请使用 **InputGroup.TextArea**,并搭配前缀与后缀。当存在 textarea 时,容器高度会自动适应内容,并将前缀/后缀与顶部对齐。
```tsx
"use client";
import {ArrowUp, At, Microphone, PlugConnection, Plus} from "@gravity-ui/icons";
import {Button, InputGroup, Kbd, Spinner, TextField, Tooltip} from "@heroui/react";
import {useState} from "react";
export function WithTextArea() {
const [value, setValue] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = () => {
if (!value.trim()) return;
setIsSubmitting(true);
setTimeout(() => {
setIsSubmitting(false);
setValue("");
}, 1000);
};
return (
添加上下文
setValue(event.target.value)}
/>
添加文件等
连接应用
语音输入
{({isPending}) => (isPending ? : )}
发送
);
}
```
### 用法示例
```tsx
import {InputGroup, TextField, Label, Button} from '@heroui/react';
import {Icon} from '@iconify/react';
function Example() {
return (
Email
);
}
```
### 文本域用法示例
```tsx
import {Envelope} from "@gravity-ui/icons";
import {Description, FieldError, InputGroup, Label, TextField} from "@heroui/react";
import {useState} from "react";
function TextAreaExample() {
const [feedback, setFeedback] = useState("");
return (
500} name="feedback" onChange={setFeedback}>
Your Feedback
Maximum 500 characters.
{feedback.length}/500
Feedback must be less than 500 characters
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
"use client";
import {Envelope} from "@gravity-ui/icons";
import {InputGroup, Label, TextField} from "@heroui/react";
export function CustomStyles() {
return (
工作邮箱
);
}
```
### 全局 CSS
InputGroup 使用可自定义的 CSS 类。覆盖组件类以匹配设计系统。
```css
@layer components {
.input-group {
@apply bg-field text-field-foreground shadow-field rounded-field inline-flex min-h-9 items-center overflow-hidden border text-sm outline-none;
}
.input-group__input {
@apply flex-1 rounded-none border-0 bg-transparent px-3 py-2 shadow-none outline-none;
}
.input-group__prefix {
@apply text-field-placeholder rounded-l-field flex h-full items-center justify-center rounded-r-none bg-transparent px-3;
}
.input-group__suffix {
@apply text-field-placeholder rounded-r-field flex h-full items-center justify-center rounded-l-none bg-transparent px-3;
}
/* Secondary variant */
.input-group--secondary {
@apply shadow-none;
background-color: var(--color-default);
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
#### 基础类 \[!toc]
* `.input-group` – 根容器:带边框、背景与 flex 布局。默认 `min-h-9` 与 `items-center`;存在 textarea 时切换为 `items-start`
* `.input-group__input` – 透明背景、无边框的输入元素。textarea 也使用该基础类
* `.input-group__prefix` – 左侧圆角的前缀容器。与 textarea 搭配时与顶部对齐
* `.input-group__suffix` – 右侧圆角的后缀容器。与 textarea 搭配时与顶部对齐
#### 变体类 \[!toc]
* `.input-group--primary` – 带阴影的主变体(默认)
* `.input-group--secondary` – 无阴影的次变体,适用于 Surface 内
**Note:** 使用 `InputGroup.TextArea` 时,容器从 `items-center` 切换为 `items-start`,并使用 `height: auto` 替代固定高度。前缀与后缀与顶部对齐,并增加内边距以匹配 textarea 的垂直内边距。textarea 使用相同的 `.input-group__input` 基础类,并通过 `[data-slot="input-group-textarea"]` 选择器应用 textarea 专用样式(最小高度与纵向 resize)。
### 交互状态
InputGroup 会根据状态自动管理以下 data 属性:
* **Hover**:`[data-hovered]` - 悬停在组合上时应用
* **Focus Within**:`[data-focus-within]` - 输入聚焦时应用
* **Invalid**:`[data-invalid]` - 父级 TextField 无效时应用
* **Disabled**:`[data-disabled]` 或 `[aria-disabled]` - 父级 TextField 禁用时应用
## API 参考
### InputGroup
InputGroup 继承 React Aria [Group](https://react-spectrum.adobe.com/react-aria/Group.html) 组件的全部 props。
#### Base Props
| Prop | 类型 | 默认值 | 描述 |
| ----------- | -------------------------------------------------------------------------- | ------- | -------------------------------------------- |
| `children` | `React.ReactNode \| (values: GroupRenderProps) => React.ReactNode` | - | 子组件(Input、TextArea、Prefix、Suffix)或 render 函数 |
| `className` | `string \| (values: GroupRenderProps) => string` | - | CSS 类,支持 render props |
| `style` | `React.CSSProperties \| (values: GroupRenderProps) => React.CSSProperties` | - | 行内样式,支持 render props |
| `fullWidth` | `boolean` | `false` | 输入组是否占满容器宽度 |
| `id` | `string` | - | 元素唯一标识符 |
#### Variant Props
| Prop | 类型 | 默认值 | 描述 |
| --------- | -------------------------- | ----------- | --------------------------------------------------------- |
| `variant` | `"primary" \| "secondary"` | `"primary"` | 视觉变体。`primary` 为默认带阴影样式;`secondary` 为低强调无阴影,适用于 Surface 内 |
#### Accessibility Props
| Prop | 类型 | 默认值 | 描述 |
| ------------------ | --------------------------------------- | --------- | --------------------------------------------- |
| `aria-label` | `string` | - | 无可见标签时的无障碍标签 |
| `aria-labelledby` | `string` | - | 标注该组的元素 ID |
| `aria-describedby` | `string` | - | 描述该组的元素 ID |
| `aria-details` | `string` | - | 包含更多详情的元素 ID |
| `role` | `'group' \| 'region' \| 'presentation'` | `'group'` | 分组的无障碍角色。重要内容用 `region`,纯视觉分组用 `presentation` |
### Composition Components
InputGroup 与以下子组件配合使用:
* **InputGroup.Root** - 根容器(也可写作 `InputGroup`)
* **InputGroup.Input** - 单行输入元素组件
* **InputGroup.TextArea** - 多行 textarea 元素组件
* **InputGroup.Prefix** - 前缀容器组件
* **InputGroup.Suffix** - 后缀容器组件
#### InputGroup.Input
InputGroup.Input 继承 React Aria [Input](https://react-spectrum.adobe.com/react-aria/Input.html) 组件的全部 props。
| Prop | 类型 | 默认值 | 描述 |
| -------------- | -------------------------- | ----------- | --------------------------- |
| `className` | `string` | - | CSS 类 |
| `variant` | `"primary" \| "secondary"` | `"primary"` | 输入视觉变体 |
| `type` | `string` | `'text'` | 输入类型(text、password、email 等) |
| `value` | `string` | - | 当前值(受控) |
| `defaultValue` | `string` | - | 默认值(非受控) |
| `placeholder` | `string` | - | 占位文本 |
| `disabled` | `boolean` | - | 是否禁用 |
| `readOnly` | `boolean` | - | 是否只读 |
#### InputGroup.TextArea
InputGroup.TextArea 继承 React Aria [TextArea](https://react-spectrum.adobe.com/react-aria/TextArea.html) 组件的全部 props。
| Prop | 类型 | 默认值 | 描述 |
| -------------- | -------------------------- | ----------- | ------------- |
| `className` | `string` | - | CSS 类 |
| `variant` | `"primary" \| "secondary"` | `"primary"` | textarea 视觉变体 |
| `value` | `string` | - | 当前值(受控) |
| `defaultValue` | `string` | - | 默认值(非受控) |
| `placeholder` | `string` | - | 占位文本 |
| `rows` | `number` | - | 可见文本行数 |
| `disabled` | `boolean` | - | 是否禁用 |
| `readOnly` | `boolean` | - | 是否只读 |
#### InputGroup.Prefix
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --- | ------------ |
| `children` | `React.ReactNode` | - | 前缀内容(图标、文字等) |
| `className` | `string` | - | CSS 类 |
#### InputGroup.Suffix
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --- | --------------- |
| `children` | `React.ReactNode` | - | 后缀内容(图标、按钮、徽章等) |
| `className` | `string` | - | CSS 类 |
## 相关案例
## 相关组件
## Related Components
* **TextField**: Composition-friendly fields with labels and validation
* **Input**: Single-line text input built on React Aria
* **Label**: Accessible label for form controls
# InputOTP 一次性密码输入
**Category**: react
**URL**: https://heroui.com/cn/docs/react/components/input-otp
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/cn/react/components/(forms)/input-otp.mdx
> 用于验证码与安全认证的一次性密码输入组件
## 用法
```tsx
import { InputOTP } from '@heroui/react';
```
```tsx
import {InputOTP, Label, Link} from "@heroui/react";
export function Basic() {
return (
验证账户
我们已向 a****@gmail.com 发送验证码
);
}
```
## 组件结构
```tsx
import { InputOTP } from '@heroui/react';
export default () => (
{/* ...rest of the slots */}
{/* ...rest of the slots */}
)
```
> **InputOTP** 基于 [@guilherme\_rodz](https://twitter.com/guilherme_rodz) 的 [input-otp](https://github.com/guilhermerodz/input-otp) 构建,为 OTP 输入组件提供灵活且无障碍的基础。
## 示例
### 变体
InputOTP 组件支持两种视觉变体:
* **`primary`**(默认)- 标准样式带阴影,适用于大多数场景
* **`secondary`** - 低强调变体无阴影,适用于 Surface 组件内
```tsx
import {InputOTP, Label} from "@heroui/react";
export function Variants() {
return (
);
}
```
### 表面样式
在 [Surface](/docs/components/surface) 内使用时,请使用 `variant="secondary"` 以应用适合 Surface 背景的低强调变体。
```tsx
import {InputOTP, Label, Link, Surface} from "@heroui/react";
export function OnSurface() {
return (
验证账户
我们已向 a****@gmail.com 发送验证码
);
}
```
### 禁用状态
```tsx
import {Description, InputOTP, Label} from "@heroui/react";
export function Disabled() {
return (
验证账户
验证码校验当前已禁用
);
}
```
### 四位验证码
```tsx
import {InputOTP, Label} from "@heroui/react";
export function FourDigits() {
return (
输入 PIN
);
}
```
### 受控组件
控制 value 以与状态同步、清空输入或实现自定义校验。
```tsx
"use client";
import {Description, InputOTP, Label} from "@heroui/react";
import React from "react";
export function Controlled() {
const [value, setValue] = React.useState("");
return (
验证账户
{value.length > 0 ? (
<>
值:{value} ({value.length}/6) •{" "}
setValue("")}>
Clear
>
) : (
"请输入 6 位验证码"
)}
);
}
```
### 输入完成回调
使用 `onComplete` 回调在所有 slot 填满时触发操作。
```tsx
"use client";
import {Button, Form, InputOTP, Label, Spinner} from "@heroui/react";
import React from "react";
export function OnComplete() {
const [value, setValue] = React.useState("");
const [isComplete, setIsComplete] = React.useState(false);
const [isSubmitting, setIsSubmitting] = React.useState(false);
const handleComplete = (code: string) => {
setIsComplete(true);
console.log("Code complete:", code);
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
setIsSubmitting(true);
// Simulate API call
setTimeout(() => {
setIsSubmitting(false);
setValue("");
setIsComplete(false);
}, 2000);
};
return (
验证账户
{
setValue(val);
setIsComplete(false);
}}
>
{isSubmitting ? (
<>
验证中…
>
) : (
"验证验证码"
)}
);
}
```
### 表单示例
完整的双因素认证表单,含校验与提交。
```tsx
"use client";
import {Button, Description, Form, InputOTP, Label, Link, Spinner} from "@heroui/react";
import React from "react";
export function FormExample() {
const [value, setValue] = React.useState("");
const [error, setError] = React.useState("");
const [isSubmitting, setIsSubmitting] = React.useState(false);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
setError("");
if (value.length !== 6) {
setError("请输入全部 6 位数字");
return;
}
setIsSubmitting(true);
// Simulate API call
setTimeout(() => {
if (value === "123456") {
console.log("Code verified successfully!");
setValue("");
} else {
setError("验证码无效,请重试。");
}
setIsSubmitting(false);
}, 1500);
};
return (
双重身份验证
请输入身份验证器应用中的 6 位验证码
{
setValue(val);
setError("");
}}
>
{error}
{isSubmitting ? (
<>
验证中…
>
) : (
"验证"
)}
);
}
```
### 限定格式
使用 `pattern` prop 限制输入字符。HeroUI 导出 `REGEXP_ONLY_CHARS`、`REGEXP_ONLY_DIGITS` 等常用模式。
```tsx
import {Description, InputOTP, Label, REGEXP_ONLY_CHARS} from "@heroui/react";
export function WithPattern() {
return (
输入验证码(仅字母)
仅允许输入字母
);
}
```
### 带校验
配合 `isInvalid` 与校验消息展示错误。
```tsx
"use client";
import {Button, Description, Form, InputOTP, Label} from "@heroui/react";
import React from "react";
export function WithValidation() {
const [value, setValue] = React.useState("");
const [isInvalid, setIsInvalid] = React.useState(false);
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const code = formData.get("code");
if (code !== "123456") {
setIsInvalid(true);
return;
}
setIsInvalid(false);
setValue("");
alert("验证码校验成功!");
};
const handleChange = (val: string) => {
setValue(val);
setIsInvalid(false);
};
return (
验证账户
提示:验证码为 123456
验证码无效,请重试。
提交
);
}
```
## 自定义样式
### Tailwind CSS
```tsx
import {InputOTP, Label, Link} from "@heroui/react";
const slotClass =
"rounded-lg border-border/80 bg-default data-[active=true]:border-accent/40 data-[active=true]:bg-accent-soft";
export function CustomStyles() {
return (
验证账户
重新发送
);
}
```
### 全局 CSS
可使用 `@layer components` 指令自定义 InputOTP 组件类。
[了解更多](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes)。
```css
@layer components {
.input-otp {
@apply gap-3;
}
.input-otp__slot {
@apply size-12 rounded-xl border-2 font-bold;
}
.input-otp__slot[data-active="true"] {
@apply border-accent-500 ring-2 ring-accent-200;
}
.input-otp__separator {
@apply w-2 h-1 bg-border-strong rounded-full;
}
}
```
## 样式参考
HeroUI 遵循 [BEM](https://getbem.com/) 方法论,确保组件变体与状态可复用且易于自定义。
### CSS 类
InputOTP 组件使用以下 CSS 类([查看源码样式](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/input-otp.css)):
#### 基础类 \[!toc]
* `.input-otp` - 基础容器
* `.input-otp__container` - input-otp 库的内部容器
* `.input-otp__group` - slot 组
* `.input-otp__slot` - 单个输入 slot
* `.input-otp__slot-value` - slot 内的字符
* `.input-otp__caret` - 闪烁光标指示器
* `.input-otp__separator` - 组之间的视觉分隔符
#### 状态类 \[!toc]
* `.input-otp__slot[data-active="true"]` - 当前激活的 slot
* `.input-otp__slot[data-filled="true"]` - 含字符的 slot
* `.input-otp__slot[data-disabled="true"]` - 禁用的 slot
* `.input-otp__slot[data-invalid="true"]` - 无效的 slot
* `.input-otp__container[data-disabled="true"]` - 禁用的容器
### 交互状态
组件同时支持 CSS 伪类与 data 属性:
* **Hover**:slot 上 `:hover` 或 `[data-hovered="true"]`
* **Active**:slot 上 `[data-active="true"]`(当前聚焦)
* **Filled**:slot 上 `[data-filled="true"]`(含字符)
* **Disabled**:容器与 slot 上 `[data-disabled="true"]`
* **Invalid**:slot 上 `[data-invalid="true"]`
## API 参考
### InputOTP
InputOTP 基于 [input-otp](https://github.com/guilhermerodz/input-otp) 库构建,并附加额外特性。
#### Base Props
| Prop | 类型 | 默认值 | 描述 |
| -------------------- | -------------------------- | ----------- | --------------------------------------------------------- |
| `maxLength` | `number` | - | **必填。** 输入 slot 数量 |
| `value` | `string` | - | 受控值(未提供则为非受控) |
| `onChange` | `(value: string) => void` | - | 值变化时的回调 |
| `onComplete` | `(value: string) => void` | - | 所有 slot 填满时的回调 |
| `className` | `string` | - | 容器的附加 CSS 类 |
| `containerClassName` | `string` | - | 内部容器的 CSS 类 |
| `variant` | `"primary" \| "secondary"` | `"primary"` | 视觉变体。`primary` 为默认带阴影样式;`secondary` 为低强调无阴影,适用于 Surface 内 |
| `children` | `React.ReactNode` | - | InputOTP.Group、InputOTP.Slot 与 InputOTP.Separator 组件 |
#### Validation Props
| Prop | 类型 | 默认值 | 描述 |
| ------------------- | --------------- | ------- | ----------- |
| `isDisabled` | `boolean` | `false` | 是否禁用 |
| `isInvalid` | `boolean` | `false` | 是否处于无效状态 |
| `validationErrors` | `string[]` | - | 服务端或自定义校验错误 |
| `validationDetails` | `ValidityState` | - | HTML5 校验详情 |
#### Input Props
| Prop | 类型 | 默认值 | 描述 |
| ------------------ | --------------------------------------------------------------------------- | ----------- | --------------------------------- |
| `pattern` | `string` | - | 允许字符的正则模式(如 `REGEXP_ONLY_DIGITS`) |
| `textAlign` | `'left' \| 'center' \| 'right'` | `'left'` | slot 内文本对齐 |
| `inputMode` | `'numeric' \| 'text' \| 'decimal' \| 'tel' \| 'search' \| 'email' \| 'url'` | `'numeric'` | 移动设备虚拟键盘类型 |
| `placeholder` | `string` | - | 空 slot 的占位文本 |
| `pasteTransformer` | `(text: string) => string` | - | 转换粘贴文本(如移除连字符) |
#### Form Props
| Prop | 类型 | 默认值 | 描述 |
| ----------- | --------- | --- | --------------- |
| `name` | `string` | - | 表单提交的 name 属性 |
| `autoFocus` | `boolean` | - | 挂载时是否聚焦第一个 slot |
### InputOTP.Group
| Prop | 类型 | 默认值 | 描述 |
| ----------- | ----------------- | --- | ---------------- |
| `className` | `string` | - | 组的附加 CSS 类 |
| `children` | `React.ReactNode` | - | InputOTP.Slot 组件 |
### InputOTP.Slot
| Prop | 类型 | 默认值 | 描述 |
| ----------- | -------- | --- | -------------------- |
| `index` | `number` | - | **必填。** slot 的从零开始索引 |
| `className` | `string` | - | slot 的附加 CSS 类 |
### InputOTP.Separator
| Prop | 类型 | 默认值 | 描述 |
| ----------- | -------- | --- | ------------ |
| `className` | `string` | - | 分隔符的附加 CSS 类 |
### Exported Patterns
HeroUI