Beautiful and modern React UI library with comprehensive components, theming, and accessibility support.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
NextUI provides comprehensive components for presenting data, images, and content in organized, accessible formats with rich customization options.
A powerful data table component with sorting, selection, pagination, and customizable styling for complex data presentation.
interface TableProps<T = object> {
/** Table content */
children?: React.ReactNode;
/** Accessibility label */
"aria-label"?: string;
/** Accessibility label reference */
"aria-labelledby"?: string;
/** Accessibility description reference */
"aria-describedby"?: string;
/** Table layout algorithm */
layout?: "auto" | "fixed";
/** Hide table header */
hideHeader?: boolean;
/** Show selection checkboxes */
showSelectionCheckboxes?: boolean;
/** Color theme */
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
/** Selection mode */
selectionMode?: SelectionMode;
/** Selection behavior */
selectionBehavior?: SelectionBehavior;
/** Currently selected keys */
selectedKeys?: Selection;
/** Default selected keys */
defaultSelectedKeys?: Selection;
/** Prevent empty selection */
disallowEmptySelection?: boolean;
/** Sort configuration */
sortDescriptor?: SortDescriptor;
/** Whether header is sticky */
isHeaderSticky?: boolean;
/** Compact table spacing */
isCompact?: boolean;
/** Remove table wrapper */
removeWrapper?: boolean;
/** Striped rows */
isStriped?: boolean;
/** Full width table */
fullWidth?: boolean;
/** Bottom content (pagination, etc.) */
bottomContent?: React.ReactNode;
/** Bottom content placement */
bottomContentPlacement?: "inside" | "outside";
/** Top content */
topContent?: React.ReactNode;
/** Top content placement */
topContentPlacement?: "inside" | "outside";
/** Table checkboxes props */
checkboxesProps?: Partial<CheckboxProps>;
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<TableSlots>;
/** Selection change handler */
onSelectionChange?: (keys: Selection) => void;
/** Sort change handler */
onSortChange?: (descriptor: SortDescriptor) => void;
/** Row action handler */
onRowAction?: (key: React.Key) => void;
}
type TableSlots =
| "base" | "wrapper" | "table" | "thead" | "tbody" | "tr" | "th" | "td"
| "tfoot" | "sortIcon" | "emptyWrapper" | "loadingWrapper";
type SelectionMode = "none" | "single" | "multiple";
type SelectionBehavior = "toggle" | "replace";
type Selection = "all" | Set<React.Key>;
interface SortDescriptor {
/** Column key to sort by */
column?: React.Key;
/** Sort direction */
direction?: "ascending" | "descending";
}
function Table<T = object>(props: TableProps<T>): JSX.Element;
/**
* Hook for Table state management
*/
function useTable<T = object>(props: TableProps<T>): {
Component: React.ElementType;
slots: Record<TableSlots, string>;
classNames: SlotsToClasses<TableSlots>;
getTableProps: () => any;
getWrapperProps: () => any;
getBaseProps: () => any;
};Components for building table structure with proper accessibility and styling.
interface TableHeaderProps<T = object> {
/** Header columns */
children?: React.ReactNode;
/** Columns data for dynamic rendering */
columns?: T[];
/** Custom CSS class */
className?: string;
}
interface TableBodyProps<T = object> {
/** Table rows */
children?: React.ReactNode;
/** Items data for dynamic rendering */
items?: T[];
/** Loading state */
isLoading?: boolean;
/** Loading content */
loadingContent?: React.ReactNode;
/** Empty state content */
emptyContent?: React.ReactNode;
/** Custom CSS class */
className?: string;
}
interface TableColumnProps {
/** Column content */
children?: React.ReactNode;
/** Column key identifier */
key?: React.Key;
/** Whether column allows sorting */
allowsSorting?: boolean;
/** Column alignment */
align?: "start" | "center" | "end";
/** Whether to hide header text */
hideHeader?: boolean;
/** Column width */
width?: string | number;
/** Minimum column width */
minWidth?: string | number;
/** Maximum column width */
maxWidth?: string | number;
/** Custom CSS class */
className?: string;
}
interface TableRowProps<T = object> {
/** Row content */
children?: React.ReactNode;
/** Row key identifier */
key?: React.Key;
/** Whether row has action */
href?: string;
/** Custom CSS class */
className?: string;
}
interface TableCellProps {
/** Cell content */
children?: React.ReactNode;
/** Cell alignment */
align?: "start" | "center" | "end";
/** Custom CSS class */
className?: string;
}
function TableHeader<T = object>(props: TableHeaderProps<T>): JSX.Element;
function TableBody<T = object>(props: TableBodyProps<T>): JSX.Element;
function TableColumn(props: TableColumnProps): JSX.Element;
function TableRow<T = object>(props: TableRowProps<T>): JSX.Element;
function TableCell(props: TableCellProps): JSX.Element;Table Usage Example:
import {
Table, TableHeader, TableColumn, TableBody, TableRow, TableCell,
Button, Chip, User, Tooltip
} from "@nextui-org/react";
const users = [
{
id: 1,
name: "Tony Reichert",
role: "CEO",
team: "Management",
status: "active",
age: "29",
avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
email: "tony.reichert@example.com",
},
// ... more users
];
const statusColorMap = {
active: "success",
paused: "danger",
vacation: "warning",
};
function UsersTable() {
const [selectedKeys, setSelectedKeys] = useState<Selection>(new Set([]));
const [sortDescriptor, setSortDescriptor] = useState<SortDescriptor>({
column: "name",
direction: "ascending",
});
const renderCell = useCallback((user: User, columnKey: React.Key) => {
const cellValue = user[columnKey as keyof User];
switch (columnKey) {
case "name":
return (
<User
avatarProps={{radius: "lg", src: user.avatar}}
description={user.email}
name={cellValue}
>
{user.email}
</User>
);
case "role":
return (
<div className="flex flex-col">
<p className="text-bold text-sm capitalize">{cellValue}</p>
<p className="text-bold text-sm capitalize text-default-400">{user.team}</p>
</div>
);
case "status":
return (
<Chip className="capitalize" color={statusColorMap[user.status]} size="sm" variant="flat">
{cellValue}
</Chip>
);
case "actions":
return (
<div className="relative flex items-center gap-2">
<Tooltip content="Details">
<Button isIconOnly size="sm" variant="light">
<EyeIcon className="text-lg text-default-400" />
</Button>
</Tooltip>
<Tooltip content="Edit user">
<Button isIconOnly size="sm" variant="light">
<EditIcon className="text-lg text-default-400" />
</Button>
</Tooltip>
<Tooltip color="danger" content="Delete user">
<Button isIconOnly size="sm" variant="light">
<DeleteIcon className="text-lg text-danger" />
</Button>
</Tooltip>
</div>
);
default:
return cellValue;
}
}, []);
return (
<Table
aria-label="Users table with custom cells"
selectionMode="multiple"
selectedKeys={selectedKeys}
onSelectionChange={setSelectedKeys}
sortDescriptor={sortDescriptor}
onSortChange={setSortDescriptor}
classNames={{
wrapper: "min-h-[222px]",
}}
>
<TableHeader>
<TableColumn key="name" allowsSorting>NAME</TableColumn>
<TableColumn key="role" allowsSorting>ROLE</TableColumn>
<TableColumn key="status" allowsSorting>STATUS</TableColumn>
<TableColumn key="actions">ACTIONS</TableColumn>
</TableHeader>
<TableBody items={users}>
{(item) => (
<TableRow key={item.id}>
{(columnKey) => <TableCell>{renderCell(item, columnKey)}</TableCell>}
</TableRow>
)}
</TableBody>
</Table>
);
}/**
* Utility function to get value by key from object
* @param obj - Source object
* @param key - Key path (supports dot notation)
* @returns Value at key path
*/
function getKeyValue<T extends Record<string, any>>(
obj: T,
key: keyof T | string
): any;Profile image component with fallbacks, status indicators, and grouping capabilities.
interface AvatarProps {
/** Avatar image source */
src?: string;
/** Alt text for image */
alt?: string;
/** Name for generating initials fallback */
name?: string;
/** Custom icon fallback */
icon?: React.ReactNode;
/** Custom fallback element */
fallback?: React.ReactNode;
/** Avatar size */
size?: "sm" | "md" | "lg";
/** Border radius */
radius?: "none" | "sm" | "md" | "lg" | "full";
/** Color theme */
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
/** Add border */
isBordered?: boolean;
/** Disabled state */
isDisabled?: boolean;
/** Focusable for accessibility */
isFocusable?: boolean;
/** Show fallback when image fails */
showFallback?: boolean;
/** Image element ref */
imgRef?: React.RefObject<HTMLImageElement>;
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<AvatarSlots>;
/** Click handler */
onClick?: () => void;
}
type AvatarSlots = "base" | "img" | "fallback" | "name" | "icon";
function Avatar(props: AvatarProps): JSX.Element;
/**
* Hook for Avatar state management
*/
function useAvatar(props: AvatarProps): {
Component: React.ElementType;
slots: Record<AvatarSlots, string>;
classNames: SlotsToClasses<AvatarSlots>;
src?: string;
alt?: string;
name?: string;
showFallback: boolean;
getAvatarProps: () => any;
getImageProps: () => any;
};Container for displaying multiple avatars with overlap and count indicators.
interface AvatarGroupProps {
/** Avatar components */
children?: React.ReactNode;
/** Maximum avatars to show */
max?: number;
/** Avatar size (applies to all) */
size?: "sm" | "md" | "lg";
/** Color theme (applies to all) */
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
/** Border radius (applies to all) */
radius?: "none" | "sm" | "md" | "lg" | "full";
/** Add borders (applies to all) */
isBordered?: boolean;
/** Disabled state (applies to all) */
isDisabled?: boolean;
/** Grid layout instead of overlap */
isGrid?: boolean;
/** Total count for +N indicator */
total?: number;
/** Custom remaining count renderer */
renderCount?: (count: number) => React.ReactNode;
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<AvatarGroupSlots>;
}
type AvatarGroupSlots = "base" | "count";
function AvatarGroup(props: AvatarGroupProps): JSX.Element;
/**
* Hook for AvatarGroup state management
*/
function useAvatarGroup(props: AvatarGroupProps): {
Component: React.ElementType;
slots: Record<AvatarGroupSlots, string>;
classNames: SlotsToClasses<AvatarGroupSlots>;
remainingCount: number;
getAvatarGroupProps: () => any;
getCountProps: () => any;
};Avatar Usage Examples:
import { Avatar, AvatarGroup, AvatarIcon } from "@nextui-org/react";
function AvatarExamples() {
return (
<div className="space-y-6">
{/* Individual avatars */}
<div className="flex gap-4 items-center">
<Avatar src="https://i.pravatar.cc/150?u=a042581f4e29026024d" />
<Avatar name="Jane Doe" />
<Avatar
icon={<AvatarIcon />}
classNames={{
base: "bg-gradient-to-br from-[#FFB457] to-[#FF705B]",
icon: "text-black/80",
}}
/>
<Avatar isBordered color="primary" src="https://i.pravatar.cc/150?u=a04258a2462d826712d" />
</div>
{/* Avatar group */}
<AvatarGroup
isBordered
max={3}
total={10}
renderCount={(count) => (
<p className="text-small text-foreground font-medium ms-2">+{count} others</p>
)}
>
<Avatar src="https://i.pravatar.cc/150?u=a042581f4e29026024d" />
<Avatar src="https://i.pravatar.cc/150?u=a04258a2462d826712d" />
<Avatar src="https://i.pravatar.cc/150?u=a042581f4e29026704d" />
<Avatar src="https://i.pravatar.cc/150?u=a04258114e29026302d" />
<Avatar src="https://i.pravatar.cc/150?u=a04258114e29026708c" />
</AvatarGroup>
</div>
);
}Context system for sharing avatar group configuration.
interface AvatarGroupProviderProps {
children: React.ReactNode;
value: AvatarGroupContextValue;
}
interface AvatarGroupContextValue {
size?: "sm" | "md" | "lg";
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
radius?: "none" | "sm" | "md" | "lg" | "full";
isBordered?: boolean;
isDisabled?: boolean;
isGrid?: boolean;
}
const AvatarGroupProvider: React.FC<AvatarGroupProviderProps>;
/**
* Hook to access avatar group context
*/
function useAvatarGroupContext(): AvatarGroupContextValue | undefined;Notification indicator component for displaying counts, status, or labels.
interface BadgeProps {
/** Badge content (number, text, etc.) */
children?: React.ReactNode;
/** Badge content */
content?: React.ReactNode | number;
/** Badge color theme */
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
/** Badge size */
size?: "sm" | "md" | "lg";
/** Badge variant */
variant?: "solid" | "flat" | "faded" | "shadow";
/** Badge shape */
shape?: "circle" | "rectangle";
/** Badge placement on target */
placement?: "top-right" | "top-left" | "bottom-right" | "bottom-left";
/** Whether badge is invisible */
isInvisible?: boolean;
/** Whether to show border */
showOutline?: boolean;
/** Disable animations */
disableAnimation?: boolean;
/** Whether badge is one character */
isOneChar?: boolean;
/** Whether badge is dot style */
isDot?: boolean;
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<BadgeSlots>;
}
type BadgeSlots = "base" | "badge";
function Badge(props: BadgeProps): JSX.Element;
/**
* Hook for Badge state management
*/
function useBadge(props: BadgeProps): {
Component: React.ElementType;
slots: Record<BadgeSlots, string>;
classNames: SlotsToClasses<BadgeSlots>;
getBadgeProps: () => any;
getBaseProps: () => any;
};Badge Usage Examples:
import { Badge, Button, Avatar } from "@nextui-org/react";
function BadgeExamples() {
return (
<div className="space-y-4">
{/* Badge on button */}
<Badge color="danger" content={5}>
<Button variant="bordered">Notifications</Button>
</Badge>
{/* Badge on avatar */}
<Badge
color="success"
content=""
isDot
placement="bottom-right"
shape="circle"
>
<Avatar
radius="md"
src="https://i.pravatar.cc/150?u=a04258a2462d826712d"
/>
</Badge>
{/* Various badge styles */}
<div className="flex gap-4">
<Badge content="99+" color="danger" shape="circle">
<Button variant="bordered">Messages</Button>
</Badge>
<Badge content="New" color="primary" variant="shadow">
<Button variant="bordered">Feature</Button>
</Badge>
</div>
</div>
);
}Compact elements for displaying tags, categories, or selected options with optional actions.
interface ChipProps {
/** Chip content */
children?: React.ReactNode;
/** Chip variant */
variant?: "solid" | "bordered" | "light" | "flat" | "faded" | "shadow" | "dot";
/** Chip color theme */
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
/** Chip size */
size?: "sm" | "md" | "lg";
/** Border radius */
radius?: "none" | "sm" | "md" | "lg" | "full";
/** Avatar element */
avatar?: React.ReactNode;
/** Start content (icon, etc.) */
startContent?: React.ReactNode;
/** End content (icon, etc.) */
endContent?: React.ReactNode;
/** Close button */
onClose?: () => void;
/** Whether chip is disabled */
isDisabled?: boolean;
/** Whether chip is closeable */
isCloseButtonFocusVisible?: boolean;
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<ChipSlots>;
}
type ChipSlots = "base" | "content" | "dot" | "avatar" | "closeButton";
function Chip(props: ChipProps): JSX.Element;
/**
* Hook for Chip state management
*/
function useChip(props: ChipProps): {
Component: React.ElementType;
slots: Record<ChipSlots, string>;
classNames: SlotsToClasses<ChipSlots>;
hasStartContent: boolean;
hasEndContent: boolean;
hasCloseButton: boolean;
getChipProps: () => any;
getContentProps: () => any;
getCloseButtonProps: () => any;
};Chip Usage Examples:
import { Chip, Avatar } from "@nextui-org/react";
import { CheckIcon } from "@heroicons/react/24/solid";
function ChipExamples() {
return (
<div className="space-y-4">
{/* Basic chips */}
<div className="flex gap-2">
<Chip>Default</Chip>
<Chip color="primary">Primary</Chip>
<Chip color="secondary">Secondary</Chip>
<Chip color="success" variant="shadow">Success</Chip>
</div>
{/* Chips with content */}
<div className="flex gap-2">
<Chip
variant="flat"
color="success"
startContent={<CheckIcon />}
>
Verified
</Chip>
<Chip
variant="flat"
color="primary"
avatar={
<Avatar
name="JW"
size="sm"
getInitials={(name) => name.charAt(0)}
/>
}
>
John Wilson
</Chip>
</div>
{/* Closeable chips */}
<div className="flex gap-2">
<Chip
onClose={() => console.log("close")}
variant="flat"
>
Closeable
</Chip>
<Chip
onClose={() => console.log("close")}
variant="bordered"
color="danger"
>
Remove
</Chip>
</div>
</div>
);
}Inline code display component with syntax highlighting support and copy functionality.
interface CodeProps {
/** Code content */
children?: React.ReactNode;
/** Code size */
size?: "sm" | "md" | "lg";
/** Code color theme */
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
/** Border radius */
radius?: "none" | "sm" | "md" | "lg" | "full";
/** Disable animations */
disableAnimation?: boolean;
/** Custom CSS class */
className?: string;
}
function Code(props: CodeProps): JSX.Element;
/**
* Hook for Code state management
*/
function useCode(props: CodeProps): {
Component: React.ElementType;
getCodeProps: () => any;
};Code Usage Example:
import { Code } from "@nextui-org/react";
function CodeExample() {
return (
<div className="space-y-2">
<p>
Install the package by running{" "}
<Code color="primary">npm install @nextui-org/react</Code>
</p>
<p>
Then import the component:{" "}
<Code size="sm">
import {Button} from "@nextui-org/react"
</Code>
</p>
</div>
);
}Enhanced image component with loading states, zoom functionality, and fallback support.
interface ImageProps {
/** Image source URL */
src?: string;
/** Alternative text */
alt?: string;
/** Image width */
width?: number | string;
/** Image height */
height?: number | string;
/** Border radius */
radius?: "none" | "sm" | "md" | "lg" | "full";
/** Shadow intensity */
shadow?: "none" | "sm" | "md" | "lg";
/** Loading behavior */
loading?: "eager" | "lazy";
/** Remove wrapper */
removeWrapper?: boolean;
/** Zoom on hover */
isZoomed?: boolean;
/** Blur placeholder */
isBlurred?: boolean;
/** Fallback element */
fallbackSrc?: string;
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<ImageSlots>;
/** Load event handler */
onLoad?: () => void;
/** Error event handler */
onError?: () => void;
}
type ImageSlots = "wrapper" | "zoomedWrapper" | "img" | "fallback" | "blurredImg";
function Image(props: ImageProps): JSX.Element;
/**
* Hook for Image state management
*/
function useImage(props: ImageProps): {
Component: React.ElementType;
slots: Record<ImageSlots, string>;
classNames: SlotsToClasses<ImageSlots>;
isLoaded: boolean;
showFallback: boolean;
getImageProps: () => any;
getWrapperProps: () => any;
getBlurredImageProps: () => any;
};Image Usage Examples:
import { Image } from "@nextui-org/react";
function ImageExamples() {
return (
<div className="space-y-4">
{/* Basic image */}
<Image
width={300}
height={200}
alt="NextUI hero"
src="https://nextui.org/images/hero-card-complete.jpeg"
/>
{/* Zoomed image */}
<Image
isZoomed
width={240}
height={240}
alt="NextUI Fruit Image with Zoom"
src="https://nextui.org/images/fruit-1.jpeg"
/>
{/* Blurred image */}
<Image
isBlurred
width={240}
height={240}
src="https://nextui.org/images/fruit-2.jpeg"
alt="NextUI Album Cover"
classNames={{
img: "object-cover",
}}
/>
</div>
);
}Specialized component for displaying user profile information with avatar and details.
interface UserProps {
/** User name */
name?: React.ReactNode;
/** User description/subtitle */
description?: React.ReactNode;
/** User avatar image */
avatarSrc?: string;
/** Avatar props */
avatarProps?: Partial<AvatarProps>;
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<UserSlots>;
}
type UserSlots = "base" | "wrapper" | "name" | "description";
function User(props: UserProps): JSX.Element;
/**
* Hook for User state management
*/
function useUser(props: UserProps): {
Component: React.ElementType;
slots: Record<UserSlots, string>;
classNames: SlotsToClasses<UserSlots>;
getUserProps: () => any;
getWrapperProps: () => any;
getNameProps: () => any;
getDescriptionProps: () => any;
getAvatarProps: () => any;
};User Usage Example:
import { User } from "@nextui-org/react";
function UserExample() {
return (
<User
name="Jane Doe"
description="Product Designer"
avatarProps={{
src: "https://i.pravatar.cc/150?u=a04258114e29026702d",
size: "sm"
}}
/>
);
}// Common data display types
type DataDisplaySize = "sm" | "md" | "lg";
type DataDisplayColor = "default" | "primary" | "secondary" | "success" | "warning" | "danger";
type DataDisplayRadius = "none" | "sm" | "md" | "lg" | "full";
// Table specific types
interface TableState<T> {
collection: Collection<Node<T>>;
showSelectionCheckboxes: boolean;
selectionManager: SelectionManager;
sortDescriptor: SortDescriptor;
isHeaderSticky: boolean;
isEmpty: boolean;
isLoading: boolean;
}
// Selection types
interface SelectionManager {
selectedKeys: Selection;
isEmpty: boolean;
isSelectAll: boolean;
firstSelectedKey: React.Key | null;
lastSelectedKey: React.Key | null;
select(key: React.Key): void;
selectAll(): void;
deselect(key: React.Key): void;
clearSelection(): void;
toggle(key: React.Key): void;
replaceSelection(key: React.Key): void;
extendSelection(key: React.Key): void;
}
// Avatar types
interface AvatarState {
src?: string;
alt?: string;
name?: string;
showFallback: boolean;
isLoading: boolean;
hasError: boolean;
}
// Badge types
interface BadgeState {
content?: React.ReactNode | number;
isInvisible: boolean;
isDot: boolean;
isOneChar: boolean;
}
// Image types
interface ImageState {
src?: string;
isLoaded: boolean;
hasError: boolean;
showFallback: boolean;
isZoomed: boolean;
isBlurred: boolean;
}