Accordion
optics/accordionFreeComponent
A vertically stacked set of interactive headings that each reveal a section of content.
See it running
Open the demo on optics
optics.agusmayol.com.ar/components/accordionInstall it
npx shadcn@latest add https://optics.agusmayol.com.ar/r/accordion.jsonSource
1"use client";23import * as React from "react";4import { Accordion as BaseAccordion } from "@base-ui/react/accordion";5import { AnimatePresence, motion } from "motion/react";6import { ChevronDownIcon } from "lucide-react";78import { getStrictContext } from "@/registry/optics/lib/get-strict-context";9import { useControlledState } from "@/registry/optics/hooks/use-controlled-state";10import { cn } from "@/registry/optics/lib/utils";1112// --- Internal Primitive Logic ---1314const [AccordionProvider, useAccordion] = getStrictContext("AccordionContext");1516const [AccordionItemProvider, useAccordionItem] = getStrictContext(17 "AccordionItemContext",18);1920function PrimitiveAccordion({ collapsible = false, ...props } = {}) {21 const [value, setValue] = useControlledState({22 value: props?.value,23 defaultValue: props?.defaultValue,24 onChange: props?.onValueChange,25 });2627 return (28 <AccordionProvider value={{ value, setValue }}>29 <BaseAccordion.Root30 data-slot="accordion"31 {...props}32 onValueChange={setValue}33 />34 </AccordionProvider>35 );36}3738function PrimitiveAccordionItem(props = {}) {39 const { value } = useAccordion();40 const [isOpen, setIsOpen] = React.useState(41 value?.includes(props?.value) ?? false,42 );4344 React.useEffect(() => {45 setIsOpen(value?.includes(props?.value) ?? false);46 }, [value, props?.value]);4748 return (49 <AccordionItemProvider value={{ isOpen, setIsOpen }}>50 <BaseAccordion.Item data-slot="accordion-item" {...props} />51 </AccordionItemProvider>52 );53}5455function PrimitiveAccordionHeader(props = {}) {56 return <BaseAccordion.Header data-slot="accordion-header" {...props} />;57}5859function PrimitiveAccordionTrigger(props = {}) {60 return <BaseAccordion.Trigger data-slot="accordion-trigger" {...props} />;61}6263function PrimitiveAccordionPanel({64 transition = { duration: 0.35, ease: "easeInOut" },65 hiddenUntilFound,66 keepRendered = false,67 ...props68} = {}) {69 const { isOpen } = useAccordionItem();7071 return (72 <AnimatePresence>73 {keepRendered ? (74 <BaseAccordion.Panel75 hidden={false}76 hiddenUntilFound={hiddenUntilFound}77 keepMounted78 render={79 <motion.div80 key="accordion-panel"81 data-slot="accordion-panel"82 initial={{ height: 0, opacity: 0, "--mask-stop": "0%", y: 20 }}83 animate={84 isOpen85 ? { height: "auto", opacity: 1, "--mask-stop": "100%", y: 0 }86 : { height: 0, opacity: 0, "--mask-stop": "0%", y: 20 }87 }88 transition={transition}89 style={{90// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from optics
All 79 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Alertalert | optics | Components | Free | 4 deps | |
| Alert Dialogalert-dialog | optics | Components | Free | 4 deps | |
| Aspect Ratioaspect-ratio | optics | Components | Free | 2 deps | |
| Auto Heightauto-height | optics | Components | Free | 3 deps | |
| Avataravatar | optics | Components | Free | 3 deps | |
| Badgebadge | optics | Components | Free | 4 deps | |
| Breadcrumbbreadcrumb | optics | Components | Free | 4 deps | |
| Buttonbutton | optics | Components | Free | 4 deps |
