moai-lib-shadcn-ui

moai-lib-shadcn-ui: Enterprise Component Library

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "moai-lib-shadcn-ui" with this command: npx skills add jg-chalk-io/nora-livekit/jg-chalk-io-nora-livekit-moai-lib-shadcn-ui

moai-lib-shadcn-ui: Enterprise Component Library

AI-powered shadcn/ui with design system architecture for modern React applications

Trust Score: 9.7/10 | Version: 4.0.0 | Last Updated: 2025-11-20

Overview

Enterprise shadcn/ui Component Library expert with:

  • Component System: 40+ production-ready components

  • Design Tokens: Comprehensive theming with CSS variables

  • Accessibility: WCAG 2.1 AA compliance with Radix UI primitives

  • TypeScript: Full type safety with modern patterns

  • Performance: Optimized bundle size and runtime performance

Foundation Technologies:

  • React 19 with server components

  • TypeScript 5.5 for type safety

  • Tailwind CSS 3.4 with JIT compilation

  • Radix UI for accessible primitives

  • Framer Motion for animations

Core Components

Button Component

// components/ui/button.tsx import * as React from "react"; import { Slot } from "@radix-ui/react-slot"; import { cva, type VariantProps } from "class-variance-authority"; import { cn } from "@/lib/utils";

const buttonVariants = cva( "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50", { variants: { variant: { default: "bg-primary text-primary-foreground shadow hover:bg-primary/90", destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline", }, size: { default: "h-9 px-4 py-2", sm: "h-8 rounded-md px-3 text-xs", lg: "h-10 rounded-md px-8", icon: "h-9 w-9", }, }, defaultVariants: { variant: "default", size: "default", }, } );

export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> { asChild?: boolean; loading?: boolean; loadingText?: string; }

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( ({ className, variant, size, asChild = false, loading, loadingText, children, disabled, ...props }, ref) => { const Comp = asChild ? Slot : "button";

return (
  &#x3C;Comp
    className={cn(buttonVariants({ variant, size, className }))}
    ref={ref}
    disabled={disabled || loading}
    aria-disabled={disabled || loading}
    aria-describedby={loading ? "loading-description" : undefined}
    {...props}
  >
    {loading &#x26;&#x26; (
      &#x3C;div className="mr-2 h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent" />
    )}

    {loading &#x26;&#x26; loadingText ? (
      &#x3C;span id="loading-description" className="sr-only">
        {loadingText}
      &#x3C;/span>
    ) : null}

    {loading ? loadingText || children : children}
  &#x3C;/Comp>
);

} );

Button.displayName = "Button"; export { Button, buttonVariants };

Form Components

// components/ui/form.tsx import * as React from "react"; import { Slot } from "@radix-ui/react-slot"; import { Controller, ControllerProps, FieldPath, FieldValues, useFormContext, } from "react-hook-form"; import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "./form";

const Form = Form;

interface FormFieldContextValue< TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>

{ name: TName; }

const FormFieldContext = React.createContext<FormFieldContextValue>( {} as FormFieldContextValue );

const FormField = < TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>

({ ...props }: ControllerProps<TFieldValues, TName>) => { return ( <FormFieldContext.Provider value={{ name: props.name }}> <Controller {...props} /> </FormFieldContext.Provider> ); };

const useFormField = () => { const fieldContext = React.useContext(FormFieldContext); const itemContext = React.useContext(FormItemContext); const { getFieldState, formState } = useFormContext();

const fieldState = getFieldState(fieldContext.name, formState);

if (!fieldContext) { throw new Error("useFormField should be used within <FormField>"); }

const { id } = itemContext;

return { id, name: fieldContext.name, formItemId: ${id}-form-item, formDescriptionId: ${id}-form-item-description, formMessageId: ${id}-form-item-message, ...fieldState, }; };

// Input Component const FormItem = React.forwardRef< HTMLDivElement, React.HTMLAttributes<HTMLDivElement>

(({ className, ...props }, ref) => ( <div ref={ref} className={cn("space-y-2", className)} {...props} /> )); FormItem.displayName = "FormItem";

const FormLabel = React.forwardRef< React.ElementRef<typeof Label>, React.ComponentPropsWithoutRef<typeof Label>

(({ className, ...props }, ref) => ( <Label ref={ref} className={cn("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", className)} {...props} /> )); FormLabel.displayName = "FormLabel";

const FormControl = React.forwardRef< React.ElementRef<typeof Slot>, React.ComponentPropsWithoutRef<typeof Slot>

(({ ...props }, ref) => ( <Slot ref={ref} className={cn( "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50", props.className )} {...props} /> )); FormControl.displayName = "FormControl";

const FormDescription = React.forwardRef< HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>

(({ className, ...props }, ref) => ( <p ref={ref} className={cn("text-[0.8rem] text-muted-foreground", className)} {...props} /> )); FormDescription.displayName = "FormDescription";

const FormMessage = React.forwardRef< HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>

(({ className, children, ...props }, ref) => { const { error } = useFormState(); const message = error ? String(error?.message) : children;

if (!message) { return null; }

return ( <p ref={ref} className={cn("text-[0.8rem] font-medium text-destructive", className)} {...props} > {message} </p> ); }); FormMessage.displayName = "FormMessage";

export { useFormField, Form, FormItem, FormLabel, FormControl, FormDescription, FormMessage, FormField, };

Card Component

// components/ui/card.tsx import * as React from "react"; import { cn } from "@/lib/utils";

const Card = React.forwardRef< HTMLDivElement, React.HTMLAttributes<HTMLDivElement>

(({ className, ...props }, ref) => ( <div ref={ref} className={cn( "rounded-xl border bg-card text-card-foreground shadow", className )} {...props} /> )); Card.displayName = "Card";

const CardHeader = React.forwardRef< HTMLDivElement, React.HTMLAttributes<HTMLDivElement>

(({ className, ...props }, ref) => ( <div ref={ref} className={cn("flex flex-col space-y-1.5 p-6", className)} {...props} /> )); CardHeader.displayName = "CardHeader";

const CardTitle = React.forwardRef< HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>

(({ className, ...props }, ref) => ( <h3 ref={ref} className={cn("font-semibold leading-none tracking-tight", className)} {...props} /> )); CardTitle.displayName = "CardTitle";

const CardDescription = React.forwardRef< HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>

(({ className, ...props }, ref) => ( <p ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} /> )); CardDescription.displayName = "CardDescription";

const CardContent = React.forwardRef< HTMLDivElement, React.HTMLAttributes<HTMLDivElement>

(({ className, ...props }, ref) => ( <div ref={ref} className={cn("p-6 pt-0", className)} {...props} /> )); CardContent.displayName = "CardContent";

const CardFooter = React.forwardRef< HTMLDivElement, React.HTMLAttributes<HTMLDivElement>

(({ className, ...props }, ref) => ( <div ref={ref} className={cn("flex items-center p-6 pt-0", className)} {...props} /> )); CardFooter.displayName = "CardFooter";

export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };

Theme System

Theme Provider

// components/theme-provider.tsx import { createContext, useContext, useEffect, useState } from "react";

type Theme = "dark" | "light" | "system";

interface ThemeProviderProps { children: React.ReactNode; defaultTheme?: Theme; storageKey?: string; attribute?: string; enableSystem?: boolean; }

interface ThemeProviderState { theme: Theme; setTheme: (theme: Theme) => void; }

const ThemeProviderContext = createContext<ThemeProviderState | undefined>(undefined);

export function ThemeProvider({ children, defaultTheme = "system", storageKey = "ui-theme", attribute = "class", enableSystem = true, ...props }: ThemeProviderProps) { const [theme, setTheme] = useState<Theme>(() => { if (typeof window !== "undefined") { return (localStorage.getItem(storageKey) as Theme) || defaultTheme; } return defaultTheme; });

useEffect(() => { const root = window.document.documentElement; root.classList.remove("light", "dark");

if (theme === "system" &#x26;&#x26; enableSystem) {
  const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
    .matches
    ? "dark"
    : "light";
  root.classList.add(systemTheme);
  return;
}

root.classList.add(theme);

}, [theme, enableSystem, attribute]);

const value = { theme, setTheme: (theme: Theme) => { localStorage.setItem(storageKey, theme); setTheme(theme); }, };

return ( <ThemeProviderContext.Provider {...props} value={value}> {children} </ThemeProviderContext.Provider> ); }

export const useTheme = () => { const context = useContext(ThemeProviderContext); if (context === undefined) throw new Error("useTheme must be used within a ThemeProvider"); return context; };

CSS Variables for Theming

/* globals.css */ :root { --background: 0 0% 100%; --foreground: 240 10% 3.9%; --card: 0 0% 100%; --card-foreground: 240 10% 3.9%; --popover: 0 0% 100%; --popover-foreground: 240 10% 3.9%; --primary: 240 9% 10%; --primary-foreground: 0 0% 98%; --secondary: 240 4.8% 95.9%; --secondary-foreground: 240 5.9% 10%; --muted: 240 4.8% 95.9%; --muted-foreground: 240 3.8% 46.1%; --accent: 240 4.8% 95.9%; --accent-foreground: 240 5.9% 10%; --destructive: 0 72% 51%; --destructive-foreground: 0 0% 98%; --border: 240 5.9% 90%; --input: 240 5.9% 90%; --ring: 240 5.9% 10%; --radius: 0.5rem; }

.dark { --background: 240 10% 3.9%; --foreground: 0 0% 98%; --card: 240 10% 3.9%; --card-foreground: 0 0% 98%; --popover: 240 10% 3.9%; --popover-foreground: 0 0% 98%; --primary: 0 0% 98%; --primary-foreground: 240 5.9% 10%; --secondary: 240 3.7% 15.9%; --secondary-foreground: 0 0% 98%; --muted: 240 3.7% 15.9%; --muted-foreground: 240 5% 64.9%; --accent: 240 3.7% 15.9%; --accent-foreground: 0 0% 98%; --destructive: 0 72% 51%; --destructive-foreground: 0 0% 98%; --border: 240 3.7% 15.9%; --input: 240 3.7% 15.9%; --ring: 240 4.9% 83.9%; }

Advanced Components

Data Table Component

// components/ui/data-table.tsx import * as React from "react"; import { ColumnDef, ColumnFiltersState, SortingState, VisibilityState, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table"; import { ArrowUpDown, ChevronDown, MoreHorizontal } from "lucide-react"; import { Button } from "./button"; import { Checkbox } from "./checkbox"; import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "./dropdown-menu"; import { Input } from "./input"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "./table";

interface DataTableProps<TData, TValue> { columns: ColumnDef<TData, TValue>[]; data: TData[]; }

export function DataTable<TData, TValue>({ columns, data, }: DataTableProps<TData, TValue>) { const [sorting, setSorting] = React.useState<SortingState>([]); const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([]); const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({}); const [rowSelection, setRowSelection] = React.useState({});

const table = useReactTable({ data, columns, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), onColumnVisibilityChange: setColumnVisibility, onRowSelectionChange: setRowSelection, state: { sorting, columnFilters, columnVisibility, rowSelection, }, });

return ( <div className="w-full"> <div className="flex items-center py-4"> <Input placeholder="Filter emails..." value={(table.getColumn("email")?.getFilterValue() as string) ?? ""} onChange={(event) => table.getColumn("email")?.setFilterValue(event.target.value) } className="max-w-sm" /> <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="outline" className="ml-auto"> Columns <ChevronDown className="ml-2 h-4 w-4" /> </Button> </DropdownMenuTrigger> <DropdownMenuContent align="end"> {table .getAllColumns() .filter((column) => column.getCanHide()) .map((column) => { return ( <DropdownMenuCheckboxItem key={column.id} className="capitalize" checked={column.getIsVisible()} onCheckedChange={(value) => column.toggleVisibility(!!value) } > {column.id} </DropdownMenuCheckboxItem> ); })} </DropdownMenuContent> </DropdownMenu> </div> <div className="rounded-md border"> <Table> <TableHeader> {table.getHeaderGroups().map((headerGroup) => ( <TableRow key={headerGroup.id}> {headerGroup.headers.map((header) => { return ( <TableHead key={header.id}> {header.isPlaceholder ? null : flexRender( header.column.columnDef.header, header.getContext() )} </TableHead> ); })} </TableRow> ))} </TableHeader> <TableBody> {table.getRowModel().rows?.length ? ( table.getRowModel().rows.map((row) => ( <TableRow key={row.id} data-state={row.getIsSelected() && "selected"} > {row.getVisibleCells().map((cell) => ( <TableCell key={cell.id}> {flexRender(cell.column.columnDef.cell, cell.getContext())} </TableCell> ))} </TableRow> )) ) : ( <TableRow> <TableCell colSpan={columns.length} className="h-24 text-center"> No results. </TableCell> </TableRow> )} </TableBody> </Table> </div> <div className="flex items-center justify-end space-x-2 py-4"> <div className="flex-1 text-sm text-muted-foreground"> {table.getFilteredSelectedRowModel().rows.length} of{" "} {table.getFilteredRowModel().rows.length} row(s) selected. </div> <div className="space-x-2"> <Button variant="outline" size="sm" onClick={() => table.previousPage()} disabled={!table.getCanPreviousPage()} > Previous </Button> <Button variant="outline" size="sm" onClick={() => table.nextPage()} disabled={!table.getCanNextPage()} > Next </Button> </div> </div> </div> ); }

Dialog Component

// components/ui/dialog.tsx import * as React from "react"; import * as DialogPrimitive from "@radix-ui/react-dialog"; import { X } from "lucide-react"; import { cn } from "@/lib/utils";

const Dialog = DialogPrimitive.Root; const DialogTrigger = DialogPrimitive.Trigger; const DialogPortal = DialogPrimitive.Portal; const DialogClose = DialogPrimitive.Close;

const DialogOverlay = React.forwardRef< React.ElementRef<typeof DialogPrimitive.Overlay>, React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>

(({ className, ...props }, ref) => ( <DialogPrimitive.Overlay ref={ref} className={cn( "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", className )} {...props} /> )); DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;

const DialogContent = React.forwardRef< React.ElementRef<typeof DialogPrimitive.Content>, React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>

(({ className, children, ...props }, ref) => ( <DialogPortal> <DialogOverlay /> <DialogPrimitive.Content ref={ref} className={cn( "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", className )} {...props} > {children} <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"> <X className="h-4 w-4" /> <span className="sr-only">Close</span> </DialogPrimitive.Close> </DialogPrimitive.Content> </DialogPortal> )); DialogContent.displayName = DialogPrimitive.Content.displayName;

const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => ( <div className={cn( "flex flex-col space-y-1.5 text-center sm:text-left", className )} {...props} /> ); DialogHeader.displayName = "DialogHeader";

const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => ( <div className={cn( "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className )} {...props} /> ); DialogFooter.displayName = "DialogFooter";

const DialogTitle = React.forwardRef< React.ElementRef<typeof DialogPrimitive.Title>, React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>

(({ className, ...props }, ref) => ( <DialogPrimitive.Title ref={ref} className={cn( "text-lg font-semibold leading-none tracking-tight", className )} {...props} /> )); DialogTitle.displayName = DialogPrimitive.Title.displayName;

const DialogDescription = React.forwardRef< React.ElementRef<typeof DialogPrimitive.Description>, React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>

(({ className, ...props }, ref) => ( <DialogPrimitive.Description ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} /> )); DialogDescription.displayName = DialogPrimitive.Description.displayName;

export { Dialog, DialogPortal, DialogOverlay, DialogClose, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, };

Form Validation

React Hook Form Integration

// hooks/use-form-validation.ts import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod";

// Example schema const userSchema = z.object({ username: z.string().min(2, "Username must be at least 2 characters"), email: z.string().email("Please enter a valid email"), password: z.string().min(8, "Password must be at least 8 characters"), confirmPassword: z.string().refine( (data) => data.password === data.confirmPassword, { message: "Passwords don't match", path: ["confirmPassword"], } ), });

type UserFormData = z.infer<typeof userSchema>;

export function useUserForm() { return useForm<UserFormData>({ resolver: zodResolver(userSchema), defaultValues: { username: "", email: "", password: "", confirmPassword: "", }, mode: "onBlur", }); }

// Custom validation hook export function useFormValidation<T extends Record<string, any>>( schema: z.ZodSchema<T>, defaultValues?: Partial<T> ) { return useForm<T>({ resolver: zodResolver(schema), defaultValues, mode: "onBlur", }); }

Utility Functions

cn utility

// lib/utils.ts import { type ClassValue, clsx } from "clsx"; import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); }

// Format utilities export function formatBytes( bytes: number, opts: { decimals?: number; sizeType?: "accurate" | "normal"; } = {} ) { const { decimals = 0, sizeType = "normal" } = opts;

const sizes = ["Bytes", "KB", "MB", "GB", "TB"]; const accurateSizes = ["Bytes", "KiB", "MiB", "GiB", "TiB"]; if (bytes === 0) return "0 Bytes"; const i = Math.floor(Math.log(bytes) / Math.log(1024)); return ${(bytes / Math.pow(1024, i)).toFixed(decimals)} ${ sizeType === "accurate" ? accurateSizes[i] ?? "Bytes" : sizes[i] ?? "Bytes" }; }

// Date utilities export function formatDate(date: Date | string | number) { return new Intl.DateTimeFormat("en-US", { month: "long", day: "numeric", year: "numeric", }).format(new Date(date)); }

Usage Examples

Form Implementation

// components/forms/user-form.tsx import { useUserForm } from "@/hooks/use-form-validation"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form";

export function UserRegistrationForm() { const form = useUserForm();

function onSubmit(values: UserFormData) { console.log(values); // Handle form submission }

return ( <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8"> <FormField control={form.control} name="username" render={({ field }) => ( <FormItem> <FormLabel>Username</FormLabel> <FormControl> <Input placeholder="Enter username" {...field} /> </FormControl> <FormDescription> This is your public display name. </FormDescription> <FormMessage /> </FormItem> )} />

    &#x3C;FormField
      control={form.control}
      name="email"
      render={({ field }) => (
        &#x3C;FormItem>
          &#x3C;FormLabel>Email&#x3C;/FormLabel>
          &#x3C;FormControl>
            &#x3C;Input type="email" placeholder="Enter email" {...field} />
          &#x3C;/FormControl>
          &#x3C;FormMessage />
        &#x3C;/FormItem>
      )}
    />

    &#x3C;FormField
      control={form.control}
      name="password"
      render={({ field }) => (
        &#x3C;FormItem>
          &#x3C;FormLabel>Password&#x3C;/FormLabel>
          &#x3C;FormControl>
            &#x3C;Input type="password" placeholder="Enter password" {...field} />
          &#x3C;/FormControl>
          &#x3C;FormMessage />
        &#x3C;/FormItem>
      )}
    />

    &#x3C;Button type="submit">Register&#x3C;/Button>
  &#x3C;/form>
&#x3C;/Form>

); }

Accessibility Features

ARIA Labels and Roles

// components/ui/accessible-button.tsx import { forwardRef } from "react"; import { Button } from "./button";

interface AccessibleButtonProps { children: React.ReactNode; ariaLabel?: string; ariaDescribedBy?: string; isLoading?: boolean; disabled?: boolean; }

export const AccessibleButton = forwardRef<HTMLButtonElement, AccessibleButtonProps>( ({ children, ariaLabel, ariaDescribedBy, isLoading, disabled, ...props }, ref) => { return ( <Button ref={ref} disabled={disabled || isLoading} aria-label={ariaLabel} aria-describedby={ariaDescribedBy} aria-busy={isLoading} {...props} > {isLoading && ( <span className="mr-2" aria-hidden="true"> <div className="h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent" /> </span> )} {children} </Button> ); } );

Performance Optimization

Lazy Loading Components

// components/ui/lazy-component.tsx import dynamic from "next/dynamic";

export const LazyChart = dynamic( () => import("recharts").then((mod) => mod.LineChart), { loading: () => <div className="h-64 w-full animate-pulse bg-muted" />, ssr: false, } );

export const LazyDataTable = dynamic( () => import("./data-table").then((mod) => mod.DataTable), { loading: () => <div className="h-96 w-full animate-pulse bg-muted" />, ssr: false, } );

Quick Reference

Essential Commands

Install shadcn/ui

npx shadcn-ui@latest init

Add components

npx shadcn-ui@latest add button npx shadcn-ui@latest add card npx shadcn-ui@latest add input npx shadcn-ui@latest add dialog

Update components

npx shadcn-ui@latest add button --overwrite

CLI help

npx shadcn-ui@latest --help

Component Structure

components/ ├── ui/ │ ├── button.tsx │ ├── input.tsx │ ├── card.tsx │ ├── dialog.tsx │ ├── form.tsx │ └── index.ts ├── forms/ │ └── user-form.tsx └── hooks/ └── use-form-validation.ts

Last Updated: 2025-11-20 Status: Production Ready | Enterprise Approved Features: 40+ Components, Theme System, Accessibility, TypeScript Support

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

moai-playwright-webapp-testing

No summary provided by upstream source.

Repository SourceNeeds Review
General

moai-lang-r

No summary provided by upstream source.

Repository SourceNeeds Review
General

moai-core-config-schema

No summary provided by upstream source.

Repository SourceNeeds Review
General

moai-baas-convex-ext

No summary provided by upstream source.

Repository SourceNeeds Review