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 feedback components for communicating system status, user notifications, loading states, and contextual information to enhance user experience.
Notification component for displaying important messages, warnings, and status information with customizable styling and actions.
interface AlertProps {
/** Alert content */
children?: React.ReactNode;
/** Alert title */
title?: React.ReactNode;
/** Alert description */
description?: React.ReactNode;
/** Alert color theme */
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
/** Alert variant */
variant?: "solid" | "bordered" | "light" | "flat" | "faded";
/** Border radius */
radius?: "none" | "sm" | "md" | "lg" | "full";
/** Start content (icon, etc.) */
startContent?: React.ReactNode;
/** End content (action buttons, etc.) */
endContent?: React.ReactNode;
/** Whether alert is closeable */
isClosable?: boolean;
/** Whether alert is visible */
isVisible?: boolean;
/** Default visibility state */
defaultVisible?: boolean;
/** Hide icon */
hideIconWrapper?: boolean;
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<AlertSlots>;
/** Close event handler */
onClose?: () => void;
/** Visibility change handler */
onVisibilityChange?: (isVisible: boolean) => void;
}
type AlertSlots =
| "base" | "wrapper" | "iconWrapper" | "icon"
| "mainWrapper" | "title" | "description"
| "closeButton" | "closeIcon";
function Alert(props: AlertProps): JSX.Element;
/**
* Hook for Alert state management
*/
function useAlert(props: AlertProps): {
Component: React.ElementType;
slots: Record<AlertSlots, string>;
classNames: SlotsToClasses<AlertSlots>;
isVisible: boolean;
getAlertProps: () => any;
getWrapperProps: () => any;
getIconWrapperProps: () => any;
getMainWrapperProps: () => any;
getTitleProps: () => any;
getDescriptionProps: () => any;
getCloseButtonProps: () => any;
};Alert Usage Examples:
import { Alert, Button } from "@nextui-org/react";
import { InfoIcon, CheckIcon, WarningIcon } from "@heroicons/react/24/solid";
function AlertExamples() {
const [isVisible, setIsVisible] = useState(true);
return (
<div className="space-y-4">
{/* Basic alerts */}
<Alert color="primary" title="Info Alert">
This is an informational message.
</Alert>
<Alert
color="success"
variant="bordered"
startContent={<CheckIcon className="w-5 h-5" />}
title="Success!"
description="Your action was completed successfully."
/>
<Alert
color="warning"
variant="flat"
startContent={<WarningIcon className="w-5 h-5" />}
title="Warning"
description="Please review the following items before continuing."
/>
<Alert
color="danger"
variant="light"
title="Error"
description="Something went wrong. Please try again."
endContent={
<Button color="danger" size="sm" variant="flat">
Retry
</Button>
}
/>
{/* Closeable alert */}
<Alert
color="secondary"
title="Dismissible Alert"
description="This alert can be closed by clicking the X button."
isClosable
isVisible={isVisible}
onVisibilityChange={setIsVisible}
/>
</div>
);
}Linear progress bar component for displaying completion status with customizable appearance and value formatting.
interface ProgressProps {
/** Progress label */
label?: React.ReactNode;
/** Progress size */
size?: "sm" | "md" | "lg";
/** Border radius */
radius?: "none" | "sm" | "md" | "lg" | "full";
/** Color theme */
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
/** Current progress value (0-100) */
value?: number;
/** Minimum value */
minValue?: number;
/** Maximum value */
maxValue?: number;
/** Indeterminate loading state */
isIndeterminate?: boolean;
/** Show value label */
showValueLabel?: boolean;
/** Custom value label */
valueLabel?: React.ReactNode;
/** Number formatting options */
formatOptions?: Intl.NumberFormatOptions;
/** Disabled state */
isDisabled?: boolean;
/** Disable animations */
disableAnimation?: boolean;
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<ProgressSlots>;
/** Value change handler */
onValueChange?: (value: number) => void;
}
type ProgressSlots = "base" | "labelWrapper" | "label" | "value" | "track" | "indicator";
function Progress(props: ProgressProps): JSX.Element;
/**
* Hook for Progress state management
*/
function useProgress(props: ProgressProps): {
Component: React.ElementType;
slots: Record<ProgressSlots, string>;
classNames: SlotsToClasses<ProgressSlots>;
progressBarProps: any;
labelProps: any;
percentage: number;
getProgressBarProps: () => any;
getLabelProps: () => any;
};Circular progress indicator for compact loading states and completion visualization.
interface CircularProgressProps {
/** Progress label */
label?: React.ReactNode;
/** Progress size */
size?: "sm" | "md" | "lg";
/** Color theme */
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
/** Current progress value (0-100) */
value?: number;
/** Minimum value */
minValue?: number;
/** Maximum value */
maxValue?: number;
/** Indeterminate loading state */
isIndeterminate?: boolean;
/** Show value label */
showValueLabel?: boolean;
/** Custom value label */
valueLabel?: React.ReactNode;
/** Number formatting options */
formatOptions?: Intl.NumberFormatOptions;
/** Disabled state */
isDisabled?: boolean;
/** Disable animations */
disableAnimation?: boolean;
/** Stroke width */
strokeWidth?: number;
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<CircularProgressSlots>;
/** Value change handler */
onValueChange?: (value: number) => void;
}
type CircularProgressSlots =
| "base" | "svgWrapper" | "svg" | "track" | "indicator"
| "value" | "label";
function CircularProgress(props: CircularProgressProps): JSX.Element;Progress Usage Examples:
import { Progress, CircularProgress, Button } from "@nextui-org/react";
function ProgressExamples() {
const [value, setValue] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setValue((v) => (v >= 100 ? 0 : v + 10));
}, 500);
return () => clearInterval(interval);
}, []);
return (
<div className="space-y-6">
{/* Linear progress */}
<div className="space-y-3">
<Progress
aria-label="Loading..."
size="md"
value={value}
color="success"
showValueLabel={true}
className="max-w-md"
/>
<Progress
label="Loading files..."
size="sm"
isIndeterminate
color="primary"
className="max-w-md"
/>
<Progress
size="lg"
radius="sm"
classNames={{
base: "max-w-md",
track: "drop-shadow-md border border-default",
indicator: "bg-gradient-to-r from-pink-500 to-yellow-500",
label: "tracking-wider font-medium text-default-600",
value: "text-foreground/60",
}}
label="Custom styled progress"
value={65}
showValueLabel={true}
/>
</div>
{/* Circular progress */}
<div className="flex gap-6 items-center">
<CircularProgress
aria-label="Loading..."
size="lg"
value={value}
color="warning"
showValueLabel={true}
/>
<CircularProgress
label="CPU Usage"
size="lg"
value={70}
color="danger"
formatOptions={{ style: "unit", unit: "percent" }}
showValueLabel={true}
/>
<CircularProgress
size="sm"
isIndeterminate
color="secondary"
aria-label="Loading..."
/>
</div>
</div>
);
}Loading spinner component for indicating processing states with various sizes and colors.
interface SpinnerProps {
/** Spinner label */
label?: React.ReactNode;
/** Spinner size */
size?: "sm" | "md" | "lg";
/** Spinner color */
color?: "current" | "white" | "default" | "primary" | "secondary" | "success" | "warning" | "danger";
/** Label color */
labelColor?: "foreground" | "primary" | "secondary" | "success" | "warning" | "danger";
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<SpinnerSlots>;
}
type SpinnerSlots = "base" | "wrapper" | "circle1" | "circle2" | "label";
function Spinner(props: SpinnerProps): JSX.Element;
/**
* Hook for Spinner state management
*/
function useSpinner(props: SpinnerProps): {
Component: React.ElementType;
slots: Record<SpinnerSlots, string>;
classNames: SlotsToClasses<SpinnerSlots>;
getSpinnerProps: () => any;
getWrapperProps: () => any;
getLabelProps: () => any;
};Spinner Usage Examples:
import { Spinner, Card, CardBody } from "@nextui-org/react";
function SpinnerExamples() {
return (
<div className="space-y-6">
{/* Basic spinners */}
<div className="flex gap-4 items-center">
<Spinner size="sm" />
<Spinner size="md" />
<Spinner size="lg" />
</div>
{/* Colored spinners */}
<div className="flex gap-4 items-center">
<Spinner color="primary" />
<Spinner color="secondary" />
<Spinner color="success" />
<Spinner color="warning" />
<Spinner color="danger" />
</div>
{/* Spinner with labels */}
<div className="flex flex-col gap-4">
<Spinner label="Loading..." />
<Spinner
label="Processing your request"
color="warning"
labelColor="warning"
/>
</div>
{/* Spinner in content */}
<Card>
<CardBody className="flex items-center justify-center py-8">
<Spinner
size="lg"
label="Loading content..."
color="primary"
/>
</CardBody>
</Card>
</div>
);
}Placeholder loading component that mimics content structure during data loading.
interface SkeletonProps {
/** Skeleton content */
children?: React.ReactNode;
/** Whether skeleton is loading */
isLoaded?: boolean;
/** Disable animations */
disableAnimation?: boolean;
/** Custom CSS class */
className?: string;
}
function Skeleton(props: SkeletonProps): JSX.Element;
/**
* Hook for Skeleton state management
*/
function useSkeleton(props: SkeletonProps): {
Component: React.ElementType;
getSkeletonProps: () => any;
};Skeleton Usage Examples:
import { Skeleton, Card, CardHeader, CardBody, Avatar } from "@nextui-org/react";
function SkeletonExamples() {
const [isLoaded, setIsLoaded] = useState(false);
useEffect(() => {
const timer = setTimeout(() => setIsLoaded(true), 3000);
return () => clearTimeout(timer);
}, []);
return (
<div className="space-y-6">
{/* Content skeleton */}
<Card className="w-[200px] space-y-5 p-4" radius="lg">
<Skeleton isLoaded={isLoaded} className="rounded-lg">
<div className="h-24 rounded-lg bg-secondary"></div>
</Skeleton>
<div className="space-y-3">
<Skeleton isLoaded={isLoaded} className="w-3/5 rounded-lg">
<div className="h-3 w-full rounded-lg bg-secondary"></div>
</Skeleton>
<Skeleton isLoaded={isLoaded} className="w-4/5 rounded-lg">
<div className="h-3 w-full rounded-lg bg-secondary-300"></div>
</Skeleton>
<Skeleton isLoaded={isLoaded} className="w-2/5 rounded-lg">
<div className="h-3 w-full rounded-lg bg-secondary-200"></div>
</Skeleton>
</div>
</Card>
{/* User profile skeleton */}
<Card className="max-w-[300px]">
<CardHeader className="justify-between">
<div className="flex gap-5">
<Skeleton isLoaded={isLoaded} className="flex rounded-full w-12 h-12">
<Avatar
isBordered
radius="full"
size="md"
src="https://nextui.org/avatars/avatar-1.png"
/>
</Skeleton>
<div className="flex flex-col gap-1 items-start justify-center">
<Skeleton isLoaded={isLoaded} className="w-20 rounded-lg">
<h4 className="text-small font-semibold leading-none text-default-600">
Zoey Lang
</h4>
</Skeleton>
<Skeleton isLoaded={isLoaded} className="w-16 rounded-lg">
<h5 className="text-small tracking-tight text-default-400">
@zoeylang
</h5>
</Skeleton>
</div>
</div>
<Skeleton isLoaded={isLoaded} className="rounded-lg">
<Button color="primary" radius="full" size="sm">
Follow
</Button>
</Skeleton>
</CardHeader>
<CardBody className="px-3 py-0 text-small text-default-400">
<Skeleton isLoaded={isLoaded} className="rounded-lg">
<p>
Frontend developer and UI/UX enthusiast. Join me on this coding adventure!
</p>
</Skeleton>
</CardBody>
</Card>
</div>
);
}Contextual information overlay that appears on hover or focus to provide additional details.
interface TooltipProps {
/** Target element to attach tooltip to */
children: React.ReactElement;
/** Tooltip content */
content?: React.ReactNode;
/** Whether tooltip is open */
isOpen?: boolean;
/** Default open state */
defaultOpen?: boolean;
/** Tooltip placement */
placement?: Placement;
/** Show delay in milliseconds */
delay?: number;
/** Close delay in milliseconds */
closeDelay?: number;
/** Disabled state */
isDisabled?: boolean;
/** Whether tooltip should flip to fit */
shouldFlip?: boolean;
/** Container padding for flip calculations */
containerPadding?: number;
/** Offset from target */
offset?: number;
/** Cross-axis offset */
crossOffset?: number;
/** Show arrow pointer */
showArrow?: boolean;
/** Border radius */
radius?: "none" | "sm" | "md" | "lg" | "full";
/** Tooltip size */
size?: "sm" | "md" | "lg";
/** Color theme */
color?: "default" | "foreground" | "primary" | "secondary" | "success" | "warning" | "danger";
/** Motion configuration */
motionProps?: MotionProps;
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<TooltipSlots>;
/** Open change handler */
onOpenChange?: (isOpen: boolean) => void;
}
type TooltipSlots = "base" | "arrow" | "content";
type Placement =
| "top" | "top-start" | "top-end"
| "bottom" | "bottom-start" | "bottom-end"
| "right" | "right-start" | "right-end"
| "left" | "left-start" | "left-end";
function Tooltip(props: TooltipProps): JSX.Element;
/**
* Hook for Tooltip state management
*/
function useTooltip(props: TooltipProps): {
Component: React.ElementType;
isOpen: boolean;
disableAnimation: boolean;
getTooltipProps: () => any;
getTriggerProps: () => any;
getTooltipContentProps: () => any;
};Tooltip Usage Examples:
import { Tooltip, Button } from "@nextui-org/react";
import { DeleteIcon, EditIcon, EyeIcon } from "@heroicons/react/24/solid";
function TooltipExamples() {
return (
<div className="space-y-6">
{/* Basic tooltips */}
<div className="flex gap-4 items-center">
<Tooltip content="I am a tooltip">
<Button>Hover me</Button>
</Tooltip>
<Tooltip content="Tooltip with arrow" showArrow>
<Button color="primary">With Arrow</Button>
</Tooltip>
</div>
{/* Colored tooltips */}
<div className="flex gap-4 items-center">
<Tooltip content="Edit" color="success" showArrow>
<Button isIconOnly color="success" variant="light">
<EditIcon className="w-4 h-4" />
</Button>
</Tooltip>
<Tooltip content="View" color="secondary" showArrow>
<Button isIconOnly color="secondary" variant="light">
<EyeIcon className="w-4 h-4" />
</Button>
</Tooltip>
<Tooltip content="Delete" color="danger" showArrow>
<Button isIconOnly color="danger" variant="light">
<DeleteIcon className="w-4 h-4" />
</Button>
</Tooltip>
</div>
{/* Placement variations */}
<div className="flex flex-wrap gap-4">
{["top", "bottom", "left", "right"].map((placement) => (
<Tooltip
key={placement}
content={`Tooltip on ${placement}`}
placement={placement as Placement}
showArrow
>
<Button variant="bordered" className="capitalize">
{placement}
</Button>
</Tooltip>
))}
</div>
{/* Custom content tooltip */}
<Tooltip
showArrow
content={
<div className="px-1 py-2">
<div className="text-small font-bold">Custom Content</div>
<div className="text-tiny">This tooltip has custom styling</div>
</div>
}
>
<Button color="secondary" variant="flat">
Custom Content
</Button>
</Tooltip>
</div>
);
}// Common feedback types
type FeedbackSize = "sm" | "md" | "lg";
type FeedbackColor = "default" | "primary" | "secondary" | "success" | "warning" | "danger";
type FeedbackRadius = "none" | "sm" | "md" | "lg" | "full";
// Alert types
interface AlertState {
isVisible: boolean;
isClosable: boolean;
color: FeedbackColor;
variant: "solid" | "bordered" | "light" | "flat" | "faded";
}
// Progress types
interface ProgressState {
value: number;
minValue: number;
maxValue: number;
percentage: number;
isIndeterminate: boolean;
valueLabel: string;
}
// Tooltip types
interface TooltipState {
isOpen: boolean;
placement: Placement;
isDisabled: boolean;
showArrow: boolean;
delay: number;
closeDelay: number;
}
// Motion configuration for animations
interface MotionProps {
initial?: any;
animate?: any;
exit?: any;
transition?: any;
variants?: any;
whileHover?: any;
whileTap?: any;
whileFocus?: any;
whileInView?: any;
}
// Placement type for positioning
type PlacementAxis = "top" | "bottom" | "left" | "right";
type PlacementAlign = "start" | "end";
type Placement = PlacementAxis | `${PlacementAxis}-${PlacementAlign}`;
// Number formatting for progress values
interface ProgressFormatOptions extends Intl.NumberFormatOptions {
style?: "decimal" | "currency" | "percent" | "unit";
unit?: string;
currency?: string;
minimumFractionDigits?: number;
maximumFractionDigits?: number;
}import {
Skeleton, Spinner, Progress, Alert, Button, Card, CardBody
} from "@nextui-org/react";
function LoadingStatesExample() {
const [loadingState, setLoadingState] = useState<'idle' | 'loading' | 'error' | 'success'>('idle');
const [progress, setProgress] = useState(0);
const handleAction = async () => {
setLoadingState('loading');
setProgress(0);
try {
// Simulate progress updates
for (let i = 0; i <= 100; i += 10) {
setProgress(i);
await new Promise(resolve => setTimeout(resolve, 200));
}
setLoadingState('success');
} catch (error) {
setLoadingState('error');
}
};
return (
<div className="space-y-6 max-w-md">
{loadingState === 'loading' && (
<Card>
<CardBody className="space-y-4">
<div className="flex items-center gap-4">
<Spinner size="sm" color="primary" />
<span>Processing...</span>
</div>
<Progress
value={progress}
color="primary"
showValueLabel
/>
</CardBody>
</Card>
)}
{loadingState === 'success' && (
<Alert
color="success"
title="Success!"
description="Your action was completed successfully."
/>
)}
{loadingState === 'error' && (
<Alert
color="danger"
title="Error"
description="Something went wrong. Please try again."
endContent={
<Button
color="danger"
variant="flat"
size="sm"
onPress={() => setLoadingState('idle')}
>
Retry
</Button>
}
/>
)}
<Button
color="primary"
onPress={handleAction}
isDisabled={loadingState === 'loading'}
>
{loadingState === 'loading' ? 'Processing...' : 'Start Action'}
</Button>
</div>
);
}import { Alert, Button } from "@nextui-org/react";
function NotificationSystem() {
const [notifications, setNotifications] = useState<Array<{
id: string;
type: 'success' | 'warning' | 'danger' | 'info';
title: string;
message: string;
}>>([]);
const addNotification = (type: string, title: string, message: string) => {
const notification = {
id: Date.now().toString(),
type,
title,
message,
};
setNotifications(prev => [...prev, notification]);
// Auto remove after 5 seconds
setTimeout(() => {
removeNotification(notification.id);
}, 5000);
};
const removeNotification = (id: string) => {
setNotifications(prev => prev.filter(n => n.id !== id));
};
return (
<div className="space-y-4">
{/* Notification triggers */}
<div className="flex gap-2">
<Button
color="success"
onPress={() => addNotification('success', 'Success', 'Operation completed successfully!')}
>
Success
</Button>
<Button
color="warning"
onPress={() => addNotification('warning', 'Warning', 'Please review your input.')}
>
Warning
</Button>
<Button
color="danger"
onPress={() => addNotification('danger', 'Error', 'Something went wrong.')}
>
Error
</Button>
</div>
{/* Notifications display */}
<div className="fixed top-4 right-4 space-y-2 z-50">
{notifications.map((notification) => (
<Alert
key={notification.id}
color={notification.type}
title={notification.title}
description={notification.message}
isClosable
onClose={() => removeNotification(notification.id)}
className="max-w-sm"
/>
))}
</div>
</div>
);
}