Refined UI

An opinionated, customizable superset of shadcn/ui

AgentsPrimitivesSkillsSkins
Guides
  • Overview
  • Get started
  • Shadcn compatibility
  • Architecture
  • Agent surface
Primitives
  • Accordion
  • Alert
  • Alert dialog
  • Aspect ratio
  • Autocomplete
  • Avatar
  • Badge
  • Button
  • Button group
  • Calendar
  • Card
  • Checkbox
  • Checkbox Group
  • Code
  • Code Diff
  • Collapsible
  • Color Picker
  • Combobox
  • Command
  • Date Picker
  • Dialog
  • Drawer
  • Empty
  • Field
  • Form
  • Gradient Editor
  • Hover card
  • Input
  • Input group
  • Input OTP
  • Item
  • Kbd
  • Markdown
  • Menu
  • Menubar
  • Meter
  • Native select
  • Navigation menu
  • Number Field
  • Pagination
  • Popover
  • Progress
  • Radio group
  • Resizable
  • Scroll area
  • Select
  • Sidebar
  • Skeleton
  • Slider
  • Spinner
  • Switch
  • Table
  • Table of contents
  • Tabs
  • Textarea
  • Toast
  • Toggle
  • Toolbar
  • Tooltip
  • Tree
  • Trigger Menu
  • Typography
Hooks
  • Use Chat Message
  • Use Chat Input
  • Use User Ask
  • Use Audio Recorder
  • Use Environment Variables
  • Use Copy To Clipboard
  • Use Tool Call
  • Use Sidebar Resize
Utils
  • cn
  • Skin
  • Contracts
  • Serialize
Extensions
  • Control Effects
  • View Transition
  • Send Aurora
  1. Primitives
  2. Collapsible
Primitives

Collapsible

Accessible disclosure primitive with measured open and close motion.

Composition

The preferred shape for composing the installed primitive from its exported parts.

Parts

Exported compound parts from the installed source.

Collapsible
├── CollapsibleTrigger
└── CollapsibleContent

The refined source installs this primitive from src/registry/sources/refined/ui/collapsible.tsx. It installs with the chat registry, so Refined UI files keep a stable import path.

Registry command
npx shadcn@latest add http://127.0.0.1:3000/r/refined/chat.json
See registry manifest

Raw code

Primary installed primitive source

Base UI Collapsible slot
src/registry/sources/refined/ui/collapsible.tsx
"use client";
​
import { Collapsible as CollapsiblePrimitive } from "@base-ui/react/collapsible";
import { mergeProps } from "@base-ui/react/merge-props";
import { cloneElement, isValidElement } from "react";
import type { CollapsibleContentProps, CollapsibleProps, CollapsibleTriggerProps } from "@/components/refined-ui/contracts";
import { cn } from "@/components/refined-ui/lib/cn";
import { skinSlot } from "@/components/refined-ui/skin";
​
// Emits skin-stable data-ui/data-slot/data-state hooks so consumers never style on Base UI's private attributes.
export function Collapsible({ className, ...props }: CollapsibleProps) {
return (
<CollapsiblePrimitive.Root
className={className}
render={(renderProps, state) => (
<div
data-ui="agent"
data-slot="collapsible"
{...renderProps}
data-state={state.open ? "open" : "closed"}
className={cn(renderProps.className, skinSlot("collapsible", { state: state.open ? "open" : "closed" }))}
/>
)}
{...props}
/>
);
}
​
export function CollapsibleTrigger({ asChild = false, className, children, ...props }: CollapsibleTriggerProps) {
return (
<CollapsiblePrimitive.Trigger
className={cn(
"cursor-pointer outline-none transition-colors duration-[var(--duration-fast)] ease-[var(--ease-standard)] focus-visible:ring-2 focus-visible:ring-foreground/20",
"[&>svg]:transition-transform [&>svg]:duration-[var(--duration-base)] [&>svg]:ease-[var(--ease-standard)] [&[data-state=open]>svg]:rotate-90",
className,
)}
{...props}
render={(renderProps, state) => {
const stateAttrs = {
"data-ui": "agent",
"data-slot": "collapsible-trigger",
"data-state": state.open ? "open" : "closed",
};
const skinClasses = skinSlot("collapsible-trigger", { state: state.open ? "open" : "closed" });
​
// asChild: mergeProps chains handlers + concatenates className instead of overwriting consumer's own props.
if (asChild && isValidElement<{ className?: string }>(children)) {
const merged = mergeProps(renderProps, children.props);
return cloneElement(children, {
...merged,
...stateAttrs,
className: cn(merged.className, skinClasses),
});
}
​
return (
<button type="button" {...renderProps} {...stateAttrs} className={cn(renderProps.className, skinClasses)}>
{children}
</button>
);
}}
/>
);
}
​
export function CollapsibleContent({ className, children, ...props }: CollapsibleContentProps) {
return (
<CollapsiblePrimitive.Panel
className={cn(
"h-[var(--collapsible-panel-height)] overflow-hidden transition-[height,opacity] duration-[var(--duration-base)] ease-[var(--ease-emphasized)]",
"data-[starting-style]:h-0 data-[starting-style]:opacity-0 data-[ending-style]:h-0 data-[ending-style]:opacity-0",
)}
{...props}
render={(renderProps, state) => (
<div
{...renderProps}
data-ui="agent"
data-slot="collapsible-content"
data-state={state.open ? "open" : "closed"}
className={cn(renderProps.className, skinSlot("collapsible-content", { state: state.open ? "open" : "closed" }))}
/>
)}
>
<div className={className}>{children}</div>
</CollapsiblePrimitive.Panel>
);
}
​

On this page

  • Preview
  • Composition
  • Installation
  • Source

Parsed the request and grouped the constraints.

Checked each candidate against the contract.

Kept the smallest change that satisfied all of them.