Alpha 35 [v3] (#5830)

* fix(component): support compound pattern in server component

* fix(component): keep accordion and chip in sync with compound pattern

* fix(component): type of forward refs

* fix(calendar): temporary workaround for ref error

* fix(storybook): imports

* refactor: migration from dot notation to separted components to support RSC

* refactor: migrate to React 19 ref pattern - remove forwardRef wrappers and explicit ref declarations from all components

* refactor: provider context removed as it is not longer needed on react 19

* feat: made the migration smoother by still supporting the "dot" exports but adjusting the main compound component

* fix: compound patter, radio group api, ref on react 19

* refactor(switch): split switch and switch-group into separate components following radio/radio-group pattern

* chore(changelog): update v3.0.0-alpha.35 release notes and date

* fix(page): update version label to reflect RSC support

* chore(changelog): update examples to use new component names CardRoot and TabsRoot

* fix(changelog): update release notes for v3.0.0-alpha.35, refactor Switch component to align with Radio/RadioGroup pattern, and clarify migration steps

* fix: broken storybook (#5836)

* fix(disclosure-group): broken api

* chore(radio): remove storybook

* chore: alpha 35 released

---------

Co-authored-by: Tianen Pang <32772271+tianenpang@users.noreply.github.com>
Co-authored-by: WK <wingkwong.code@gmail.com>
This commit is contained in:
Junior Garcia
2025-10-21 10:05:28 -03:00
committed by GitHub
parent 3991fb7e7c
commit 772b94282e
217 changed files with 4584 additions and 4247 deletions
+2 -2
View File
@@ -2,8 +2,8 @@
"mode": "pre",
"tag": "alpha",
"initialVersions": {
"@heroui/react": "3.0.0-alpha.34",
"@heroui/styles": "3.0.0-alpha.34"
"@heroui/react": "3.0.0-alpha.35",
"@heroui/styles": "3.0.0-alpha.35"
},
"changesets": ["pink-monkeys-notice"]
}
+29 -4
View File
@@ -12,6 +12,35 @@ icon: clock-arrow-rotate-left
## Latest Release
### v3.0.0-alpha.35
**October 21, 2025**
#### React Server Components Support
- Fixed critical issue where compound components didn't work in React Server Components (RSC)
- Moved compound pattern logic from components to index files, resolving `"use client"` conflicts
- **(⚠️ Breaking change)**: Main component now requires `.Root` suffix (e.g., `<Avatar>` → `<Avatar.Root>`)
- Named exports remain unchanged and fully supported
#### React 19 Improvements
- Removed `forwardRef` (now native in [React 19](https://react.dev/blog/2024/12/05/react-19#ref-as-a-prop))
- Simplified Context usage (`Context.Provider` → [React 19](https://react.dev/blog/2024/12/05/react-19#context-as-a-provider))
#### Switch Component Refactoring
- **(⚠️ Breaking change)**: Split Switch and SwitchGroup into separate components
- Cleaner API: `<SwitchGroup>` replaces `<Switch.Group>` and `<Switch.GroupItems>`
- Matches Radio/RadioGroup pattern for consistency
- Separate styles, types, and implementations
#### Affected Components
All compound components now require `.Root` suffix: `Accordion`, `Avatar`, `Card`, `Disclosure`, `Fieldset`, `Kbd`, `Link`, `Popover`, `Radio`, `Switch`, `Tabs`, `Tooltip`
[Read full release notes →](/docs/changelog/v3-0-0-alpha-35)
---
## Previous Releases
### v3.0.0-alpha.34
**October 15, 2025**
@@ -26,10 +55,6 @@ icon: clock-arrow-rotate-left
[Read full release notes →](/docs/changelog/v3-0-0-alpha-34)
---
## Previous Releases
### v3.0.0-alpha.33
**October 5, 2025**
+1 -1
View File
@@ -2,5 +2,5 @@
"title": "Changelog",
"description": "HeroUI v3 Release Notes",
"root": false,
"pages": ["changelog", "v3-0-0-alpha-34"]
"pages": ["changelog", "v3-0-0-alpha-35"]
}
@@ -4,7 +4,7 @@ description: Card component redesign, CloseButton, MCP Server for AI assistants
---
<div className="flex items-center gap-3 mb-6">
<span className="text-sm text-neutral-500 dark:text-neutral-400">October 1, 2025</span>
<span className="text-sm text-muted">October 1, 2025</span>
</div>
This release adds AI development tools, updates the [Card component](/docs/components/card) API, and improves the developer experience.
@@ -4,7 +4,7 @@ description: RAC upgrade, Tabs indicator redesign, Switch size variant, Related
---
<div className="flex items-center gap-3 mb-6">
<span className="text-sm text-neutral-500 dark:text-neutral-400">October 5, 2025</span>
<span className="text-sm text-muted">October 5, 2025</span>
</div>
This release upgrades React Aria Components, redesigns the Tabs indicator, adds Switch sizes, and includes component showcases.
@@ -4,7 +4,7 @@ description: Essentials for building forms with a clean API Form, TextField, Rad
---
<div className="flex items-center gap-3 mb-6">
<span className="text-sm text-neutral-500 dark:text-neutral-400">October 15, 2025</span>
<span className="text-sm text-muted">October 15, 2025</span>
</div>
This release introduces Form-based components, form field tokens, reorganizes Storybook, and aligns data-slot markers across components.
@@ -0,0 +1,401 @@
---
title: v3.0.0-alpha.35
description: React Server Components support for compound components, React 19 improvements, and critical bug fixes.
---
<div className="flex items-center gap-3 mb-6">
<span className="text-sm text-muted">October 21, 2025</span>
</div>
This release fixes a critical issue where **compound components didn't work correctly in React Server Components (RSC)**. Additionally, this release adopts React 19 best practices by removing `forwardRef` and simplifying context usage. The Switch component has been refactored to match the Radio/RadioGroup pattern, providing a cleaner and more consistent API.
## Installation
Update to the latest version:
<Tabs items={["npm", "pnpm", "yarn", "bun"]}>
<Tab value="npm">
```bash
npm i @heroui/styles@alpha @heroui/react@alpha
```
</Tab>
<Tab value="pnpm">
```bash
pnpm add @heroui/styles@alpha @heroui/react@alpha
```
</Tab>
<Tab value="yarn">
```bash
yarn add @heroui/styles@alpha @heroui/react@alpha
```
</Tab>
<Tab value="bun">
```bash
bun add @heroui/styles@alpha @heroui/react@alpha
```
</Tab>
</Tabs>
<Callout type="info">
**Using AI assistants?** Simply prompt "Hey Cursor, update HeroUI to the latest version" and your AI assistant will automatically compare versions and apply the necessary changes. Learn more about the [HeroUI MCP Server](/docs/ui-for-agents/mcp-server).
</Callout>
## What's New
### React Server Components Support
Compound components now work correctly in React Server Components. The previous implementation had the compound pattern logic inside components, which conflicted with the `"use client"` directive. This has been fixed by moving the pattern logic to component index files.
### React 19 Improvements
This release adopts React 19 best practices:
1. **Removed `forwardRef`**: No longer needed in React 19, where `ref` is now a prop ([React 19 docs](https://react.dev/blog/2024/12/05/react-19#ref-as-a-prop))
2. **Simplified Context**: `Context.Provider` replaced with just `Context` ([React 19 docs](https://react.dev/blog/2024/12/05/react-19#context-as-a-provider))
### Switch Component Architecture Improvement
The Switch component has been refactored to follow the same clean separation pattern as Radio/RadioGroup:
- **Separate Components**: Switch and SwitchGroup are now independent components (previously combined)
- **Cleaner API**: `<SwitchGroup>` replaces the nested `<Switch.Group>` and `<Switch.GroupItems>` pattern
- **Better Organization**: Separate styles, types, and implementations for each component
- **Consistent Pattern**: Matches the Radio/RadioGroup architecture for a more predictable API
**Before:**
```tsx
<Switch.Group>
<Switch.GroupItems>
<Switch.Root>...</Switch.Root>
</Switch.GroupItems>
</Switch.Group>
```
**After:**
```tsx
<SwitchGroup>
<Switch.Root>...</Switch.Root>
<Switch.Root>...</Switch.Root>
</SwitchGroup>
```
## ⚠️ Breaking Changes
### Main Component Requires `.Root` Suffix
To support React Server Components, the compound component pattern has been restructured. The main component now requires the `.Root` suffix when using the compound pattern.
**Before:**
```tsx
import { Avatar } from "@heroui/react"
<Avatar>
<Avatar.Image src="/images/avatar.jpeg" alt="Junior Garcia" />
<Avatar.Fallback>JR</Avatar.Fallback>
</Avatar>
```
**After:**
```tsx
import { Avatar } from "@heroui/react"
<Avatar.Root>
<Avatar.Image src="/images/avatar.jpeg" alt="Junior Garcia" />
<Avatar.Fallback>JR</Avatar.Fallback>
</Avatar.Root>
```
**Note:** Named exports (e.g., `<Avatar>`, `<AvatarImage>`, `<AvatarFallback>`) remain unchanged and fully supported.
### Switch Component API Changes
The Switch component grouping API has been restructured to match the Radio/RadioGroup pattern:
**Before:**
```tsx
import { Switch } from "@heroui/react"
<Switch.Group orientation="horizontal">
<Switch.GroupItems>
<Switch.Root name="notifications">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label>Notifications</Label>
</Switch.Root>
<Switch.Root name="marketing">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label>Marketing</Label>
</Switch.Root>
</Switch.GroupItems>
</Switch.Group>
```
**After:**
```tsx
import { Switch, SwitchGroup } from "@heroui/react"
<SwitchGroup orientation="horizontal">
<Switch.Root name="notifications">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label>Notifications</Label>
</Switch.Root>
<Switch.Root name="marketing">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label>Marketing</Label>
</Switch.Root>
</SwitchGroup>
```
This change helps to:
- **Separate Components**: Switch and SwitchGroup are now independent components (previously combined)
- **Cleaner API**: `<SwitchGroup>` replaces the nested `<Switch.Group>` and `<Switch.GroupItems>` pattern
- **Better Organization**: Separate styles, types, and implementations for each component
- **Consistent Pattern**: Matches the Radio/RadioGroup architecture for a more predictable API
**Migration Steps:**
1. Import `SwitchGroup` separately: `import { Switch, SwitchGroup } from "@heroui/react"`
2. Replace `<Switch.Group>` with `<SwitchGroup>`
3. Remove the nested `<Switch.GroupItems>` wrapper
4. Individual `Switch.Root` components remain unchanged
#### Affected Components
All compound components are affected:
- `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`
## Migration Guide
You have two options for using HeroUI compound components:
### Option 1: Update to Use `.Root` (Compound Pattern)
If you're using the compound pattern (dot notation), update your code to use `.Root` for the main component:
**Card Example:**
```tsx
import { Card } from "@heroui/react"
<Card.Root>
<Card.Header>
<Card.Title>Card Title</Card.Title>
<Card.Description>Card description</Card.Description>
</Card.Header>
<Card.Content>
Card content
</Card.Content>
<Card.Footer>
Card footer
</Card.Footer>
</Card.Root>
```
**Tabs Example:**
```tsx
import { Tabs } from "@heroui/react"
<Tabs.Root>
<Tabs.ListWrapper>
<Tabs.List>
<Tabs.Tab id="tab1">Tab 1<Tabs.Indicator /></Tabs.Tab>
<Tabs.Tab id="tab2">Tab 2<Tabs.Indicator /></Tabs.Tab>
</Tabs.List>
</Tabs.ListWrapper>
<Tabs.Panel id="tab1">Panel 1</Tabs.Panel>
<Tabs.Panel id="tab2">Panel 2</Tabs.Panel>
</Tabs.Root>
```
[See more examples in the documentation](/docs/components/card)
**Avatar Example:**
```tsx
import { Avatar } from "@heroui/react"
<Avatar.Root>
<Avatar.Image alt="John Doe" src="..." />
<Avatar.Fallback>JD</Avatar.Fallback>
</Avatar.Root>
```
[See more examples in the documentation](/docs/components/avatar)
### Option 2: Use Named Exports
We added support for named exports for all compound components. You can use them like this:
**Card Example:**
```tsx
import {
CardRoot,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
} from "@heroui/react"
<CardRoot>
<CardHeader>
<CardTitle>Card Title</CardTitle>
<CardDescription>Card description</CardDescription>
</CardHeader>
<CardContent>
Card content
</CardContent>
<CardFooter>
Card footer
</CardFooter>
</CardRoot>
```
**Tabs Example:**
```tsx
import { TabsRoot, TabListWrapper, TabList, Tab, TabIndicator, TabPanel } from "@heroui/react"
<TabsRoot>
<TabListWrapper>
<TabList>
<Tab id="tab1">Tab 1<TabIndicator /></Tab>
<Tab id="tab2">Tab 2<TabIndicator /></Tab>
</TabList>
</TabListWrapper>
<TabPanel id="tab1">Panel 1</TabPanel>
<TabPanel id="tab2">Panel 2</TabPanel>
</TabsRoot>
```
**Avatar Example:**
```tsx
import { Avatar, AvatarImage, AvatarFallback } from "@heroui/react"
<Avatar>
<AvatarImage alt="John Doe" src="..." />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
```
### Migration Steps
If you're using the compound pattern, you only need to update the main component to use `.Root`:
1. **Find all instances of compound components** (e.g., `<Avatar>` with `<Avatar.Image>` inside)
2. **Add `.Root` to the main component**:
```tsx
// Before
<Avatar>
<Avatar.Image ... />
</Avatar>
// After
<Avatar.Root>
<Avatar.Image ... />
</Avatar.Root>
```
3. **That's it!** All child components (e.g., `Avatar.Image`, `Avatar.Fallback`) remain unchanged.
### Complete Migration Reference
| Component | Named Export Pattern | Compound Pattern (with `.Root`) | Additional Changes |
|-----------|---------------------|---------------------|---------------------|
| **Accordion** | `<Accordion>` | `<Accordion.Root>` | - |
| **Avatar** | `<Avatar>` | `<Avatar.Root>` | - |
| **Card** | `<Card>` | `<Card.Root>` | - |
| **Disclosure** | `<Disclosure>` | `<Disclosure.Root>` | - |
| **Fieldset** | `<Fieldset>` | `<Fieldset.Root>` | - |
| **Kbd** | `<Kbd>` | `<Kbd.Root>` | - |
| **Link** | `<Link>` | `<Link.Root>` | - |
| **Popover** | `<Popover>` | `<Popover.Root>` | - |
| **Radio** | `<Radio>` | `<Radio.Root>` | - |
| **Switch** | `<Switch>`, `<SwitchControl>` | `<Switch.Root>`, `<Switch.Control>` | `<Switch.Group>` → `<SwitchGroup>` (separate component) |
| **Tabs** | `<Tabs>`, `<TabList>` | `<Tabs.Root>`, `<Tabs.List>` | - |
| **Tooltip** | `<Tooltip>`, `<TooltipTrigger>` | `<Tooltip.Root>`, `<Tooltip.Trigger>` | - |
### Automated Migration
For large codebases using the compound pattern, you can use find-and-replace:
```bash
# Example for Avatar component
# Update the main component to use .Root
sed -i 's/<Avatar>/<Avatar.Root>/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/<Switch\.Group/<SwitchGroup/g' **/*.tsx
sed -i 's/<\/Switch\.Group>/<\/SwitchGroup>/g' **/*.tsx
# Remove Switch.GroupItems wrapper
sed -i 's/<Switch\.GroupItems>//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
```
**Important:**
- Be careful with automated replacements. Make sure you're only replacing compound pattern usage, not named exports.
- For Switch migrations, verify that `SwitchGroup` is imported: `import { Switch, SwitchGroup } from "@heroui/react"`
- Test your code after running automated migrations to ensure all changes are correct.
## Why This Change?
This change was necessary to fix React Server Components compatibility. The previous implementation had architectural limitations:
1. **RSC Compatibility**: Compound pattern logic conflicted with `"use client"` directives
2. **React 19 Readiness**: Removes deprecated patterns like `forwardRef` and `Context.Provider`
3. **Cleaner Architecture**: Pattern logic is now in index files, not component files
4. **Better Separation**: Server and client components can now work together seamlessly
## Documentation Updates
Component documentation will be updated to reflect the new patterns:
- Examples will show the compound pattern with `.Root`
- Named export examples remain valid and supported
- Migration guides will help you transition smoothly
- Both patterns are fully supported and work identically
## Need Help?
If you encounter any issues during migration:
1. **Compound pattern users**: Update the main component to use `.Root` (e.g., `<Avatar>` → `<Avatar.Root>`)
2. **Named export users**: No changes needed - your code continues to work as-is
3. Check the component documentation for examples
4. Report issues at: [GitHub Issues](https://github.com/heroui-inc/heroui/issues)
## Links
- [Component Documentation](https://heroui.com/docs/components)
- [React Server Components](https://react.dev/reference/rsc/server-components)
- [React 19 Release](https://react.dev/blog/2024/12/05/react-19)
- [GitHub Repository](https://github.com/heroui-inc/heroui)
## Contributors
Thanks to everyone who contributed to this release, improving React Server Components support and React 19 compatibility!
@@ -1,6 +1,7 @@
---
title: Accordion
description: A collapsible content panel for organizing information in a compact space
icon: updated
links:
rac: Disclosure
source: accordion/accordion.tsx
@@ -24,13 +25,13 @@ import { Accordion } from '@heroui/react';
### Anatomy
Import all parts and piece them together.
Import the Accordion component and access all parts using dot notation.
```tsx
import { Accordion } from '@heroui/react';
export default () => (
<Accordion>
<Accordion.Root>
<Accordion.Item>
<Accordion.Heading>
<Accordion.Trigger>
@@ -41,7 +42,7 @@ export default () => (
<Accordion.Body/>
</Accordion.Panel>
</Accordion.Item>
</Accordion>
</Accordion.Root>
)
```
@@ -89,7 +90,7 @@ export default () => (
<CollapsibleCode lang="tsx" code={`"use client";
import {Accordion, cn} from "@heroui/react";
import { Accordion, cn } from "@heroui/react";
import {Icon} from "@iconify/react";
const items = [
@@ -119,7 +120,7 @@ const items = [
export function CustomStyles() {
return (
<Accordion className="bg-surface-1 w-full max-w-md rounded-2xl" variant="outline">
<Accordion.Root className="bg-surface-1 w-full max-w-md rounded-2xl" variant="outline">
{items.map((item, index) => (
<Accordion.Item
key={index}
@@ -152,7 +153,7 @@ export function CustomStyles() {
</Accordion.Panel>
</Accordion.Item>
))}
</Accordion>
</Accordion.Root>
);
}`} />
@@ -210,7 +211,7 @@ The component supports both CSS pseudo-classes and data attributes for flexibili
## API Reference
### Accordion Props
### Accordion.Root Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
+7 -6
View File
@@ -1,6 +1,7 @@
---
title: Avatar
description: Display user profile images with customizable fallback content
icon: updated
links:
radix: avatar
source: avatar/avatar.tsx
@@ -21,16 +22,16 @@ import { Avatar } from '@heroui/react';
### Anatomy
Import all parts and piece them together.
Import the Avatar component and access all parts using dot notation.
```tsx
import { Avatar } from '@heroui/react';
export default () => (
<Avatar>
<Avatar.Root>
<Avatar.Image/>
<Avatar.Fallback/>
</Avatar>
</Avatar.Root>
)
```
@@ -63,10 +64,10 @@ import { Avatar } from '@heroui/react';
function CustomAvatar() {
return (
<Avatar className="size-20">
<Avatar.Root className="size-20">
<Avatar.Image src="..." alt="..." />
<Avatar.Fallback>XL</Avatar.Fallback>
</Avatar>
</Avatar.Root>
);
}
```
@@ -113,7 +114,7 @@ The Avatar component uses these CSS classes ([View source styles](https://github
## API Reference
### Avatar Props
### Avatar.Root Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
+13 -12
View File
@@ -1,6 +1,7 @@
---
title: Card
description: Flexible container component for grouping related content and actions
icon: updated
links:
source: card/card.tsx
styles: card.css
@@ -10,7 +11,7 @@ links:
## Import
```tsx
import {Card} from "@heroui/react";
import { Card } from "@heroui/react";
```
### Usage
@@ -21,20 +22,20 @@ import {Card} from "@heroui/react";
### Anatomy
Import all parts and piece them together.
Import the Card component and access all parts using dot notation.
```tsx
import {Card} from "@heroui/react";
import { Card } from "@heroui/react";
export default () => (
<Card>
<Card.Root>
<Card.Header>
<Card.Title />
<Card.Description />
</Card.Header>
<Card.Content />
<Card.Footer />
</Card>
</Card.Root>
);
```
@@ -78,18 +79,18 @@ export default () => (
```tsx
// Semantic markup
<Card role="article" aria-labelledby="card-title">
<Card.Root role="article" aria-labelledby="card-title">
<Card.Header>
<Card.Title id="card-title">Article Title</Card.Title>
</Card.Header>
</Card>
</Card.Root>
// Interactive cards
<Card asChild>
<Card.Root asChild>
<a href="/details" aria-label="View product details">
<Card.Title>Product Name</Card.Title>
</a>
</Card>
</Card.Root>
```
## Styling
@@ -97,7 +98,7 @@ export default () => (
### Component Customization
```tsx
<Card className="border-2 border-blue-500 bg-gradient-to-r from-blue-50 to-purple-50">
<Card.Root className="border-2 border-blue-500 bg-gradient-to-r from-blue-50 to-purple-50">
<Card.Header>
<Card.Title className="text-blue-900">Custom Styled Card</Card.Title>
<Card.Description className="text-blue-700">Custom colors applied</Card.Description>
@@ -105,7 +106,7 @@ export default () => (
<Card.Content>
<p className="text-blue-800">Content with custom styling</p>
</Card.Content>
</Card>
</Card.Root>
```
### CSS Variable Overrides
@@ -145,7 +146,7 @@ Card uses BEM naming for predictable styling, ([View source styles](https://gith
## API Reference
### Card
### Card.Root
| Prop | Type | Default | Description |
| ----------- | --------------------------------------------------------- | ------------ | -------------------------- |
@@ -1,7 +1,6 @@
---
title: Description
description: Provides supplementary text for form fields and other components
icon: new
links:
rac: TextField
source: description/description.tsx
@@ -1,6 +1,7 @@
---
title: DisclosureGroup
description: Container that manages multiple Disclosure items with coordinated expanded states
icon: updated
links:
rac: DisclosureGroup
source: disclosure-group/disclosure-group.tsx
@@ -30,14 +31,14 @@ import {DisclosureGroup, Disclosure} from '@heroui/react';
export default () => (
<DisclosureGroup>
<Disclosure id="item1">
<Disclosure.Root id="item1">
<Disclosure.Heading>
<Disclosure.Trigger>
<Disclosure.Indicator />
</Disclosure.Trigger>
</Disclosure.Heading>
<Disclosure.Content />
</Disclosure>
</Disclosure.Root>
</DisclosureGroup>
)
```
@@ -59,18 +60,23 @@ You can control which disclosures are expanded with external navigation controls
### Passing Tailwind CSS classes
```tsx
import {DisclosureGroup, Disclosure} from '@heroui/react';
import {
DisclosureGroup,
Disclosure,
DisclosureTrigger,
DisclosurePanel
} from '@heroui/react';
function CustomDisclosureGroup() {
return (
<DisclosureGroup className="border rounded-lg p-4 space-y-2">
<Disclosure id="first" className="border-b pb-2">
<Disclosure.Trigger>Item 1</Disclosure.Trigger>
<Disclosure.Content>Content 1</Disclosure.Content>
<DisclosureTrigger>Item 1</DisclosureTrigger>
<DisclosurePanel>Content 1</DisclosurePanel>
</Disclosure>
<Disclosure id="second">
<Disclosure.Trigger>Item 2</Disclosure.Trigger>
<Disclosure.Content>Content 2</Disclosure.Content>
<DisclosureTrigger>Item 2</DisclosureTrigger>
<DisclosurePanel>Content 2</DisclosurePanel>
</Disclosure>
</DisclosureGroup>
);
@@ -1,6 +1,7 @@
---
title: Disclosure
description: A disclosure is a collapsible section with a header containing a heading and a trigger button, and a panel that wraps the content.
icon: updated
links:
rac: Disclosure
source: disclosure/disclosure.tsx
@@ -12,7 +13,7 @@ links:
## Import
```tsx
import {Disclosure} from '@heroui/react';
import { Disclosure } from '@heroui/react';
```
### Usage
@@ -23,20 +24,20 @@ import {Disclosure} from '@heroui/react';
### Anatomy
Import all parts and piece them together.
Import the Disclosure component and access all parts using dot notation.
```tsx
import { Disclosure } from '@heroui/react';
export default () => (
<Disclosure>
<Disclosure.Root>
<Disclosure.Heading>
<Disclosure.Trigger>
<Disclosure.Indicator />
</Disclosure.Trigger>
</Disclosure.Heading>
<Disclosure.Content/>
</Disclosure>
</Disclosure.Root>
)
```
@@ -51,15 +52,19 @@ import { Disclosure } from '@heroui/react';
function CustomDisclosure() {
return (
<Disclosure className="border rounded-lg p-4">
<Disclosure.Trigger className="text-lg font-semibold">
Click to expand
<Disclosure.Indicator className="ml-2" />
</Disclosure.Trigger>
<Disclosure.Content className="mt-4 text-gray-600">
Hidden content
<Disclosure.Root className="border rounded-lg p-4">
<Disclosure.Heading>
<Disclosure.Trigger className="text-lg font-semibold">
Click to expand
<Disclosure.Indicator />
</Disclosure.Trigger>
</Disclosure.Heading>
<Disclosure.Content>
<Disclosure.Body className="mt-4 text-gray-600">
Hidden content
</Disclosure.Body>
</Disclosure.Content>
</Disclosure>
</Disclosure.Root>
);
}
```
@@ -114,7 +119,7 @@ The component supports both CSS pseudo-classes and data attributes for flexibili
## API Reference
### Disclosure Props
### Disclosure.Root Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
@@ -124,28 +129,20 @@ The component supports both CSS pseudo-classes and data attributes for flexibili
| `children` | `ReactNode \| RenderFunction` | - | Content to render |
| `className` | `string` | - | Additional CSS classes |
### Disclosure.Trigger Props
### DisclosureTrigger Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `children` | `ReactNode \| RenderFunction` | - | Trigger content |
| `className` | `string` | - | Additional CSS classes |
| `slot` | `string` | `"trigger"` | Slot name for React Aria |
### Disclosure.Content Props
### DisclosurePanel Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `children` | `ReactNode` | - | Content to show/hide |
| `className` | `string` | - | Additional CSS classes |
### Disclosure.Indicator Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `children` | `ReactElement` | `<IconChevronDown />` | Custom indicator element |
| `className` | `string` | - | Additional CSS classes |
### RenderProps
When using the render prop pattern, these values are provided:
@@ -1,7 +1,6 @@
---
title: FieldError
description: Displays validation error messages for form fields
icon: new
links:
rac: FieldError
source: field-error/field-error.tsx
+9 -13
View File
@@ -1,7 +1,7 @@
---
title: Fieldset
description: Group related form controls with legends, descriptions, and actions
icon: new
icon: updated
links:
source: fieldset/fieldset.tsx
styles: fieldset.css
@@ -20,13 +20,13 @@ import { Fieldset } from '@heroui/react';
### Anatomy
Import all parts and piece them together.
Import the Fieldset component and access all parts using dot notation.
```tsx
import {Fieldset} from '@heroui/react';
import { Fieldset } from '@heroui/react';
export default () => (
<Fieldset>
<Fieldset.Root>
<Fieldset.Legend />
<Fieldset.Group>
{/* form fields go here */}
@@ -34,7 +34,7 @@ export default () => (
<Fieldset.Actions>
{/* action buttons go here */}
</Fieldset.Actions>
</Fieldset>
</Fieldset.Root>
)
```
@@ -47,11 +47,11 @@ export default () => (
### Passing Tailwind CSS classes
```tsx
import {Fieldset, TextField} from '@heroui/react';
import { Fieldset, TextField, Label, Input } from '@heroui/react';
function CustomFieldset() {
return (
<Fieldset className="rounded-xl border border-border bg-surface-2 p-6 shadow-sm">
<Fieldset.Root className="rounded-xl border border-border bg-surface-2 p-6 shadow-sm">
<Fieldset.Legend className="text-lg font-semibold">Team members</Fieldset.Legend>
<Fieldset.Group className="grid gap-4 md:grid-cols-2">
<TextField>
@@ -66,7 +66,7 @@ function CustomFieldset() {
<Fieldset.Actions className="justify-end gap-3">
{/* Action buttons */}
</Fieldset.Actions>
</Fieldset>
</Fieldset.Root>
);
}
```
@@ -106,14 +106,13 @@ The Fieldset compound component exposes these CSS selectors:
## API Reference
### Fieldset Props
### Fieldset.Root Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `asChild` | `boolean` | `false` | Render the fieldset as a custom component via `Slot`. |
| `className` | `string` | - | Tailwind CSS classes applied to the root element. |
| `children` | `React.ReactNode` | - | Fieldset content (legend, groups, descriptions, actions). |
| `ref` | `React.Ref<HTMLFieldSetElement>` | - | Ref forwarded to the fieldset element. |
| `nativeProps` | `React.HTMLAttributes<HTMLFieldSetElement>` | Supports native fieldset attributes and events. |
### Fieldset.Legend Props
@@ -123,7 +122,6 @@ The Fieldset compound component exposes these CSS selectors:
| `asChild` | `boolean` | `false` | Render the legend as another component with `Slot`. |
| `className` | `string` | - | Tailwind classes for the legend element. |
| `children` | `React.ReactNode` | - | Legend content, usually plain text. |
| `ref` | `React.Ref<HTMLLegendElement>` | - | Ref forwarded to the legend element. |
| `nativeProps` | `React.HTMLAttributes<HTMLLegendElement>` | - | Native legend attributes. |
### Fieldset.Group Props
@@ -133,7 +131,6 @@ The Fieldset compound component exposes these CSS selectors:
| `asChild` | `boolean` | `false` | Render the group as a different component. |
| `className` | `string` | - | Layout and spacing classes for grouped fields. |
| `children` | `React.ReactNode` | - | Form controls to group inside the fieldset. |
| `ref` | `React.Ref<HTMLDivElement>` | - | Ref forwarded to the group wrapper. |
| `nativeProps` | `React.HTMLAttributes<HTMLDivElement>` | - | Native div attributes. |
### Fieldset.Actions Props
@@ -143,5 +140,4 @@ The Fieldset compound component exposes these CSS selectors:
| `asChild` | `boolean` | `false` | Render the actions container as a custom component. |
| `className` | `string` | - | Tailwind classes to align action buttons or text. |
| `children` | `React.ReactNode` | - | Action buttons or helper text. |
| `ref` | `React.Ref<HTMLDivElement>` | - | Ref forwarded to the actions container. |
| `nativeProps` | `React.HTMLAttributes<HTMLDivElement>` | - | Native div attributes. |
@@ -1,7 +1,6 @@
---
title: Form
description: Wrapper component for form validation and submission handling
icon: new
links:
source: form/form.tsx
rac: https://react-spectrum.adobe.com/react-aria/Form.html
@@ -76,7 +75,6 @@ The Form component is a wrapper around React Aria's Form primitive that provides
| `onInvalid` | `(event: FormEvent<HTMLFormElement>) => void` | - | Handler called when the form validation fails. By default, the first invalid field will be focused. Use `preventDefault()` to customize focus behavior. |
| `onReset` | `(event: FormEvent<HTMLFormElement>) => void` | - | Handler called when the form is reset. |
| `onSubmit` | `(event: FormEvent<HTMLFormElement>) => void` | - | Handler called when the form is submitted. |
| `ref` | `React.Ref<HTMLFormElement>` | - | Ref forwarded to the form element. |
| `target` | `'_self' \| '_blank' \| '_parent' \| '_top'` | - | Where to display the response after submitting the form. |
| `validationBehavior` | `'native' \| 'aria'` | `'native'` | Whether to use native HTML validation or ARIA validation. 'native' blocks form submission, 'aria' displays errors in realtime. |
| `validationErrors` | `ValidationErrors` | - | Server-side validation errors mapped by field name. Displayed immediately and cleared when user modifies the field. |
@@ -1,7 +1,6 @@
---
title: Input
description: Primitive single-line text input component that accepts standard HTML attributes
icon: new
links:
rac: Input
source: input/input.tsx
@@ -117,6 +116,5 @@ Input accepts all standard HTML `<input>` attributes plus the following:
| `min` | `number \| string` | - | Minimum value (for number/date inputs). |
| `max` | `number \| string` | - | Maximum value (for number/date inputs). |
| `step` | `number \| string` | - | Stepping interval (for number inputs). |
| `ref` | `React.Ref<HTMLInputElement>` | - | Ref forwarded to the input element. |
> For validation props like `isInvalid`, `isRequired`, and error handling, use **[TextField](/docs/components/text-field)** with Input as a child component.
+15 -13
View File
@@ -1,6 +1,7 @@
---
title: Kbd
description: Display keyboard shortcuts and key combinations
icon: updated
links:
source: kbd/kbd.tsx
styles: kbd.css
@@ -11,7 +12,7 @@ links:
## Import
```tsx
import {Kbd} from "@heroui/react";
import { Kbd } from "@heroui/react";
```
### Usage
@@ -22,16 +23,16 @@ import {Kbd} from "@heroui/react";
### Anatomy
Import all parts and piece them together.
Import the Kbd component and access all parts using dot notation.
```tsx
import {Kbd} from "@heroui/react";
import { Kbd } from "@heroui/react";
export default () => (
<Kbd>
<Kbd.Abbr keyValue="command" />
<Kbd.Root>
<Kbd.Abbr title="Command">⌘</Kbd.Abbr>
<Kbd.Content>K</Kbd.Content>
</Kbd>
</Kbd.Root>
);
```
@@ -64,13 +65,13 @@ export default () => (
### Passing Tailwind CSS classes
```tsx
import {Kbd} from "@heroui/react";
import { Kbd } from "@heroui/react";
function CustomKbd() {
return (
<Kbd className="bg-gray-100 dark:bg-gray-800">
<Kbd.Root className="bg-gray-100 dark:bg-gray-800">
<Kbd.Content>K</Kbd.Content>
</Kbd>
</Kbd.Root>
);
}
```
@@ -110,7 +111,7 @@ The Kbd component uses these CSS classes ([View source styles](https://github.co
## API Reference
### Kbd Props
### Kbd.Root Props
| Prop | Type | Default | Description |
| ----------- | ----------------- | ------- | ---------------------- |
@@ -121,17 +122,18 @@ The Kbd component uses these CSS classes ([View source styles](https://github.co
| Prop | Type | Default | Description |
| ----------- | -------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `keyValue` | `KbdKey` | - | The keyboard key to display. Available values include modifier keys and special keys |
| `title` | `string` | - | Title attribute for accessibility (e.g., "Command" for ⌘) |
| `children` | `React.ReactNode` | - | The symbol or text to display (e.g., ⌘, ⌥, ⇧) |
| `className` | `string` | - | Custom CSS classes |
### Kbd.Content Props
### Kbd.Key Props
| Prop | Type | Default | Description |
| ----------- | ----------------- | ------- | ---------------------------------- |
| `children` | `React.ReactNode` | - | Text content of the key |
| `className` | `string` | - | Custom CSS classes |
### KbdKey Type
### Kbd.Content Type
Available key values for the `keyValue` prop:
@@ -1,7 +1,6 @@
---
title: Label
description: Renders an accessible label associated with form controls
icon: new
links:
rac: TextField
source: label/label.tsx
+8 -8
View File
@@ -24,16 +24,16 @@ import { Link } from '@heroui/react';
### Anatomy
Import all parts and piece them together.
Import the Link component and access all parts using dot notation.
```tsx
import {Link} from '@heroui/react';
import { Link } from '@heroui/react';
export default () => (
<Link href="#">
<Link.Root href="#">
Call to action
<Link.Icon />
</Link>
</Link.Root>
);
```
@@ -54,16 +54,16 @@ export default () => (
### Passing Tailwind CSS classes
```tsx
import {Link} from '@heroui/react';
import { Link } from '@heroui/react';
function CustomLink() {
return (
<Link
<Link.Root
href="#"
className="text-lg font-bold text-accent hover:text-accent/80"
>
Custom styled link
</Link>
</Link.Root>
);
}
```
@@ -99,7 +99,7 @@ The component supports both CSS pseudo-classes and data attributes for flexibili
## API Reference
### Link Props
### Link.Root Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
+12 -16
View File
@@ -1,6 +1,7 @@
---
title: Popover
description: Displays rich content in a portal triggered by a button or any custom element
icon: updated
links:
rac: Popover
source: popover/popover.tsx
@@ -22,13 +23,13 @@ import { Popover } from '@heroui/react';
### Anatomy
Import all parts and piece them together.
Import the Popover component and access all parts using dot notation.
```tsx
import { Popover } from '@heroui/react';
export default () => (
<Popover>
<Popover.Root>
<Popover.Trigger/>
<Popover.Content>
<Popover.Arrow />
@@ -37,7 +38,7 @@ export default () => (
{/* content goes here */}
</Popover.Dialog>
</Popover.Content>
</Popover>
</Popover.Root>
)
```
@@ -64,19 +65,21 @@ export default () => (
### Passing Tailwind CSS classes
```tsx
import {Popover, Button} from '@heroui/react';
import { Popover, Button } from '@heroui/react';
function CustomPopover() {
return (
<Popover>
<Button>Open</Button>
<Popover.Root>
<Popover.Trigger>
<Button>Open</Button>
</Popover.Trigger>
<Popover.Content className="bg-accent text-accent-foreground">
<Popover.Dialog>
<Popover.Heading>Custom Styled</Popover.Heading>
<h3>Custom Styled</h3>
<p>This popover has custom styling</p>
</Popover.Dialog>
</Popover.Content>
</Popover>
</Popover.Root>
);
}
```
@@ -125,7 +128,7 @@ The component supports animation states:
## API Reference
### Popover Props
### Popover.Root Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
@@ -158,13 +161,6 @@ The component supports animation states:
| `children` | `React.ReactNode` | - | Element that triggers the popover |
| `className` | `string` | - | Additional CSS classes |
### Popover.Heading Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `children` | `React.ReactNode` | - | Heading text content |
| `className` | `string` | - | Additional CSS classes |
### Popover.Arrow Props
| Prop | Type | Default | Description |
@@ -1,7 +1,7 @@
---
title: RadioGroup
description: Radio group for selecting a single option from a list
icon: new
icon: updated
links:
rac: RadioGroup
source: radio-group/radio-group.tsx
@@ -24,7 +24,7 @@ import { RadioGroup, Radio } from '@heroui/react';
### Anatomy
Import all parts and piece them together.
Import the RadioGroup component and access all parts using dot notation.
```tsx
import {RadioGroup, Radio, Label, Description, FieldError} from '@heroui/react';
@@ -33,7 +33,7 @@ export default () => (
<RadioGroup>
<Label />
<Description />
<Radio value="option1">
<Radio.Root value="option1">
<Radio.Control>
<Radio.Indicator>
<span>✓</span> {/* Custom indicator (optional) */}
@@ -43,7 +43,7 @@ export default () => (
<Label />
<Description />
</Radio.Content>
</Radio>
</Radio.Root>
<FieldError />
</RadioGroup>
)
@@ -103,52 +103,31 @@ Combine `defaultValue` with `onChange` when you only need to react to updates.
### Passing Tailwind CSS classes
```tsx
import {RadioGroup, Radio, Label, Description} from '@heroui/react';
import { RadioGroup, Radio } from '@heroui/react';
export default () => (
<RadioGroup defaultValue="premium" name="plan">
<Label>Plan selection</Label>
<Description>Choose the plan that best suits your needs</Description>
<Radio
<Radio.Root
className="border-border group cursor-pointer rounded-xl border-2 p-4 hover:border-blue-300 data-[selected=true]:border-blue-500 data-[selected=true]:bg-blue-500/10"
value="basic"
>
<Radio.Control className="border-border border-2 group-hover:border-blue-400 group-data-[selected=true]:border-blue-500 group-data-[selected=true]:bg-blue-500">
<Radio.Indicator />
</Radio.Control>
<Radio.Content>
<Label className="cursor-pointer font-semibold">Basic Plan</Label>
<Description className="text-sm">
Includes 100 messages per month and up to 3 themes to set up
</Description>
</Radio.Content>
</Radio>
<Radio
<Radio.Indicator className="border-border border-2 group-hover:border-blue-400 group-data-[selected=true]:border-blue-500 group-data-[selected=true]:bg-blue-500" />
Basic Plan
</Radio.Root>
<Radio.Root
className="border-border group cursor-pointer rounded-xl border-2 p-4 hover:border-purple-300 data-[selected=true]:border-purple-500 data-[selected=true]:bg-purple-500/10"
value="premium"
>
<Radio.Control className="border-border border-2 group-hover:border-purple-400 group-data-[selected=true]:border-purple-500 group-data-[selected=true]:bg-purple-500">
<Radio.Indicator />
</Radio.Control>
<Radio.Content>
<Label className="cursor-pointer font-semibold">Premium Plan</Label>
<Description className="text-sm">
Includes 200 messages per month and up to 6 themes to set up
</Description>
</Radio.Content>
</Radio>
<Radio
<Radio.Indicator className="border-border border-2 group-hover:border-purple-400 group-data-[selected=true]:border-purple-500 group-data-[selected=true]:bg-purple-500" />
Premium Plan
</Radio.Root>
<Radio.Root
className="border-border group cursor-pointer rounded-xl border-2 p-4 hover:border-emerald-300 data-[selected=true]:border-emerald-500 data-[selected=true]:bg-emerald-500/10"
value="business"
>
<Radio.Control className="border-border border-2 group-hover:border-emerald-400 group-data-[selected=true]:border-emerald-500 group-data-[selected=true]:bg-emerald-500">
<Radio.Indicator />
</Radio.Control>
<Radio.Content>
<Label className="cursor-pointer font-semibold">Business Plan</Label>
<Description className="text-sm">Unlimited messages and themes</Description>
</Radio.Content>
</Radio>
<Radio.Indicator className="border-border border-2 group-hover:border-emerald-400 group-data-[selected=true]:border-emerald-500 group-data-[selected=true]:bg-emerald-500" />
Business Plan
</Radio.Root>
</RadioGroup>
);
```
@@ -226,7 +205,7 @@ The radio supports both CSS pseudo-classes and data attributes for flexibility:
| `orientation` | `'horizontal' \| 'vertical'` | `'vertical'` | The orientation of the radio group |
| `children` | `React.ReactNode \| (values: RadioGroupRenderProps) => React.ReactNode` | - | Radio group content or render prop |
### Radio Props
### Radio.Root Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
@@ -241,7 +220,7 @@ Extends `React.HTMLAttributes<HTMLSpanElement>`.
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `children` | `React.ReactNode` | - | Content to render inside the control, typically `Radio.Indicator`. |
| `children` | `React.ReactNode` | - | The content to render inside the control wrapper (typically Radio.Indicator) |
### Radio.Indicator Props
@@ -257,7 +236,7 @@ Extends `React.HTMLAttributes<HTMLDivElement>`.
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `children` | `React.ReactNode` | - | Content displayed next to the control, usually `Label` and `Description`. |
| `children` | `React.ReactNode` | - | The content to render inside the content wrapper (typically Label and Description) |
### RadioRenderProps
+74 -20
View File
@@ -1,6 +1,7 @@
---
title: Switch
description: A toggle switch component for boolean states
icon: updated
links:
rac: Switch
source: switch/switch.tsx
@@ -12,7 +13,7 @@ links:
## Import
```tsx
import { Switch, SwitchGroup } from '@heroui/react';
import { Switch, SwitchGroup, Label } from '@heroui/react';
```
### Usage
@@ -23,19 +24,43 @@ import { Switch, SwitchGroup } from '@heroui/react';
### Anatomy
Import all parts and piece them together.
Import the Switch component and access all parts using dot notation.
```tsx
import {Switch} from '@heroui/react';
import { Switch, Label } from '@heroui/react';
export default () => (
<Switch>
<Switch.Root>
<Switch.Control>
<Switch.Thumb>
<Switch.Icon /> {/* Optional */}
<Switch.Icon/> {/* Optional */}
</Switch.Thumb>
</Switch.Control>
</Switch>
<Label/> {/* Optional */}
</Switch.Root>
);
```
For grouping multiple switches, use the `SwitchGroup` component:
```tsx
import { Switch, SwitchGroup, Label } from '@heroui/react';
export default () => (
<SwitchGroup>
<Switch.Root>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label>Option 1</Label>
</Switch.Root>
<Switch.Root>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label>Option 2</Label>
</Switch.Root>
</SwitchGroup>
);
```
@@ -121,12 +146,14 @@ export default () => (
### Passing Tailwind CSS classes
You can customize individual Switch components:
```tsx
import { Switch, Label } from '@heroui/react';
function CustomSwitch() {
return (
<Switch>
<Switch.Root>
{({isSelected}) => (
<>
<Switch.Control
@@ -134,18 +161,37 @@ function CustomSwitch() {
>
<Switch.Thumb
className={`size-[27px] bg-white shadow-sm ${isSelected ? "translate-x-5 shadow-lg" : ""}`}
>
<Switch.Icon>
<Icon
className={`size-4 ${isSelected ? "text-cyan-600" : "text-blue-600"}`}
icon={isSelected ? "gravity-ui:check" : "gravity-ui:power"}
/>
</Switch.Icon>
</Switch.Thumb>
/>
</Switch.Control>
<Label>Custom Switch</Label>
</>
)}
</Switch>
</Switch.Root>
);
}
```
Or customize the SwitchGroup layout:
```tsx
import { Switch, SwitchGroup, Label } from '@heroui/react';
function CustomSwitchGroup() {
return (
<SwitchGroup className="gap-8" orientation="horizontal">
<Switch.Root>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label>Option 1</Label>
</Switch.Root>
<Switch.Root>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label>Option 2</Label>
</Switch.Root>
</SwitchGroup>
);
}
```
@@ -179,19 +225,26 @@ HeroUI follows the [BEM](https://getbem.com/) methodology to ensure component va
### CSS Classes
#### Switch Classes
The Switch component uses these CSS classes ([View source styles](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/switch.css)):
#### Base Classes
- `.switch` - Base switch container
- `.switch__control` - Switch control track
- `.switch__thumb` - Switch thumb that moves
- `.switch__icon` - Optional icon inside the thumb
- `.switch--sm` - Small size variant
- `.switch--md` - Medium size variant (default)
- `.switch--lg` - Large size variant
#### SwitchGroup Classes
The SwitchGroup component uses these CSS classes ([View source styles](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/switch-group.css)):
#### Group Classes
- `.switch-group` - Switch group container
- `.switch-group__items` - Container for switch items
- `.switch-group--horizontal` - Horizontal layout
- `.switch-group--vertical` - Vertical layout
- `.switch-group--vertical` - Vertical layout (default)
### Interactive States
@@ -205,7 +258,7 @@ The switch supports both CSS pseudo-classes and data attributes for flexibility:
## API Reference
### Switch Props
### Switch.Root Props
Inherits from [React Aria Switch](https://react-spectrum.adobe.com/react-aria/Switch.html).
@@ -242,3 +295,4 @@ When using the render prop pattern, these values are provided:
|------|------|---------|-------------|
| `orientation` | `'horizontal' \| 'vertical'` | `'vertical'` | The orientation of the switch group |
| `children` | `React.ReactNode` | - | The switch items to render |
| `className` | `string` | - | Additional CSS class names |
+11 -10
View File
@@ -1,6 +1,7 @@
---
title: Tabs
description: Tabs organize content into multiple sections and allow users to navigate between them.
icon: updated
links:
rac: Tabs
source: tabs/tabs.tsx
@@ -24,13 +25,13 @@ import { Tabs } from '@heroui/react';
### Anatomy
Import all parts and piece them together.
Import the Tabs component and access all parts using dot notation.
```tsx
import { Tabs } from '@heroui/react';
export default () => (
<Tabs>
<Tabs.Root>
<Tabs.ListWrapper>
<Tabs.List aria-label="Options">
<Tabs.Tab>
@@ -39,7 +40,7 @@ export default () => (
</Tabs.List>
</Tabs.ListWrapper>
<Tabs.Panel/>
</Tabs>
</Tabs.Root>
)
```
@@ -75,16 +76,16 @@ import { Tabs } from '@heroui/react';
function CustomTabs() {
return (
<Tabs className="w-full max-w-lg text-center">
<Tabs.Root className="w-full max-w-lg text-center">
<Tabs.ListWrapper>
<Tabs.List
aria-label="Options"
className="*:data-[selected=true]:text-accent-foreground w-fit *:h-6 *:w-fit *:px-3 *:text-sm *:font-normal"
>
<Tabs.Tab id="daily">Daily</Tabs.Tab>
<Tabs.Tab id="weekly">Weekly</Tabs.Tab>
<Tabs.Tab id="bi-weekly">Bi-Weekly</Tabs.Tab>
<Tabs.Tab id="monthly">Monthly</Tabs.Tab>
<Tabs.Tab id="daily">Daily<Tabs.Indicator /></Tabs.Tab>
<Tabs.Tab id="weekly">Weekly<Tabs.Indicator /></Tabs.Tab>
<Tabs.Tab id="bi-weekly">Bi-Weekly<Tabs.Indicator /></Tabs.Tab>
<Tabs.Tab id="monthly">Monthly<Tabs.Indicator /></Tabs.Tab>
</Tabs.List>
</Tabs.ListWrapper>
<Tabs.Panel className="px-4" id="daily">
@@ -103,7 +104,7 @@ function CustomTabs() {
<h3 className="mb-2 font-semibold">Monthly</h3>
<p className="text-sm text-gray-600">Manage your monthly tasks and goals.</p>
</Tabs.Panel>
</Tabs>
</Tabs.Root>
);
}
`} />
@@ -137,7 +138,7 @@ The component supports both CSS pseudo-classes and data attributes:
## API Reference
### Tabs Props
### Tabs.Root Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
@@ -1,7 +1,6 @@
---
title: TextField
description: Composition-friendly text fields with labels, descriptions, and inline validation
icon: new
links:
rac: TextField
source: text-field/text-field.tsx
@@ -1,7 +1,6 @@
---
title: TextArea
description: Primitive multiline text input component that accepts standard HTML attributes
icon: new
links:
rac: TextArea
source: textarea/textarea.tsx
@@ -118,6 +117,5 @@ TextArea accepts all standard HTML `<textarea>` attributes plus the following:
| `maxLength` | `number` | - | Maximum number of characters. |
| `minLength` | `number` | - | Minimum number of characters. |
| `wrap` | `'soft' \| 'hard'` | - | How text wraps when submitted. |
| `ref` | `React.Ref<HTMLTextAreaElement>` | - | Ref forwarded to the textarea element. |
> For validation props like `isInvalid`, `isRequired`, and error handling, use **[TextField](/docs/components/text-field)** with TextArea as a child component.
+11 -8
View File
@@ -1,6 +1,7 @@
---
title: Tooltip
description: Displays informative text when users hover over or focus on an element
icon: updated
links:
rac: Tooltip
source: tooltip/tooltip.tsx
@@ -23,13 +24,13 @@ import { Tooltip } from '@heroui/react';
### Anatomy
Import all parts and piece them together.
Import the Tooltip component and access all parts using dot notation.
```tsx
import { Tooltip } from '@heroui/react';
export default () => (
<Tooltip>
<Tooltip.Root>
<Tooltip.Trigger>
<button>Hover for tooltip</button>
</Tooltip.Trigger>
@@ -37,7 +38,7 @@ export default () => (
<Tooltip.Arrow />
Helpful information about this element
</Tooltip.Content>
</Tooltip>
</Tooltip.Root>
)
```
@@ -64,16 +65,18 @@ export default () => (
### Passing Tailwind CSS classes
```tsx
import {Tooltip, Button} from '@heroui/react';
import { Tooltip, Button } from '@heroui/react';
function CustomTooltip() {
return (
<Tooltip>
<Button>Hover me</Button>
<Tooltip.Root>
<Tooltip.Trigger>
<Button>Hover me</Button>
</Tooltip.Trigger>
<Tooltip.Content className="bg-accent text-accent-foreground">
<p>Custom styled tooltip</p>
</Tooltip.Content>
</Tooltip>
</Tooltip.Root>
);
}
```
@@ -115,7 +118,7 @@ The component supports animation states:
## API Reference
### Tooltip Props
### Tooltip.Root Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
+40 -20
View File
@@ -43,13 +43,15 @@ Built on [React Aria Components](https://react-spectrum.adobe.com/react-aria/) f
```tsx
// Automatic ARIA attributes, keyboard navigation, and focus management
import { Tabs, TabList, Tab, TabPanel } from '@heroui/react';
<Tabs defaultSelectedKey="profile">
<Tabs.List aria-label="Settings">
<Tabs.Tab id="profile">Profile</Tabs.Tab>
<Tabs.Tab id="security">Security</Tabs.Tab>
</Tabs.List>
<Tabs.Panel id="profile">Content</Tabs.Panel>
<Tabs.Panel id="security">Content</Tabs.Panel>
<TabList aria-label="Settings">
<Tab id="profile">Profile</Tab>
<Tab id="security">Security</Tab>
</TabList>
<TabPanel id="profile">Content</TabPanel>
<TabPanel id="security">Content</TabPanel>
</Tabs>
```
@@ -59,18 +61,28 @@ Compound components let you rearrange, customize, or omit parts as needed.
```tsx
// Compose parts to build exactly what you need
import {
Accordion,
AccordionItem,
AccordionHeading,
AccordionTrigger,
AccordionIndicator,
AccordionPanel,
AccordionBody
} from '@heroui/react';
<Accordion>
<Accordion.Item id="1">
<Accordion.Heading>
<Accordion.Trigger>
<AccordionItem id="1">
<AccordionHeading>
<AccordionTrigger>
Question Text
<Accordion.Indicator />
</Accordion.Trigger>
</Accordion.Heading>
<Accordion.Panel>
<Accordion.Body>Answer content</Accordion.Body>
</Accordion.Panel>
</Accordion.Item>
<AccordionIndicator />
</AccordionTrigger>
</AccordionHeading>
<AccordionPanel>
<AccordionBody>Answer content</AccordionBody>
</AccordionPanel>
</AccordionItem>
</Accordion>
```
@@ -104,10 +116,18 @@ Consistent patterns across all components: sizes (`sm`, `md`, `lg`), variants, c
<Chip size="lg" variant="success" className="custom" />
<Avatar size="lg" className="custom" />
// Compound components use dot notation
<Alert.Icon />
<Card.Header />
<Accordion.Trigger />
// Compound components support both named exports and dot notation
import { Alert, AlertIcon, CardHeader, AccordionTrigger } from '@heroui/react';
// Named exports
<Alert>
<AlertIcon />
</Alert>
// Dot notation (requires .Root)
<Alert.Root>
<Alert.Icon />
</Alert.Root>
```
### 6. Type Safety First
+48 -13
View File
@@ -38,28 +38,60 @@ import Link from 'next/link';
These components support `asChild`:
- `Button` - Change button element
- `Alert` parts - Root, Icon, Content, Title, Description, Action, Close
- `Avatar` - Change root element
- `Alert` and its parts - `Alert`, `AlertIcon`, `AlertContent`, `AlertTitle`, `AlertDescription`, `AlertAction`, `AlertClose`
- `Avatar` and its parts - `Avatar`, `AvatarImage`, `AvatarFallback`
- More components coming soon
## Compound Components
HeroUI components are built as compound components - they export multiple parts that work together:
HeroUI components are built as compound components - they export multiple parts that work together. You can use them in two ways:
### Option 1: Named Exports (Recommended)
Import each part separately:
```tsx
import {
Alert,
AlertIcon,
AlertContent,
AlertTitle,
AlertDescription,
AlertClose
} from '@heroui/react';
<Alert>
<AlertIcon />
<AlertContent>
<AlertTitle>Success</AlertTitle>
<AlertDescription>Your changes have been saved.</AlertDescription>
</AlertContent>
<AlertClose />
</Alert>
```
### Option 2: Dot Notation (Compound Pattern)
Import the main component and access parts via dot notation:
```tsx
import { Alert } from '@heroui/react';
<Alert>
<Alert.Root>
<Alert.Icon />
<Alert.Content>
<Alert.Title>Success</Alert.Title>
<Alert.Description>Your changes have been saved.</Alert.Description>
</Alert.Content>
<Alert.Close />
</Alert>
</Alert.Root>
```
This pattern provides:
**Note:** When using dot notation, the main component requires `.Root` suffix (e.g., `<Alert.Root>` instead of `<Alert>`).
### Benefits of Compound Components
Both patterns provide:
- **Flexibility** - Arrange parts as needed
- **Customization** - Style each part independently
@@ -74,7 +106,7 @@ HeroUI exports variant functions that can be applied to any component. This allo
Apply button styles to any component:
```tsx
import { Link, buttonVariants } from '@heroui/react';
import { Link, LinkIcon, buttonVariants } from '@heroui/react';
// Link styled as a tertiary button
<Link
@@ -87,7 +119,7 @@ import { Link, buttonVariants } from '@heroui/react';
target="_blank"
>
HeroUI
<Link.Icon className="h-2 w-2" />
<LinkIcon className="h-2 w-2" />
</Link>
// Native anchor styled as primary button
@@ -128,11 +160,14 @@ function LinkButton({ href, children, ...props }) {
// Icon button with tooltip
function IconButton({ icon, label, ...props }) {
return (
<Tooltip content={label}>
<Button isIconOnly {...props}>
<Icon icon={icon} />
</Button>
</Tooltip>
<Tooltip.Root>
<Tooltip.Trigger>
<Button isIconOnly {...props}>
<Icon icon={icon} />
</Button>
</Tooltip.Trigger>
<Tooltip.Content>{label}</Tooltip.Content>
</Tooltip.Root>
);
}
```
+11 -8
View File
@@ -1,5 +1,5 @@
import {buttonVariants} from "@heroui/react";
import Link from "fumadocs-core/link";
import LinkRoot from "fumadocs-core/link";
// TODO:
import {Iconify} from "@/components/iconify";
@@ -9,14 +9,14 @@ import {currentVersion} from "@/utils/version";
const VersionChip = () => {
return (
<Link
<LinkRoot
className="chip bg-pink-400/8 hover:bg-default/40 rounded-full border-pink-400/20 dark:border-pink-400/10 dark:bg-white/10 dark:hover:bg-pink-400/20"
href="/docs/changelog"
>
<Iconify className="text-pink-400/90" icon="sparkles" />
{/* <span className="bg-gradient-to-r from-[#CA8501] to-[#BD3232] bg-clip-text text-transparent"> */}
<span className="text-pink-400/90">v{currentVersion}: Form Components</span>
</Link>
<span className="text-pink-400/90">v{currentVersion}: RSC Support</span>
</LinkRoot>
);
};
@@ -35,15 +35,18 @@ export default function HomePage() {
skip the copy-paste and focus on building.
</p>
<div className="mt-2 flex gap-3">
<Link className={buttonVariants({class: "shadow-lg", variant: "primary"})} href="/docs">
<LinkRoot
className={buttonVariants({class: "shadow-lg", variant: "primary"})}
href="/docs"
>
Explore Docs
</Link>
<Link
</LinkRoot>
<LinkRoot
className={buttonVariants({class: "bg-default/50", variant: "tertiary"})}
href="/docs/components/accordion"
>
View Components
</Link>
</LinkRoot>
</div>
</div>
{/* <HomeThemeCustomizer /> */}
+3 -3
View File
@@ -17,7 +17,7 @@ interface GenerateProps {
site?: ReactNode;
}
export function generateOGImage(options: GenerateProps & ImageResponseOptions): ImageResponse {
function generateOGImage(options: GenerateProps & ImageResponseOptions): ImageResponse {
const {description, icon, site, title, ...rest} = options;
return new ImageResponse(generate({description, icon, site, title}), {
@@ -27,7 +27,7 @@ export function generateOGImage(options: GenerateProps & ImageResponseOptions):
});
}
export function generate({...props}: GenerateProps): ReactElement {
function generate({...props}: GenerateProps): ReactElement {
return (
<div
style={{
@@ -85,7 +85,7 @@ const [interRegular, interBold] = await Promise.all([
promises.readFile(path.join(process.cwd(), "public/fonts/Inter-Bold.ttf")),
]);
export const GET = async (_req: Request, {params}: RouteContext<"/og/[...slug]">) => {
export const GET = async (_req: Request, {params}: {params: Promise<{slug: string[]}>}) => {
const {slug} = await params;
const page = source.getPage(slug.slice(0, -1));
@@ -3,7 +3,7 @@
import type {ShowcaseItem as ShowcaseItemType} from "@/showcases";
import {chipVariants} from "@heroui/react";
import Link from "next/link";
import LinkRoot from "next/link";
import {useSearchParams} from "next/navigation";
import {Suspense} from "react";
import {tv} from "tailwind-variants";
@@ -108,7 +108,7 @@ export function ShowcaseDetailClient({codePanel, showcase, showcaseId}: Showcase
{/* Center - Show used components */}
<div className="order-1 my-2 flex flex-1 items-center justify-center gap-2 md:order-2 md:my-0">
{showcase.components.map((component) => (
<Link
<LinkRoot
key={component}
href={`/docs/components/${component.toLowerCase().replace(/group$/, "-group")}`}
className={chipVariants({
@@ -117,7 +117,7 @@ export function ShowcaseDetailClient({codePanel, showcase, showcaseId}: Showcase
})}
>
{component}
</Link>
</LinkRoot>
))}
</div>
@@ -1,6 +1,14 @@
"use client";
import {Button, Kbd, Tooltip} from "@heroui/react";
import {
Button,
KbdContent,
KbdRoot,
TooltipArrow,
TooltipContent,
TooltipRoot,
TooltipTrigger,
} from "@heroui/react";
import {useRouter, useSearchParams} from "next/navigation";
import {useEffect} from "react";
@@ -19,7 +27,7 @@ export function ShowcaseHeader() {
const returnUrl = searchParams.get("returnUrl") || "/showcase";
const onClose = () => {
router.push(returnUrl);
router.push(returnUrl as any);
};
useEffect(() => {
@@ -39,39 +47,43 @@ export function ShowcaseHeader() {
return (
<header className="border-border/50 bg-background/50 z-[1] flex items-center justify-between border-b p-4 backdrop-blur-sm">
<div className="flex flex-1 justify-start">
<Tooltip delay={0}>
<Button isIconOnly aria-label="Close" variant="secondary" onPress={onClose}>
<Iconify className="text-foreground/70" icon="xmark" />
</Button>
<Tooltip.Content className="text-muted px-2 py-0.5 text-xs" offset={7} placement="bottom">
<Tooltip.Arrow />
<TooltipRoot delay={0}>
<TooltipTrigger>
<Button isIconOnly aria-label="Close" variant="secondary" onPress={onClose}>
<Iconify className="text-foreground/70" icon="xmark" />
</Button>
</TooltipTrigger>
<TooltipContent className="text-muted px-2 py-0.5 text-xs" offset={7} placement="bottom">
<TooltipArrow />
Press{" "}
<Kbd>
<Kbd.Content className="text-xs">Esc</Kbd.Content>
</Kbd>{" "}
<KbdRoot>
<KbdContent className="text-xs">Esc</KbdContent>
</KbdRoot>{" "}
to close
</Tooltip.Content>
</Tooltip>
</TooltipContent>
</TooltipRoot>
</div>
<div className="flex flex-1 items-center justify-center">
<HeroUILogo className="text-foreground/20" />
</div>
<div className="flex flex-1 items-center justify-end gap-2">
<ShowcaseThemeSwitch />
<Tooltip delay={1500}>
<Button
isIconOnly
aria-label="Toggle showcase code"
variant={isCodeVisible ? "primary" : "secondary"}
onPress={toggleCode}
>
<Iconify className={isCodeVisible ? "" : "text-foreground/70"} icon="code" />
</Button>
<Tooltip.Content offset={7}>
<Tooltip.Arrow />
<TooltipRoot delay={1500}>
<TooltipTrigger>
<Button
isIconOnly
aria-label="Toggle showcase code"
variant={isCodeVisible ? "primary" : "secondary"}
onPress={toggleCode}
>
<Iconify className={isCodeVisible ? "" : "text-foreground/70"} icon="code" />
</Button>
</TooltipTrigger>
<TooltipContent offset={7}>
<TooltipArrow />
<p className="text-muted text-xs">{isCodeVisible ? "Hide code" : "Show code"}</p>
</Tooltip.Content>
</Tooltip>
</TooltipContent>
</TooltipRoot>
{/* TODO: Add this later */}
{/* <Button isIconOnly aria-label="Open showcase in new tab" variant="secondary">
<Iconify className="text-foreground/70" icon="arrow-up-right-from-square" />
@@ -1,6 +1,6 @@
"use client";
import {Button, Tooltip} from "@heroui/react";
import {Button, TooltipArrow, TooltipContent, TooltipRoot, TooltipTrigger} from "@heroui/react";
import React from "react";
import {Iconify} from "@/components/iconify";
@@ -44,21 +44,23 @@ export function ShowcaseThemeSwitch() {
: "Toggle theme";
return (
<Tooltip delay={1500}>
<Button
isIconOnly
aria-label="Toggle showcase theme"
className={cn("border-none", isDisabled && "cursor-not-allowed opacity-50")}
isDisabled={isDisabled}
variant="secondary"
onPress={onPress}
>
<Iconify className="text-foreground/70 m-0" icon={isDark ? "moon" : "sun"} />
</Button>
<Tooltip.Content offset={7}>
<Tooltip.Arrow />
<TooltipRoot delay={1500}>
<TooltipTrigger>
<Button
isIconOnly
aria-label="Toggle showcase theme"
className={cn("border-none", isDisabled && "cursor-not-allowed opacity-50")}
isDisabled={isDisabled}
variant="secondary"
onPress={onPress}
>
<Iconify className="text-foreground/70 m-0" icon={isDark ? "moon" : "sun"} />
</Button>
</TooltipTrigger>
<TooltipContent offset={7}>
<TooltipArrow />
<p className="text-muted text-xs">{tooltipContent}</p>
</Tooltip.Content>
</Tooltip>
</TooltipContent>
</TooltipRoot>
);
}
@@ -6,13 +6,12 @@ import React from "react";
import {
ColorSwatchPicker as AriaColorSwatchPicker,
ColorSwatchPickerItem as AriaColorSwatchPickerItem,
ColorSwatch,
} from "react-aria-components";
import {tv} from "tailwind-variants";
import {composeTailwindRenderProps, focusRing} from "@/utils/compose-tw-render";
import {ColorSwatch} from "./color-swatch";
const itemStyles = tv({
base: "rounded-xs relative",
extend: focusRing,
+2 -2
View File
@@ -43,7 +43,7 @@ const items = [
export function Basic() {
return (
<Accordion className="w-full max-w-md">
<Accordion.Root className="w-full max-w-md">
{items.map((item, index) => (
<Accordion.Item key={index}>
<Accordion.Heading>
@@ -62,6 +62,6 @@ export function Basic() {
</Accordion.Panel>
</Accordion.Item>
))}
</Accordion>
</Accordion.Root>
);
}
@@ -10,7 +10,7 @@ export function CustomIndicator() {
const [expandedKeys, setExpandedKeys] = React.useState<Set<Key>>(new Set([""]));
return (
<Accordion
<Accordion.Root
className="w-full max-w-md"
expandedKeys={expandedKeys}
variant="outline"
@@ -70,6 +70,6 @@ export function CustomIndicator() {
</Accordion.Body>
</Accordion.Panel>
</Accordion.Item>
</Accordion>
</Accordion.Root>
);
}
@@ -28,7 +28,7 @@ const items = [
export function CustomStyles() {
return (
<Accordion className="bg-surface-1/10 w-full max-w-md rounded-2xl" variant="outline">
<Accordion.Root className="bg-surface-1/10 w-full max-w-md rounded-2xl" variant="outline">
{items.map((item, index) => (
<Accordion.Item
key={index}
@@ -61,6 +61,6 @@ export function CustomStyles() {
</Accordion.Panel>
</Accordion.Item>
))}
</Accordion>
</Accordion.Root>
);
}
+4 -4
View File
@@ -7,7 +7,7 @@ export function Disabled() {
<div className="flex w-full flex-col items-center gap-8">
<div className="w-full max-w-md space-y-2">
<h3 className="text-muted text-sm font-medium">Entire accordion disabled</h3>
<Accordion isDisabled className="w-full max-w-md">
<Accordion.Root isDisabled className="w-full max-w-md">
<Accordion.Item>
<Accordion.Heading>
<Accordion.Trigger>
@@ -35,12 +35,12 @@ export function Disabled() {
</Accordion.Body>
</Accordion.Panel>
</Accordion.Item>
</Accordion>
</Accordion.Root>
</div>
<div className="w-full max-w-md space-y-2">
<h3 className="text-muted text-sm font-medium">Individual items disabled</h3>
<Accordion className="w-full max-w-md">
<Accordion.Root className="w-full max-w-md">
<Accordion.Item>
<Accordion.Heading>
<Accordion.Trigger>
@@ -78,7 +78,7 @@ export function Disabled() {
<Accordion.Body>This item is also active and can be toggled.</Accordion.Body>
</Accordion.Panel>
</Accordion.Item>
</Accordion>
</Accordion.Root>
</div>
</div>
);
+2 -2
View File
@@ -58,7 +58,7 @@ export function FAQ() {
{categories.map((category) => (
<div key={category.title}>
<p className="text-muted text-md mb-2 font-medium">{category.title}</p>
<Accordion className="w-full" variant="outline">
<Accordion.Root className="w-full" variant="outline">
{category.items.map((item, index) => (
<Accordion.Item key={index}>
<Accordion.Heading>
@@ -74,7 +74,7 @@ export function FAQ() {
</Accordion.Panel>
</Accordion.Item>
))}
</Accordion>
</Accordion.Root>
</div>
))}
</div>
+2 -2
View File
@@ -4,7 +4,7 @@ import {Accordion} from "@heroui/react";
export function Multiple() {
return (
<Accordion allowsMultipleExpanded className="w-full max-w-md">
<Accordion.Root allowsMultipleExpanded className="w-full max-w-md">
<Accordion.Item>
<Accordion.Heading>
<Accordion.Trigger>
@@ -64,6 +64,6 @@ export function Multiple() {
</Accordion.Body>
</Accordion.Panel>
</Accordion.Item>
</Accordion>
</Accordion.Root>
);
}
+2 -2
View File
@@ -43,7 +43,7 @@ const items = [
export function Oultine() {
return (
<Accordion className="w-full max-w-md" variant="outline">
<Accordion.Root className="w-full max-w-md" variant="outline">
{items.map((item, index) => (
<Accordion.Item key={index}>
<Accordion.Heading>
@@ -62,6 +62,6 @@ export function Oultine() {
</Accordion.Panel>
</Accordion.Item>
))}
</Accordion>
</Accordion.Root>
);
}
+2 -2
View File
@@ -4,12 +4,12 @@ import {Alert} from "@heroui/react";
export function Basic() {
return (
<Alert className="max-w-lg">
<Alert.Root className="max-w-lg">
<Alert.Icon />
<Alert.Content>
<Alert.Title>Heads up!</Alert.Title>
<Alert.Description>You can add components to your app using the cli.</Alert.Description>
</Alert.Content>
</Alert>
</Alert.Root>
);
}
+4 -4
View File
@@ -6,7 +6,7 @@ import {Icon} from "@iconify/react";
export function CustomIcon() {
return (
<div className="flex flex-col gap-4">
<Alert className="max-w-lg" variant="success">
<Alert.Root className="max-w-lg" variant="success">
<Alert.Icon>
<Icon className="size-5" icon="gravity-ui:circle-check-fill" />
</Alert.Icon>
@@ -14,9 +14,9 @@ export function CustomIcon() {
<Alert.Title>Payment received</Alert.Title>
<Alert.Description>Your payment has been successfully processed.</Alert.Description>
</Alert.Content>
</Alert>
</Alert.Root>
<Alert className="max-w-lg" variant="danger">
<Alert.Root className="max-w-lg" variant="danger">
<Alert.Icon>
<Icon className="size-5" icon="gravity-ui:triangle-exclamation-fill" />
</Alert.Icon>
@@ -24,7 +24,7 @@ export function CustomIcon() {
<Alert.Title>Security alert</Alert.Title>
<Alert.Description>Unusual activity detected in your account.</Alert.Description>
</Alert.Content>
</Alert>
</Alert.Root>
</div>
);
}
+2 -2
View File
@@ -18,7 +18,7 @@ export function Dismissible() {
}
return (
<Alert className="max-w-lg">
<Alert.Root className="max-w-lg">
<Alert.Icon />
<Alert.Content>
<Alert.Title>Dismissible Alert</Alert.Title>
@@ -27,6 +27,6 @@ export function Dismissible() {
</Alert.Description>
</Alert.Content>
<Alert.Close onClick={() => setIsVisible(false)} />
</Alert>
</Alert.Root>
);
}
+8 -8
View File
@@ -5,7 +5,7 @@ import {Alert} from "@heroui/react";
export function Variants() {
return (
<div className="flex flex-col gap-4">
<Alert className="max-w-lg">
<Alert.Root className="max-w-lg">
<Alert.Icon />
<Alert.Content>
<Alert.Title>Default Alert</Alert.Title>
@@ -13,31 +13,31 @@ export function Variants() {
This is the default alert variant with neutral styling.
</Alert.Description>
</Alert.Content>
</Alert>
</Alert.Root>
<Alert className="max-w-lg" variant="success">
<Alert.Root className="max-w-lg" variant="success">
<Alert.Icon />
<Alert.Content>
<Alert.Title>Success!</Alert.Title>
<Alert.Description>Your operation completed successfully.</Alert.Description>
</Alert.Content>
</Alert>
</Alert.Root>
<Alert className="max-w-lg" variant="warning">
<Alert.Root className="max-w-lg" variant="warning">
<Alert.Icon />
<Alert.Content>
<Alert.Title>Warning</Alert.Title>
<Alert.Description>Please review the information before proceeding.</Alert.Description>
</Alert.Content>
</Alert>
</Alert.Root>
<Alert className="max-w-lg" variant="danger">
<Alert.Root className="max-w-lg" variant="danger">
<Alert.Icon />
<Alert.Content>
<Alert.Title>Error</Alert.Title>
<Alert.Description>An error occurred while processing your request.</Alert.Description>
</Alert.Content>
</Alert>
</Alert.Root>
</div>
);
}
+2 -2
View File
@@ -4,7 +4,7 @@ import {Alert} from "@heroui/react";
export function WithAction() {
return (
<Alert className="max-w-lg">
<Alert.Root className="max-w-lg">
<Alert.Icon />
<Alert.Content>
<Alert.Title>Update available</Alert.Title>
@@ -13,6 +13,6 @@ export function WithAction() {
</Alert.Description>
</Alert.Content>
<Alert.Action onClick={() => console.log("Update clicked")}>Update</Alert.Action>
</Alert>
</Alert.Root>
);
}
+6 -6
View File
@@ -5,20 +5,20 @@ import {Avatar} from "@heroui/react";
export function Basic() {
return (
<div className="flex items-center gap-4">
<Avatar>
<Avatar.Root>
<Avatar.Image alt="John Doe" src="https://img.heroui.chat/image/avatar?w=400&h=400&u=3" />
<Avatar.Fallback>JD</Avatar.Fallback>
</Avatar>
<Avatar>
</Avatar.Root>
<Avatar.Root>
<Avatar.Image
alt="Blue"
src="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/blue.jpg"
/>
<Avatar.Fallback>B</Avatar.Fallback>
</Avatar>
<Avatar>
</Avatar.Root>
<Avatar.Root>
<Avatar.Fallback>JR</Avatar.Fallback>
</Avatar>
</Avatar.Root>
</div>
);
}
+10 -10
View File
@@ -5,21 +5,21 @@ import {Avatar} from "@heroui/react";
export function Colors() {
return (
<div className="flex items-center gap-4">
<Avatar color="default">
<Avatar.Root color="default">
<Avatar.Fallback>DF</Avatar.Fallback>
</Avatar>
<Avatar color="accent">
</Avatar.Root>
<Avatar.Root color="accent">
<Avatar.Fallback>AC</Avatar.Fallback>
</Avatar>
<Avatar color="success">
</Avatar.Root>
<Avatar.Root color="success">
<Avatar.Fallback>SC</Avatar.Fallback>
</Avatar>
<Avatar color="warning">
</Avatar.Root>
<Avatar.Root color="warning">
<Avatar.Fallback>WR</Avatar.Fallback>
</Avatar>
<Avatar color="danger">
</Avatar.Root>
<Avatar.Root color="danger">
<Avatar.Fallback>DG</Avatar.Fallback>
</Avatar>
</Avatar.Root>
</div>
);
}
+8 -8
View File
@@ -6,25 +6,25 @@ export function CustomStyles() {
return (
<div className="flex items-center gap-4">
{/* Custom size with Tailwind classes */}
<Avatar className="size-16">
<Avatar.Root className="size-16">
<Avatar.Image
alt="Extra Large"
src="https://img.heroui.chat/image/avatar?w=400&h=400&u=3"
/>
<Avatar.Fallback>XL</Avatar.Fallback>
</Avatar>
</Avatar.Root>
{/* Square avatar */}
<Avatar className="rounded-lg">
<Avatar.Root className="rounded-lg">
<Avatar.Image
alt="Square Avatar"
src="https://img.heroui.chat/image/avatar?w=400&h=400&u=4"
/>
<Avatar.Fallback className="rounded-lg">SQ</Avatar.Fallback>
</Avatar>
</Avatar.Root>
{/* Gradient border */}
<Avatar className="bg-gradient-to-tr from-pink-500 to-yellow-500 p-0.5">
<Avatar.Root className="bg-gradient-to-tr from-pink-500 to-yellow-500 p-0.5">
<div className="bg-background size-full rounded-full p-0.5">
<Avatar.Image
alt="Gradient Border"
@@ -33,17 +33,17 @@ export function CustomStyles() {
/>
<Avatar.Fallback className="border-none">GB</Avatar.Fallback>
</div>
</Avatar>
</Avatar.Root>
{/* Status indicator */}
<div className="relative">
<Avatar>
<Avatar.Root>
<Avatar.Image
alt="Online User"
src="https://img.heroui.chat/image/avatar?w=400&h=400&u=8"
/>
<Avatar.Fallback>ON</Avatar.Fallback>
</Avatar>
</Avatar.Root>
<span className="ring-background absolute bottom-0 right-0 size-3 rounded-full bg-green-500 ring-2" />
</div>
</div>
+8 -8
View File
@@ -7,32 +7,32 @@ export function Fallback() {
return (
<div className="flex items-center gap-4">
{/* Text fallback */}
<Avatar>
<Avatar.Root>
<Avatar.Fallback>JD</Avatar.Fallback>
</Avatar>
</Avatar.Root>
{/* Icon fallback */}
<Avatar>
<Avatar.Root>
<Avatar.Fallback>
<Icon icon="gravity-ui:person" />
</Avatar.Fallback>
</Avatar>
</Avatar.Root>
{/* Fallback with delay */}
<Avatar>
<Avatar.Root>
<Avatar.Image
alt="Delayed Avatar"
src="https://invalid-url-to-show-fallback.com/image.jpg"
/>
<Avatar.Fallback delayMs={600}>NA</Avatar.Fallback>
</Avatar>
</Avatar.Root>
{/* Custom styled fallback */}
<Avatar>
<Avatar.Root>
<Avatar.Fallback className="border-none bg-gradient-to-br from-pink-500 to-purple-500 text-white">
GB
</Avatar.Fallback>
</Avatar>
</Avatar.Root>
</div>
);
}
+6 -6
View File
@@ -36,7 +36,7 @@ export function Group() {
{/* Basic avatar group */}
<div className="flex -space-x-2">
{users.slice(0, 4).map((user) => (
<Avatar key={user.id} className="ring-background ring-2">
<Avatar.Root key={user.id} className="ring-background ring-2">
<Avatar.Image alt={user.name} src={user.image} />
<Avatar.Fallback>
{user.name
@@ -44,14 +44,14 @@ export function Group() {
.map((n) => n[0])
.join("")}
</Avatar.Fallback>
</Avatar>
</Avatar.Root>
))}
</div>
{/* Avatar group with counter */}
<div className="flex -space-x-2">
{users.slice(0, 3).map((user) => (
<Avatar key={user.id} className="ring-background ring-2">
<Avatar.Root key={user.id} className="ring-background ring-2">
<Avatar.Image alt={user.name} src={user.image} />
<Avatar.Fallback>
{user.name
@@ -59,11 +59,11 @@ export function Group() {
.map((n) => n[0])
.join("")}
</Avatar.Fallback>
</Avatar>
</Avatar.Root>
))}
<Avatar className="ring-background ring-2">
<Avatar.Root className="ring-background ring-2">
<Avatar.Fallback className="text-xs">+{users.length - 3}</Avatar.Fallback>
</Avatar>
</Avatar.Root>
</div>
</div>
);
+6 -6
View File
@@ -5,27 +5,27 @@ import {Avatar} from "@heroui/react";
export function Sizes() {
return (
<div className="flex items-center gap-4">
<Avatar size="sm">
<Avatar.Root size="sm">
<Avatar.Image
alt="Small Avatar"
src="https://img.heroui.chat/image/avatar?w=400&h=400&u=3"
/>
<Avatar.Fallback>SM</Avatar.Fallback>
</Avatar>
<Avatar size="md">
</Avatar.Root>
<Avatar.Root size="md">
<Avatar.Image
alt="Medium Avatar"
src="https://img.heroui.chat/image/avatar?w=400&h=400&u=4"
/>
<Avatar.Fallback>MD</Avatar.Fallback>
</Avatar>
<Avatar size="lg">
</Avatar.Root>
<Avatar.Root size="lg">
<Avatar.Image
alt="Large Avatar"
src="https://img.heroui.chat/image/avatar?w=400&h=400&u=5"
/>
<Avatar.Fallback>LG</Avatar.Fallback>
</Avatar>
</Avatar.Root>
</div>
);
}
+4 -4
View File
@@ -5,7 +5,7 @@ import {Icon} from "@iconify/react";
export function Default() {
return (
<Card className="w-[400px]">
<Card.Root className="w-[400px]">
<Icon
aria-label="Dollar sign icon"
className="text-primary size-6"
@@ -20,7 +20,7 @@ export function Default() {
<p>Add your wallet in settings to withdraw</p>
</Card.Content>
<Card.Footer>
<Link
<Link.Root
aria-label="Go to settings (opens in new tab)"
href="https://heroui.com"
rel="noopener noreferrer"
@@ -28,8 +28,8 @@ export function Default() {
>
Go to settings
<Link.Icon aria-hidden="true" />
</Link>
</Link.Root>
</Card.Footer>
</Card>
</Card.Root>
);
}
+2 -2
View File
@@ -4,7 +4,7 @@ import {Button, Card} from "@heroui/react";
export function Horizontal() {
return (
<Card className="w-full items-stretch md:flex-row">
<Card.Root className="w-full items-stretch md:flex-row">
<img
alt="Porsche 911 Golden Edition"
className="rounded-panel pointer-events-none aspect-square w-full select-none object-cover md:max-w-[136px]"
@@ -34,6 +34,6 @@ export function Horizontal() {
<Button>Buy Now</Button>
</Card.Footer>
</div>
</Card>
</Card.Root>
);
}
+8 -8
View File
@@ -5,7 +5,7 @@ import {Card} from "@heroui/react";
export function Variants() {
return (
<div className="flex flex-col gap-4">
<Card className="w-[320px]" variant="flat">
<Card.Root className="w-[320px]" variant="flat">
<Card.Header>
<Card.Title>Variant Flat</Card.Title>
<Card.Description>Transparent background with no border</Card.Description>
@@ -13,9 +13,9 @@ export function Variants() {
<Card.Content>
<p>Content with no variant styling</p>
</Card.Content>
</Card>
</Card.Root>
<Card className="w-[320px]" variant="outlined">
<Card.Root className="w-[320px]" variant="outlined">
<Card.Header>
<Card.Title>Variant Outlined</Card.Title>
<Card.Description>This card uses outlined variant (default)</Card.Description>
@@ -23,9 +23,9 @@ export function Variants() {
<Card.Content>
<p>Content with subtle elevation</p>
</Card.Content>
</Card>
</Card.Root>
<Card className="w-[320px]" variant="elevated">
<Card.Root className="w-[320px]" variant="elevated">
<Card.Header>
<Card.Title>Variant Elevated</Card.Title>
<Card.Description>This card uses elevated variant</Card.Description>
@@ -33,9 +33,9 @@ export function Variants() {
<Card.Content>
<p>Content with medium elevation</p>
</Card.Content>
</Card>
</Card.Root>
<Card className="w-[320px]" variant="filled">
<Card.Root className="w-[320px]" variant="filled">
<Card.Header>
<Card.Title>Variant Filled</Card.Title>
<Card.Description>This card uses filled variant</Card.Description>
@@ -43,7 +43,7 @@ export function Variants() {
<Card.Content>
<p>Content with higher elevation</p>
</Card.Content>
</Card>
</Card.Root>
</div>
);
}
+8 -8
View File
@@ -5,7 +5,7 @@ import {Avatar, Card} from "@heroui/react";
export function WithAvatar() {
return (
<div className="flex flex-col gap-4 md:flex-row">
<Card className="w-[200px] gap-2">
<Card.Root className="w-[200px] gap-2">
<img
alt="Indie Hackers community"
className="rounded-panel pointer-events-none aspect-square w-14 select-none object-cover"
@@ -17,18 +17,18 @@ export function WithAvatar() {
<Card.Description>148 members</Card.Description>
</Card.Header>
<Card.Footer className="flex gap-2">
<Avatar aria-label="Martha's profile picture" className="size-5" role="img">
<Avatar.Root aria-label="Martha's profile picture" className="size-5" role="img">
<Avatar.Image
alt="Martha's avatar"
src="https://img.heroui.chat/image/avatar?w=160&h=160"
/>
<Avatar.Fallback className="text-xs">IH</Avatar.Fallback>
</Avatar>
</Avatar.Root>
<span className="text-xs">By Martha</span>
</Card.Footer>
</Card>
</Card.Root>
<Card className="w-[200px] gap-2">
<Card.Root className="w-[200px] gap-2">
<img
alt="AI Builders community"
className="rounded-panel pointer-events-none aspect-square w-14 select-none object-cover"
@@ -40,16 +40,16 @@ export function WithAvatar() {
<Card.Description>362 members</Card.Description>
</Card.Header>
<Card.Footer className="flex gap-2">
<Avatar aria-label="John's profile picture" className="size-5" role="img">
<Avatar.Root aria-label="John's profile picture" className="size-5" role="img">
<Avatar.Image
alt="John's avatar - blue themed"
src="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/blue.jpg"
/>
<Avatar.Fallback className="text-xs">B</Avatar.Fallback>
</Avatar>
</Avatar.Root>
<span className="text-xs">By John</span>
</Card.Footer>
</Card>
</Card.Root>
</div>
);
}
@@ -6,7 +6,7 @@ import {Icon} from "@iconify/react";
export function WithBackgroundImage() {
return (
<div className="flex flex-col items-center justify-center gap-6 md:flex-row">
<Card className="aspect-[280/337] w-full max-w-[280px]">
<Card.Root className="aspect-[280/337] w-full max-w-[280px]">
{/* Background image */}
<img
alt="Happy pet"
@@ -67,9 +67,9 @@ export function WithBackgroundImage() {
Notify me
</Button>
</Card.Footer>
</Card>
</Card.Root>
<Card className="aspect-[65/56] w-full md:w-[390px]">
<Card.Root className="aspect-[65/56] w-full md:w-[390px]">
{/* Background image */}
<img
alt="Beautiful aerial view of Buenos Aires cityscape"
@@ -105,7 +105,7 @@ export function WithBackgroundImage() {
Map
</Button>
</Card.Footer>
</Card>
</Card.Root>
</div>
);
}
+13 -27
View File
@@ -1,46 +1,32 @@
"use client";
import {Button, Card, Link} from "@heroui/react";
import {Button, Card, Input, Label, Link, TextField} from "@heroui/react";
export function WithForm() {
return (
<Card className="w-full max-w-md">
<Card.Root className="w-full max-w-md">
<Card.Header>
<Card.Title>Login</Card.Title>
<Card.Description>Enter your credentials to access your account</Card.Description>
</Card.Header>
<Card.Content>
<form className="flex flex-col gap-4">
<div className="flex flex-col gap-2">
<label className="text-sm font-medium" htmlFor="email">
Email
</label>
<input
className="border-border bg-background focus:ring-focus rounded-md border px-3 py-2 text-sm focus:outline-none focus:ring-2"
id="email"
placeholder="email@example.com"
type="email"
/>
</div>
<div className="flex flex-col gap-2">
<label className="text-sm font-medium" htmlFor="password">
Password
</label>
<input
className="border-border bg-background focus:ring-focus rounded-md border px-3 py-2 text-sm focus:outline-none focus:ring-2"
id="password"
placeholder="••••••••"
type="password"
/>
</div>
<TextField name="email" type="email">
<Label>Email</Label>
<Input placeholder="email@example.com" />
</TextField>
<TextField name="password" type="password">
<Label>Password</Label>
<Input placeholder="••••••••" />
</TextField>
</form>
</Card.Content>
<Card.Footer className="flex flex-col gap-2">
<Button className="w-full">Sign In</Button>
<Link className="text-center text-sm" href="#">
<Link.Root className="text-center text-sm" href="#">
Forgot password?
</Link>
</Link.Root>
</Card.Footer>
</Card>
</Card.Root>
);
}
+4 -4
View File
@@ -5,7 +5,7 @@ import {Card} from "@heroui/react";
export function WithImage() {
return (
<div className="flex flex-col gap-4 md:flex-row">
<Card className="w-[220px] gap-2 p-1">
<Card.Root className="w-[220px] gap-2 p-1">
<img
alt="Luxury cars collection"
className="block aspect-square w-full shrink-0 select-none rounded-[calc(theme(--radius-panel)-theme(spacing.1))] object-cover align-middle"
@@ -18,9 +18,9 @@ export function WithImage() {
18 pictures
</span>
</Card.Footer>
</Card>
</Card.Root>
<Card className="w-[220px] gap-2 p-1">
<Card.Root className="w-[220px] gap-2 p-1">
<img
alt="Modern office workspace"
className="block aspect-square w-full shrink-0 select-none rounded-[calc(theme(--radius-panel)-theme(spacing.1))] object-cover align-middle"
@@ -33,7 +33,7 @@ export function WithImage() {
56 pictures
</span>
</Card.Footer>
</Card>
</Card.Root>
</div>
);
}
@@ -12,7 +12,7 @@ export function Basic() {
<div className="w-full max-w-md">
<div className="flex flex-col gap-4 bg-transparent p-4">
<DisclosureGroup expandedKeys={expandedKeys} onExpandedChange={setExpandedKeys}>
<Disclosure aria-label="Preview HeroUI Native" id="preview">
<Disclosure.Root aria-label="Preview HeroUI Native" id="preview">
<Disclosure.Heading>
<Button
slot="trigger"
@@ -45,9 +45,9 @@ export function Basic() {
</Button>
</Disclosure.Body>
</Disclosure.Content>
</Disclosure>
</Disclosure.Root>
<Separator className="my-2" />
<Disclosure id="download">
<Disclosure.Root id="download">
<Disclosure.Heading aria-label="Download HeroUI Native">
<Button
slot="trigger"
@@ -81,7 +81,7 @@ export function Basic() {
</Button>
</Disclosure.Body>
</Disclosure.Content>
</Disclosure>
</Disclosure.Root>
</DisclosureGroup>
</div>
</div>
@@ -48,7 +48,7 @@ export function Controlled() {
</div>
</div>
<DisclosureGroup expandedKeys={expandedKeys} onExpandedChange={setExpandedKeys}>
<Disclosure aria-label="Preview HeroUI Native" id="preview">
<Disclosure.Root aria-label="Preview HeroUI Native" id="preview">
<Disclosure.Heading>
<Button
slot="trigger"
@@ -81,9 +81,9 @@ export function Controlled() {
</Button>
</Disclosure.Body>
</Disclosure.Content>
</Disclosure>
</Disclosure.Root>
<Separator className="my-2" />
<Disclosure id="download">
<Disclosure.Root id="download">
<Disclosure.Heading aria-label="Download HeroUI Native">
<Button
slot="trigger"
@@ -116,7 +116,7 @@ export function Controlled() {
</Button>
</Disclosure.Body>
</Disclosure.Content>
</Disclosure>
</Disclosure.Root>
</DisclosureGroup>
</div>
</div>
+2 -2
View File
@@ -9,7 +9,7 @@ export function Basic() {
return (
<div className="w-full max-w-md text-center">
<Disclosure isExpanded={isExpanded} onExpandedChange={setIsExpanded}>
<Disclosure.Root isExpanded={isExpanded} onExpandedChange={setIsExpanded}>
<Disclosure.Heading>
<Button slot="trigger" variant="secondary">
<Icon icon="gravity-ui:qr-code" />
@@ -34,7 +34,7 @@ export function Basic() {
</Button>
</Disclosure.Body>
</Disclosure.Content>
</Disclosure>
</Disclosure.Root>
</div>
);
}
+5 -4
View File
@@ -4,6 +4,7 @@ import {
Button,
Description,
FieldError,
FieldGroup,
Fieldset,
Form,
Input,
@@ -29,10 +30,10 @@ export function Basic() {
return (
<Form className="w-full max-w-96" onSubmit={onSubmit}>
<Fieldset>
<Fieldset.Root>
<Fieldset.Legend>Profile Settings</Fieldset.Legend>
<Description>Update your profile information.</Description>
<Fieldset.Group>
<FieldGroup>
<TextField
isRequired
name="name"
@@ -69,7 +70,7 @@ export function Basic() {
<Description>Minimum 10 characters</Description>
<FieldError />
</TextField>
</Fieldset.Group>
</FieldGroup>
<Fieldset.Actions>
<Button type="submit">
<Icon icon="gravity-ui:floppy-disk" />
@@ -79,7 +80,7 @@ export function Basic() {
Cancel
</Button>
</Fieldset.Actions>
</Fieldset>
</Fieldset.Root>
</Form>
);
}
+8 -8
View File
@@ -5,22 +5,22 @@ import {Kbd} from "@heroui/react";
export function Basic() {
return (
<div className="flex items-center gap-4">
<Kbd>
<Kbd.Root>
<Kbd.Abbr keyValue="command" />
<Kbd.Content>K</Kbd.Content>
</Kbd>
<Kbd>
</Kbd.Root>
<Kbd.Root>
<Kbd.Abbr keyValue="shift" />
<Kbd.Content>P</Kbd.Content>
</Kbd>
<Kbd>
</Kbd.Root>
<Kbd.Root>
<Kbd.Abbr keyValue="ctrl" />
<Kbd.Content>C</Kbd.Content>
</Kbd>
<Kbd>
</Kbd.Root>
<Kbd.Root>
<Kbd.Abbr keyValue="option" />
<Kbd.Content>D</Kbd.Content>
</Kbd>
</Kbd.Root>
</div>
);
}
+10 -10
View File
@@ -7,36 +7,36 @@ export function InlineUsage() {
<div className="space-y-4">
<p className="text-sm">
Press{" "}
<Kbd>
<Kbd.Root>
<Kbd.Content>Esc</Kbd.Content>
</Kbd>{" "}
</Kbd.Root>{" "}
to close the dialog.
</p>
<p className="text-sm">
Use{" "}
<Kbd>
<Kbd.Root>
<Kbd.Abbr keyValue="command" />
<Kbd.Content>K</Kbd.Content>
</Kbd>{" "}
</Kbd.Root>{" "}
to open the command palette.
</p>
<p className="text-sm">
Navigate with{" "}
<Kbd>
<Kbd.Root>
<Kbd.Abbr keyValue="up" />
</Kbd>{" "}
</Kbd.Root>{" "}
and{" "}
<Kbd>
<Kbd.Root>
<Kbd.Abbr keyValue="down" />
</Kbd>{" "}
</Kbd.Root>{" "}
arrow keys.
</p>
<p className="text-sm">
Save your work with{" "}
<Kbd>
<Kbd.Root>
<Kbd.Abbr keyValue="command" />
<Kbd.Content>S</Kbd.Content>
</Kbd>{" "}
</Kbd.Root>{" "}
regularly.
</p>
</div>
+8 -8
View File
@@ -10,31 +10,31 @@ export function InstructionalText() {
<ul className="space-y-2 text-sm">
<li>
Open search:{" "}
<Kbd>
<Kbd.Root>
<Kbd.Abbr keyValue="command" />
<Kbd.Content>K</Kbd.Content>
</Kbd>
</Kbd.Root>
</li>
<li>
Toggle sidebar:{" "}
<Kbd>
<Kbd.Root>
<Kbd.Abbr keyValue="command" />
<Kbd.Content>B</Kbd.Content>
</Kbd>
</Kbd.Root>
</li>
<li>
New file:{" "}
<Kbd>
<Kbd.Root>
<Kbd.Abbr keyValue="command" />
<Kbd.Content>N</Kbd.Content>
</Kbd>
</Kbd.Root>
</li>
<li>
Quick save:{" "}
<Kbd>
<Kbd.Root>
<Kbd.Abbr keyValue="command" />
<Kbd.Content>S</Kbd.Content>
</Kbd>
</Kbd.Root>
</li>
</ul>
</div>
+16 -16
View File
@@ -8,35 +8,35 @@ export function NavigationKeys() {
<div className="flex items-center gap-2">
<span className="text-muted text-sm">Arrow Keys:</span>
<div className="flex items-center gap-2">
<Kbd>
<Kbd.Root>
<Kbd.Abbr keyValue="up" />
</Kbd>
<Kbd>
</Kbd.Root>
<Kbd.Root>
<Kbd.Abbr keyValue="down" />
</Kbd>
<Kbd>
</Kbd.Root>
<Kbd.Root>
<Kbd.Abbr keyValue="left" />
</Kbd>
<Kbd>
</Kbd.Root>
<Kbd.Root>
<Kbd.Abbr keyValue="right" />
</Kbd>
</Kbd.Root>
</div>
</div>
<div className="flex items-center gap-2">
<span className="text-muted text-sm">Page Navigation:</span>
<div className="flex items-center gap-2">
<Kbd>
<Kbd.Root>
<Kbd.Abbr keyValue="pageup" />
</Kbd>
<Kbd>
</Kbd.Root>
<Kbd.Root>
<Kbd.Abbr keyValue="pagedown" />
</Kbd>
<Kbd>
</Kbd.Root>
<Kbd.Root>
<Kbd.Abbr keyValue="home" />
</Kbd>
<Kbd>
</Kbd.Root>
<Kbd.Root>
<Kbd.Abbr keyValue="end" />
</Kbd>
</Kbd.Root>
</div>
</div>
</div>
+10 -10
View File
@@ -7,32 +7,32 @@ export function SpecialKeys() {
<div className="space-y-3">
<p className="text-sm">
Press{" "}
<Kbd>
<Kbd.Root>
<Kbd.Abbr keyValue="enter" />
</Kbd>{" "}
</Kbd.Root>{" "}
to confirm or{" "}
<Kbd>
<Kbd.Root>
<Kbd.Abbr keyValue="escape" />
</Kbd>{" "}
</Kbd.Root>{" "}
to cancel.
</p>
<p className="text-sm">
Use{" "}
<Kbd>
<Kbd.Root>
<Kbd.Abbr keyValue="tab" />
</Kbd>{" "}
</Kbd.Root>{" "}
to navigate between form fields and{" "}
<Kbd>
<Kbd.Root>
<Kbd.Abbr keyValue="shift" />
<Kbd.Abbr keyValue="tab" />
</Kbd>{" "}
</Kbd.Root>{" "}
to go back.
</p>
<p className="text-sm">
Hold{" "}
<Kbd>
<Kbd.Root>
<Kbd.Abbr keyValue="space" />
</Kbd>{" "}
</Kbd.Root>{" "}
to temporarily enable panning mode.
</p>
</div>
+6 -6
View File
@@ -5,15 +5,15 @@ import {Link} from "@heroui/react";
export function LinkBasic() {
return (
<div className="flex flex-wrap items-center gap-4">
<Link href="#">
<Link.Root href="#">
Call to action
<Link.Icon />
</Link>
<Link isDisabled href="#">
</Link.Root>
<Link.Root isDisabled href="#">
Call to action
<Link.Icon />
</Link>
<Link
</Link.Root>
<Link.Root
className="border-default bg-default-100 text-foreground hover:bg-default-200 inline-flex items-center gap-2 rounded-full border px-3 py-1 text-sm font-medium transition"
href="https://heroui.com"
rel="noopener noreferrer"
@@ -21,7 +21,7 @@ export function LinkBasic() {
>
HeroUI
<Link.Icon className="h-3 w-3" />
</Link>
</Link.Root>
</div>
);
}
+4 -4
View File
@@ -7,20 +7,20 @@ import {LinkIcon} from "@/icons/link";
export function LinkCustomIcon() {
return (
<div className="flex flex-col gap-3">
<Link href="#">
<Link.Root href="#">
External link
<Link.Icon>
<LinkIcon className="h-3.5 w-3.5" />
</Link.Icon>
</Link>
<Link className="gap-1" href="#">
</Link.Root>
<Link.Root className="gap-1" href="#">
<Link.Icon>
<svg aria-hidden="true" className="h-4 w-4" fill="currentColor" viewBox="0 0 20 20">
<path d="M10 2a8 8 0 1 1-8 8 8.01 8.01 0 0 1 8-8Zm.75 4.75a.75.75 0 1 0-1.5 0v4.5a.75.75 0 0 0 1.5 0Zm0 6a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z" />
</svg>
</Link.Icon>
Inline SVG icon
</Link>
</Link.Root>
</div>
);
}
+4 -4
View File
@@ -5,14 +5,14 @@ import {Link} from "@heroui/react";
export function LinkIconPlacement() {
return (
<div className="flex flex-col gap-3">
<Link href="#">
<Link.Root href="#">
Icon at end (default)
<Link.Icon />
</Link>
<Link className="gap-1" href="#">
</Link.Root>
<Link.Root className="gap-1" href="#">
<Link.Icon />
Icon at start
</Link>
</Link.Root>
</div>
);
}
+2 -2
View File
@@ -5,7 +5,7 @@ import {Button, Popover} from "@heroui/react";
export function PopoverBasic() {
return (
<div className="flex items-center gap-4">
<Popover>
<Popover.Root>
<Button>Click me</Button>
<Popover.Content>
<Popover.Dialog>
@@ -15,7 +15,7 @@ export function PopoverBasic() {
</p>
</Popover.Dialog>
</Popover.Content>
</Popover>
</Popover.Root>
</div>
);
}
+6 -6
View File
@@ -8,16 +8,16 @@ export function PopoverInteractive() {
return (
<div className="flex items-center gap-6">
<Popover>
<Popover.Root>
<Popover.Trigger aria-label="User profile">
<div className="flex items-center gap-2">
<Avatar size="sm">
<Avatar.Root size="sm">
<Avatar.Image
alt="Sarah Johnson"
src="https://img.heroui.chat/image/avatar?w=400&h=400&u=3"
/>
<Avatar.Fallback>SJ</Avatar.Fallback>
</Avatar>
</Avatar.Root>
<div className="flex flex-col">
<p className="text-sm font-medium">Sarah Johnson</p>
<p className="text-muted text-xs">@sarahj</p>
@@ -29,13 +29,13 @@ export function PopoverInteractive() {
<Popover.Heading>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<Avatar size="md">
<Avatar.Root size="md">
<Avatar.Image
alt="Sarah Johnson"
src="https://img.heroui.chat/image/avatar?w=400&h=400&u=3"
/>
<Avatar.Fallback>SJ</Avatar.Fallback>
</Avatar>
</Avatar.Root>
<div>
<p className="font-semibold">Sarah Johnson</p>
<p className="text-muted text-sm">@sarahj</p>
@@ -66,7 +66,7 @@ export function PopoverInteractive() {
</div>
</Popover.Dialog>
</Popover.Content>
</Popover>
</Popover.Root>
</div>
);
}
+8 -8
View File
@@ -6,7 +6,7 @@ export function PopoverPlacement() {
return (
<div className="grid grid-cols-3 gap-4">
<div />
<Popover>
<Popover.Root>
<Button className="w-full" variant="tertiary">
Top
</Button>
@@ -16,10 +16,10 @@ export function PopoverPlacement() {
<p className="text-sm">Top placement</p>
</Popover.Dialog>
</Popover.Content>
</Popover>
</Popover.Root>
<div />
<Popover>
<Popover.Root>
<Button className="w-full" variant="tertiary">
Left
</Button>
@@ -29,13 +29,13 @@ export function PopoverPlacement() {
<p className="text-sm">Left placement</p>
</Popover.Dialog>
</Popover.Content>
</Popover>
</Popover.Root>
<div className="flex items-center justify-center">
<span className="text-muted text-sm">Click buttons</span>
</div>
<Popover>
<Popover.Root>
<Button className="w-full" variant="tertiary">
Right
</Button>
@@ -45,10 +45,10 @@ export function PopoverPlacement() {
<p className="text-sm">Right placement</p>
</Popover.Dialog>
</Popover.Content>
</Popover>
</Popover.Root>
<div />
<Popover>
<Popover.Root>
<Button className="w-full" variant="tertiary">
Bottom
</Button>
@@ -58,7 +58,7 @@ export function PopoverPlacement() {
<p className="text-sm">Bottom placement</p>
</Popover.Dialog>
</Popover.Content>
</Popover>
</Popover.Root>
<div />
</div>
);
+4 -4
View File
@@ -6,7 +6,7 @@ import {Icon} from "@iconify/react";
export function PopoverWithArrow() {
return (
<div className="flex items-center gap-4">
<Popover>
<Popover.Root>
<Button variant="secondary">With Arrow</Button>
<Popover.Content>
<Popover.Dialog>
@@ -17,9 +17,9 @@ export function PopoverWithArrow() {
</p>
</Popover.Dialog>
</Popover.Content>
</Popover>
</Popover.Root>
<Popover>
<Popover.Root>
<Button isIconOnly variant="tertiary">
<Icon icon="gravity-ui:ellipsis" />
</Button>
@@ -32,7 +32,7 @@ export function PopoverWithArrow() {
</p>
</Popover.Dialog>
</Popover.Content>
</Popover>
</Popover.Root>
</div>
);
}
+6 -6
View File
@@ -7,7 +7,7 @@ export function Basic() {
<RadioGroup defaultValue="premium" name="plan">
<Label>Plan selection</Label>
<Description>Choose the plan that suits you best</Description>
<Radio value="basic">
<Radio.Root value="basic">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -15,8 +15,8 @@ export function Basic() {
<Label>Basic Plan</Label>
<Description>Includes 100 messages per month</Description>
</Radio.Content>
</Radio>
<Radio value="premium">
</Radio.Root>
<Radio.Root value="premium">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -24,8 +24,8 @@ export function Basic() {
<Label>Premium Plan</Label>
<Description>Includes 200 messages per month</Description>
</Radio.Content>
</Radio>
<Radio value="business">
</Radio.Root>
<Radio.Root value="business">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -33,7 +33,7 @@ export function Basic() {
<Label>Business Plan</Label>
<Description>Unlimited messages</Description>
</Radio.Content>
</Radio>
</Radio.Root>
</RadioGroup>
);
}
@@ -10,7 +10,7 @@ export function Controlled() {
<div className="flex flex-col gap-4">
<RadioGroup name="plan-controlled" value={value} onChange={setValue}>
<Label>Subscription plan</Label>
<Radio value="starter">
<Radio.Root value="starter">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -18,8 +18,8 @@ export function Controlled() {
<Label>Starter</Label>
<Description>For side projects and small teams</Description>
</Radio.Content>
</Radio>
<Radio value="pro">
</Radio.Root>
<Radio.Root value="pro">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -27,8 +27,8 @@ export function Controlled() {
<Label>Pro</Label>
<Description>Advanced reporting and analytics</Description>
</Radio.Content>
</Radio>
<Radio value="teams">
</Radio.Root>
<Radio.Root value="teams">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -36,7 +36,7 @@ export function Controlled() {
<Label>Teams</Label>
<Description>Share access with up to 10 teammates</Description>
</Radio.Content>
</Radio>
</Radio.Root>
</RadioGroup>
<p className="text-muted text-sm">
Selected plan: <span className="font-medium">{value}</span>
@@ -7,7 +7,7 @@ export function CustomIndicator() {
<RadioGroup defaultValue="premium" name="plan-custom-indicator">
<Label>Plan selection</Label>
<Description>Choose the plan that suits you best</Description>
<Radio value="basic">
<Radio.Root value="basic">
<Radio.Control>
<Radio.Indicator>
{({isSelected}) =>
@@ -19,8 +19,8 @@ export function CustomIndicator() {
<Label>Basic Plan</Label>
<Description>Includes 100 messages per month</Description>
</Radio.Content>
</Radio>
<Radio value="premium">
</Radio.Root>
<Radio.Root value="premium">
<Radio.Control>
<Radio.Indicator>
{({isSelected}) =>
@@ -32,8 +32,8 @@ export function CustomIndicator() {
<Label>Premium Plan</Label>
<Description>Includes 200 messages per month</Description>
</Radio.Content>
</Radio>
<Radio value="business">
</Radio.Root>
<Radio.Root value="business">
<Radio.Control>
<Radio.Indicator>
{({isSelected}) =>
@@ -45,7 +45,7 @@ export function CustomIndicator() {
<Label>Business Plan</Label>
<Description>Unlimited messages</Description>
</Radio.Content>
</Radio>
</Radio.Root>
</RadioGroup>
);
}
@@ -65,7 +65,7 @@ export function DeliveryAndPayment() {
<Label>Delivery method</Label>
<div className="grid gap-x-4 md:grid-cols-3">
{deliveryOptions.map((option) => (
<Radio
<Radio.Root
key={option.value}
value={option.value}
className={clsx(
@@ -83,7 +83,7 @@ export function DeliveryAndPayment() {
</div>
<span className="text-sm font-semibold">{option.price}</span>
</Radio.Content>
</Radio>
</Radio.Root>
))}
</div>
</RadioGroup>
@@ -95,7 +95,7 @@ export function DeliveryAndPayment() {
</div>
<div className="grid gap-x-4 md:grid-cols-2">
{paymentOptions.map((option) => (
<Radio
<Radio.Root
key={option.value}
value={option.value}
className={clsx(
@@ -113,7 +113,7 @@ export function DeliveryAndPayment() {
<Description>{option.description}</Description>
</div>
</Radio.Content>
</Radio>
</Radio.Root>
))}
</div>
</RadioGroup>
+6 -6
View File
@@ -7,7 +7,7 @@ export function Disabled() {
<RadioGroup isDisabled defaultValue="pro" name="plan-disabled">
<Label>Subscription plan</Label>
<Description>Plan changes are temporarily paused while we roll out updates.</Description>
<Radio value="starter">
<Radio.Root value="starter">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -15,8 +15,8 @@ export function Disabled() {
<Label>Starter</Label>
<Description>For side projects and small teams</Description>
</Radio.Content>
</Radio>
<Radio value="pro">
</Radio.Root>
<Radio.Root value="pro">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -24,8 +24,8 @@ export function Disabled() {
<Label>Pro</Label>
<Description>Advanced reporting and analytics</Description>
</Radio.Content>
</Radio>
<Radio value="teams">
</Radio.Root>
<Radio.Root value="teams">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -33,7 +33,7 @@ export function Disabled() {
<Label>Teams</Label>
<Description>Share access with up to 10 teammates</Description>
</Radio.Content>
</Radio>
</Radio.Root>
</RadioGroup>
);
}
@@ -7,7 +7,7 @@ export function Horizontal() {
<div className="flex flex-col gap-4">
<Label>Subscription plan</Label>
<RadioGroup defaultValue="pro" name="plan-orientation" orientation="horizontal">
<Radio value="starter">
<Radio.Root value="starter">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -15,8 +15,8 @@ export function Horizontal() {
<Label>Starter</Label>
<Description>For side projects</Description>
</Radio.Content>
</Radio>
<Radio value="pro">
</Radio.Root>
<Radio.Root value="pro">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -24,8 +24,8 @@ export function Horizontal() {
<Label>Pro</Label>
<Description>Advanced reporting</Description>
</Radio.Content>
</Radio>
<Radio value="teams">
</Radio.Root>
<Radio.Root value="teams">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -33,7 +33,7 @@ export function Horizontal() {
<Label>Teams</Label>
<Description>Up to 10 teammates</Description>
</Radio.Content>
</Radio>
</Radio.Root>
</RadioGroup>
</div>
);
@@ -14,7 +14,7 @@ export function Uncontrolled() {
onChange={(nextValue) => setSelection(nextValue)}
>
<Label>Subscription plan</Label>
<Radio value="starter">
<Radio.Root value="starter">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -22,8 +22,8 @@ export function Uncontrolled() {
<Label>Starter</Label>
<Description>For side projects and small teams</Description>
</Radio.Content>
</Radio>
<Radio value="pro">
</Radio.Root>
<Radio.Root value="pro">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -31,8 +31,8 @@ export function Uncontrolled() {
<Label>Pro</Label>
<Description>Advanced reporting and analytics</Description>
</Radio.Content>
</Radio>
<Radio value="teams">
</Radio.Root>
<Radio.Root value="teams">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -40,7 +40,7 @@ export function Uncontrolled() {
<Label>Teams</Label>
<Description>Share access with up to 10 teammates</Description>
</Radio.Content>
</Radio>
</Radio.Root>
</RadioGroup>
<p className="text-muted text-sm">
Last chosen plan: <span className="font-medium">{selection}</span>
@@ -20,7 +20,7 @@ export function Validation() {
>
<RadioGroup isRequired name="plan-validation">
<Label>Subscription plan</Label>
<Radio value="starter">
<Radio.Root value="starter">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -28,8 +28,8 @@ export function Validation() {
<Label>Starter</Label>
<Description>For side projects and small teams</Description>
</Radio.Content>
</Radio>
<Radio value="pro">
</Radio.Root>
<Radio.Root value="pro">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -37,8 +37,8 @@ export function Validation() {
<Label>Pro</Label>
<Description>Advanced reporting and analytics</Description>
</Radio.Content>
</Radio>
<Radio value="teams">
</Radio.Root>
<Radio.Root value="teams">
<Radio.Control>
<Radio.Indicator />
</Radio.Control>
@@ -46,7 +46,7 @@ export function Validation() {
<Label>Teams</Label>
<Description>Share access with up to 10 teammates</Description>
</Radio.Content>
</Radio>
</Radio.Root>
<FieldError>Choose a subscription before continuing.</FieldError>
</RadioGroup>
<Button className="mt-2 w-fit" type="submit">
+6 -6
View File
@@ -1,14 +1,14 @@
"use client";
import {Label, Switch} from "@heroui/react";
import {Label, SwitchControl, SwitchRoot, SwitchThumb} from "@heroui/react";
export function Basic() {
return (
<Switch>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<SwitchRoot>
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<Label className="text-sm">Enable notifications</Label>
</Switch>
</SwitchRoot>
);
}
+7 -7
View File
@@ -1,6 +1,6 @@
"use client";
import {Label, Switch} from "@heroui/react";
import {Label, SwitchControl, SwitchRoot, SwitchThumb} from "@heroui/react";
import React from "react";
export function Controlled() {
@@ -8,13 +8,13 @@ export function Controlled() {
return (
<div className="flex flex-col gap-4">
<Switch isSelected={isSelected} onChange={setIsSelected}>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<SwitchRoot isSelected={isSelected} onChange={setIsSelected}>
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<Label className="text-sm">Enable notifications</Label>
</Switch>
<p className="text-muted text-sm">Switch is {isSelected ? "on" : "off"}</p>
</SwitchRoot>
<p className="text-muted text-sm">SwitchRoot is {isSelected ? "on" : "off"}</p>
</div>
);
}
+9 -9
View File
@@ -1,29 +1,29 @@
"use client";
import {Switch} from "@heroui/react";
import {SwitchControl, SwitchIcon, SwitchRoot, SwitchThumb} from "@heroui/react";
import {Icon} from "@iconify/react";
export function CustomStyles() {
return (
<Switch>
<SwitchRoot>
{({isSelected}) => (
<>
<Switch.Control
<SwitchControl
className={`h-[31px] w-[51px] bg-blue-500 ${isSelected ? "bg-cyan-500 shadow-[0_0_12px_rgba(6,182,212,0.5)]" : ""}`}
>
<Switch.Thumb
<SwitchThumb
className={`size-[27px] bg-white shadow-sm ${isSelected ? "ms-[22px] shadow-lg" : ""}`}
>
<Switch.Icon>
<SwitchIcon>
<Icon
className={`size-4 ${isSelected ? "text-cyan-600" : "text-blue-600"}`}
icon={isSelected ? "gravity-ui:check" : "gravity-ui:power"}
/>
</Switch.Icon>
</Switch.Thumb>
</Switch.Control>
</SwitchIcon>
</SwitchThumb>
</SwitchControl>
</>
)}
</Switch>
</SwitchRoot>
);
}
@@ -1,14 +1,14 @@
"use client";
import {Label, Switch} from "@heroui/react";
import {Label, SwitchControl, SwitchRoot, SwitchThumb} from "@heroui/react";
export function DefaultSelected() {
return (
<Switch defaultSelected>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<SwitchRoot defaultSelected>
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<Label className="text-sm">Enable notifications</Label>
</Switch>
</SwitchRoot>
);
}
+6 -6
View File
@@ -1,14 +1,14 @@
"use client";
import {Label, Switch} from "@heroui/react";
import {Label, SwitchControl, SwitchRoot, SwitchThumb} from "@heroui/react";
export function Disabled() {
return (
<Switch isDisabled>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<SwitchRoot isDisabled>
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<Label className="text-sm">Enable notifications</Label>
</Switch>
</SwitchRoot>
);
}
+18 -20
View File
@@ -18,26 +18,24 @@ export function Form() {
return (
<form className="flex flex-col gap-4" onSubmit={handleSubmit}>
<SwitchGroup>
<SwitchGroup.Items>
<Switch name="notifications" value="on">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Enable notifications</Label>
</Switch>
<Switch defaultSelected name="newsletter" value="on">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Subscribe to newsletter</Label>
</Switch>
<Switch name="marketing" value="on">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Receive marketing updates</Label>
</Switch>
</SwitchGroup.Items>
<Switch.Root name="notifications" value="on">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Enable notifications</Label>
</Switch.Root>
<Switch.Root defaultSelected name="newsletter" value="on">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Subscribe to newsletter</Label>
</Switch.Root>
<Switch.Root name="marketing" value="on">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Receive marketing updates</Label>
</Switch.Root>
</SwitchGroup>
<Button className="mt-4" size="sm" type="submit" variant="primary">
Submit
+18 -20
View File
@@ -5,26 +5,24 @@ import {Label, Switch, SwitchGroup} from "@heroui/react";
export function GroupHorizontal() {
return (
<SwitchGroup className="overflow-x-auto" orientation="horizontal">
<SwitchGroup.Items>
<Switch name="notifications">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Notifications</Label>
</Switch>
<Switch name="marketing">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Marketing</Label>
</Switch>
<Switch name="social">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Social</Label>
</Switch>
</SwitchGroup.Items>
<Switch.Root name="notifications">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Notifications</Label>
</Switch.Root>
<Switch.Root name="marketing">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Marketing</Label>
</Switch.Root>
<Switch.Root name="social">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Social</Label>
</Switch.Root>
</SwitchGroup>
);
}
+18 -20
View File
@@ -5,26 +5,24 @@ import {Label, Switch, SwitchGroup} from "@heroui/react";
export function Group() {
return (
<SwitchGroup>
<SwitchGroup.Items>
<Switch name="notifications">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Allow Notifications</Label>
</Switch>
<Switch name="marketing">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Marketing emails</Label>
</Switch>
<Switch name="social">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Social media updates</Label>
</Switch>
</SwitchGroup.Items>
<Switch.Root name="notifications">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Allow Notifications</Label>
</Switch.Root>
<Switch.Root name="marketing">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Marketing emails</Label>
</Switch.Root>
<Switch.Root name="social">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<Label className="text-sm">Social media updates</Label>
</Switch.Root>
</SwitchGroup>
);
}
+11 -11
View File
@@ -1,22 +1,22 @@
"use client";
import {Label, Switch} from "@heroui/react";
import {Label, SwitchControl, SwitchRoot, SwitchThumb} from "@heroui/react";
export function LabelPosition() {
return (
<div className="flex flex-col gap-4">
<Switch>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<SwitchRoot>
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<Label className="text-sm">Label after</Label>
</Switch>
<Switch>
</SwitchRoot>
<SwitchRoot>
<Label className="text-sm">Label before</Label>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
</Switch>
<SwitchControl>
<SwitchThumb />
</SwitchControl>
</SwitchRoot>
</div>
);
}
+6 -6
View File
@@ -1,18 +1,18 @@
"use client";
import {Label, Switch} from "@heroui/react";
import {Label, SwitchControl, SwitchRoot, SwitchThumb} from "@heroui/react";
export function RenderProps() {
return (
<Switch>
<SwitchRoot>
{({isSelected}) => (
<>
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<Label className="text-sm">{isSelected ? "Enabled" : "Disabled"}</Label>
</>
)}
</Switch>
</SwitchRoot>
);
}
+16 -16
View File
@@ -1,28 +1,28 @@
"use client";
import {Label, Switch} from "@heroui/react";
import {Label, SwitchControl, SwitchRoot, SwitchThumb} from "@heroui/react";
export function Sizes() {
return (
<div className="flex gap-6">
<Switch size="sm">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<SwitchRoot size="sm">
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<Label className="text-xs">Small</Label>
</Switch>
<Switch size="md">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
</SwitchRoot>
<SwitchRoot size="md">
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<Label className="text-sm">Medium</Label>
</Switch>
<Switch size="lg">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
</SwitchRoot>
<SwitchRoot size="lg">
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<Label className="text-base">Large</Label>
</Switch>
</SwitchRoot>
</div>
);
}
@@ -1,21 +1,21 @@
"use client";
import {Description, Label, Switch} from "@heroui/react";
import {Description, Label, SwitchControl, SwitchRoot, SwitchThumb} from "@heroui/react";
export function WithDescription() {
return (
<div className="max-w-sm">
<Switch>
<SwitchRoot>
<div className="flex gap-3">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
<SwitchControl>
<SwitchThumb />
</SwitchControl>
<div className="flex flex-col gap-1">
<Label className="text-sm">Public profile</Label>
<Description>Allow others to see your profile information</Description>
</div>
</div>
</Switch>
</SwitchRoot>
</div>
);
}
+9 -9
View File
@@ -1,6 +1,6 @@
"use client";
import {Switch} from "@heroui/react";
import {SwitchControl, SwitchIcon, SwitchRoot, SwitchThumb} from "@heroui/react";
import {Icon} from "@iconify/react";
export function WithIcons() {
@@ -35,22 +35,22 @@ export function WithIcons() {
return (
<div className="flex gap-3">
{Object.entries(icons).map(([key, value]) => (
<Switch key={key} defaultSelected size="lg">
<SwitchRoot key={key} defaultSelected size="lg">
{({isSelected}) => (
<>
<Switch.Control className={isSelected ? value.selectedControlClass : ""}>
<Switch.Thumb>
<Switch.Icon>
<SwitchControl className={isSelected ? value.selectedControlClass : ""}>
<SwitchThumb>
<SwitchIcon>
<Icon
className={`${isSelected ? "opacity-100" : "opacity-70"} size-3 text-inherit`}
icon={isSelected ? value.on : value.off}
/>
</Switch.Icon>
</Switch.Thumb>
</Switch.Control>
</SwitchIcon>
</SwitchThumb>
</SwitchControl>
</>
)}
</Switch>
</SwitchRoot>
))}
</div>
);
+6 -6
View File
@@ -1,13 +1,13 @@
"use client";
import {Switch} from "@heroui/react";
import {SwitchControl, SwitchRoot, SwitchThumb} from "@heroui/react";
export function WithoutLabel() {
return (
<Switch aria-label="Enable notifications">
<Switch.Control>
<Switch.Thumb />
</Switch.Control>
</Switch>
<SwitchRoot aria-label="Enable notifications">
<SwitchControl>
<SwitchThumb />
</SwitchControl>
</SwitchRoot>
);
}
+22 -22
View File
@@ -1,35 +1,35 @@
"use client";
import {Tabs} from "@heroui/react";
import {Tab, TabIndicator, TabList, TabListWrapper, TabPanel, TabsRoot} from "@heroui/react";
export function Basic() {
return (
<Tabs className="w-full max-w-md">
<Tabs.ListWrapper>
<Tabs.List aria-label="Options">
<Tabs.Tab id="overview">
<TabsRoot className="w-full max-w-md">
<TabListWrapper>
<TabList aria-label="Options">
<Tab id="overview">
Overview
<Tabs.Indicator />
</Tabs.Tab>
<Tabs.Tab id="analytics">
<TabIndicator />
</Tab>
<Tab id="analytics">
Analytics
<Tabs.Indicator />
</Tabs.Tab>
<Tabs.Tab id="reports">
<TabIndicator />
</Tab>
<Tab id="reports">
Reports
<Tabs.Indicator />
</Tabs.Tab>
</Tabs.List>
</Tabs.ListWrapper>
<Tabs.Panel className="pt-4" id="overview">
<TabIndicator />
</Tab>
</TabList>
</TabListWrapper>
<TabPanel className="pt-4" id="overview">
<p>View your project overview and recent activity.</p>
</Tabs.Panel>
<Tabs.Panel className="pt-4" id="analytics">
</TabPanel>
<TabPanel className="pt-4" id="analytics">
<p>Track your metrics and analyze performance data.</p>
</Tabs.Panel>
<Tabs.Panel className="pt-4" id="reports">
</TabPanel>
<TabPanel className="pt-4" id="reports">
<p>Generate and download detailed reports.</p>
</Tabs.Panel>
</Tabs>
</TabPanel>
</TabsRoot>
);
}
+19 -19
View File
@@ -1,33 +1,33 @@
"use client";
import {Tabs} from "@heroui/react";
import {Tab, TabIndicator, TabList, TabListWrapper, TabsRoot} from "@heroui/react";
export function CustomStyles() {
return (
<Tabs className="w-full max-w-lg text-center">
<Tabs.ListWrapper>
<Tabs.List
<TabsRoot className="w-full max-w-lg text-center">
<TabListWrapper>
<TabList
aria-label="Options"
className="*:data-[selected=true]:text-accent-foreground w-fit *:h-6 *:w-fit *:px-3 *:text-sm *:font-normal"
>
<Tabs.Tab id="daily">
<Tab id="daily">
Daily
<Tabs.Indicator className="bg-accent" />
</Tabs.Tab>
<Tabs.Tab id="weekly">
<TabIndicator className="bg-accent" />
</Tab>
<Tab id="weekly">
Weekly
<Tabs.Indicator className="bg-accent" />
</Tabs.Tab>
<Tabs.Tab id="bi-weekly">
<TabIndicator className="bg-accent" />
</Tab>
<Tab id="bi-weekly">
Bi-Weekly
<Tabs.Indicator className="bg-accent" />
</Tabs.Tab>
<Tabs.Tab id="monthly">
<TabIndicator className="bg-accent" />
</Tab>
<Tab id="monthly">
Monthly
<Tabs.Indicator className="bg-accent" />
</Tabs.Tab>
</Tabs.List>
</Tabs.ListWrapper>
</Tabs>
<TabIndicator className="bg-accent" />
</Tab>
</TabList>
</TabListWrapper>
</TabsRoot>
);
}

Some files were not shown because too many files have changed in this diff Show More