docs: Explain Radix force-mount animation requirements (#6471)

## Summary

Document the animation constraints around Radix `forceMount`: closed
content remains mounted and needs explicit closed-state CSS, while Radix
suppresses CSS transitions and animations during height measurement, so
the first opening may not animate.

Updated Accordion and Collapsible docs, custom prop descriptions, and
generated prop metadata so the guidance appears in component discovery.

Closes #6197.

## Checks

- [x] Accordion and Collapsible documentation updated
- [x] Generated prop metadata refreshed
- [x] Package typecheck
- [x] Targeted Collapsible tests
This commit is contained in:
Oleg Isonen authored and GitHub committed 2026-09-29 16:00:41 +02:00
1 parent adf1fd3aaf
commit 6044792b77
6 files changed
+28 -6

No files matched your search

+6
View File
@@ -30,6 +30,12 @@ To change the content of an Accordion that isn't currently displayed in the canv
<figure><img src="../../.gitbook/assets/radix-accordion-content.png" alt="Accordion Content selected on the canvas and in the Navigator"><figcaption></figcaption></figure>
## Animating Accordion content
The Accordion template keeps its content mounted with **Force Mount** and uses a closed-state `height: 0` rule. If you add a custom animation, keep an explicit collapsed style for `[data-state="closed"]`; animation-only examples can leave every panel visible when content stays mounted.
Radix temporarily sets inline `transition-duration: 0s` and `animation-name: none` while it measures content height. This can suppress the first open animation. Test both the first open and later open/close cycles when changing the animation.
## Using Collections within Accordions
To create an accordion with a [Collection](../core-components/collection.md) that iterates over data and outputs an accordion item for each entry, ensure each item has a unique value set, like this:
+4
View File
@@ -34,6 +34,10 @@ To customize the Collapsible component:
Select **Collapsible Content** and enable **Force Mount** to keep its content in the HTML while the Collapsible is closed. New Collapsible components enable this setting by default. Disable it to remove closed content from the HTML.
When **Force Mount** is enabled, add a closed-state CSS rule such as `height: 0` for `[data-state="closed"]`. Animation-only examples can leave the content visible because they assume Radix unmounts closed content.
Radix temporarily sets inline `transition-duration: 0s` and `animation-name: none` while it measures content height. This can suppress the first open animation, so test both the first open and later open/close cycles.
## Using Collapsible for UI Patterns
The Collapsible component is useful for various UI patterns:
@@ -65,10 +65,10 @@ export const propsAccordionHeader: Record<string, PropMeta> = {};
export const propsAccordionTrigger: Record<string, PropMeta> = {};
export const propsAccordionContent: Record<string, PropMeta> = {
forceMount: {
description:
"Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries or keeping content available in the DOM.",
required: false,
control: "boolean",
type: "boolean",
description:
"When true, closed content stays mounted. Keep an explicit closed-state CSS rule such as height: 0; Radix's animation-only example assumes unmounted content. Radix suppresses CSS transitions and animations while measuring height, so the first open may not animate.",
},
};
@@ -19,7 +19,7 @@ export const propsCollapsibleTrigger: Record<string, PropMeta> = {};
export const propsCollapsibleContent: Record<string, PropMeta> = {
forceMount: {
description:
"Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries or keeping content available in the DOM.",
"When true, closed content stays mounted. Keep an explicit closed-state CSS rule such as height: 0; Radix's animation-only example assumes unmounted content. Radix suppresses CSS transitions and animations while measuring height, so the first open may not animate.",
required: false,
control: "boolean",
type: "boolean",
@@ -58,9 +58,12 @@ export const AccordionTrigger: ForwardRefExoticComponent<
> = Trigger;
export const AccordionContent: ForwardRefExoticComponent<
Omit<ComponentProps<typeof Content>, "asChild"> &
RefAttributes<HTMLDivElement>
> = Content;
Omit<ComponentPropsWithoutRef<typeof Content>, "asChild" | "forceMount"> & {
forceMount?: boolean;
} & RefAttributes<HTMLDivElement>
> = forwardRef(({ forceMount, ...props }, ref) => (
<Content ref={ref} forceMount={forceMount ? true : undefined} {...props} />
));
/* BUILDER HOOKS */
@@ -10,6 +10,9 @@ const sideOffset =
const side =
"The preferred alignment against the Trigger. May change when collisions occur.";
const forceMount =
"When true, closed content stays mounted. Keep an explicit closed-state CSS rule such as height: 0; Radix's animation-only example assumes unmounted content. Radix suppresses CSS transitions and animations while measuring height, so the first open may not animate.";
export const propsDescriptions = {
Dialog: {
open,
@@ -20,6 +23,12 @@ export const propsDescriptions = {
Collapsible: {
open,
},
AccordionContent: {
forceMount,
},
CollapsibleContent: {
forceMount,
},
Popover: {
open,
},