{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "switch", "title": "Integrated Switch", "description": "Thin labeled Switch wrapper with optional description, accessible label and description wiring, primitive state and form behavior, and explicit control, option, and text class ownership.", "registryDependencies": [ "switch" ], "files": [ { "path": "registry/ui/switch.tsx", "content": "\"use client\";\n\nimport type { ClassValue } from \"clsx\";\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { useId } from \"react\";\nimport { Switch as SwitchControl } from \"@/components/ui/switch\";\nimport { cn } from \"@/lib/utils\";\n\nconst WHITESPACE_PATTERN = /\\s+/;\n\ntype SwitchControlProps = ComponentProps;\n\nexport interface SwitchProps\n extends Omit<\n SwitchControlProps,\n | \"children\"\n | \"className\"\n | \"dangerouslySetInnerHTML\"\n | \"nativeButton\"\n | \"render\"\n > {\n /** Class override for the visible Switch control. */\n className?: ClassValue;\n /** Optional supporting content announced after the label. */\n description?: ReactNode;\n /** Class override for the description content. */\n descriptionClassName?: ClassValue;\n /** Required caller-owned content that names the switch. */\n label: ReactNode;\n /** Class override for the label content. */\n labelClassName?: ClassValue;\n /** Class override for the outer option layout. */\n optionClassName?: ClassValue;\n}\n\nconst hasNode = (node: ReactNode): boolean =>\n node !== null && node !== undefined && typeof node !== \"boolean\";\n\nconst mergeIds = (...values: (string | undefined)[]): string | undefined => {\n const tokens = values\n .flatMap((value) => value?.split(WHITESPACE_PATTERN) ?? [])\n .filter(Boolean);\n const merged = [...new Set(tokens)].join(\" \");\n\n return merged || undefined;\n};\n\nexport const Switch = ({\n \"aria-describedby\": ariaDescribedBy,\n \"aria-labelledby\": ariaLabelledBy,\n className,\n description,\n descriptionClassName,\n label,\n labelClassName,\n optionClassName,\n id,\n ...controlProps\n}: SwitchProps) => {\n const autoId = useId();\n const controlId = id ?? `${autoId}-control`;\n const labelId = `${autoId}-label`;\n const descriptionId = `${autoId}-description`;\n const hasLabel = hasNode(label);\n const hasDescription = hasNode(description);\n const mergedLabelledBy = mergeIds(\n hasLabel ? labelId : undefined,\n ariaLabelledBy\n );\n // Prevent Base UI's native-label fallback from promoting description-only\n // content into the accessible name while keeping the label clickable.\n const blockDescriptionAsLabel =\n hasDescription && !hasLabel && mergedLabelledBy === undefined;\n\n return (\n
\n \n {hasLabel || hasDescription ? (\n \n ) : null}\n
\n );\n};\n\nexport default Switch;\n", "type": "registry:component", "target": "components/easy/switch.tsx" } ], "type": "registry:component" }