When to use
Collapsibleis a behavior component with animation effect by default. It is used in various components in Semi Components, including:Navigation,Collapse,Tree,TreeSelect, andTypography.- When the above components do not meet requirements or customized collapsed behavior, you can use
Collapsibleto put in contents that need to be expanded or folded.
Demos
How to import
import { Collapsible } from '@fibrous/semi-ui-solid';
Basic Usage
Use isOpen to control the expansion or folding of the content.
Code
import { createSignal } from 'solid-js';
import { Button, Collapsible } from '@fibrous/semi-ui-solid';
export default function CollapsibleDemo() {
const [isOpen, setOpen] = createSignal(false);
const toggle = () => {
setOpen(!isOpen());
};
return (
<div>
<Button onClick={toggle} aria-expanded={isOpen()} aria-controls="collapsible-basic">
Toggle
</Button>
<Collapsible isOpen={isOpen()} id="collapsible-basic">
<ul>
<li>
<p>Semi Design 以内容优先进行设计。</p>
</li>
<li>
<p>更容易地自定义主题。</p>
</li>
<li>
<p>适用国际化场景。</p>
</li>
<li>
<p>效率场景加入人性化关怀。</p>
</li>
</ul>
</Collapsible>
</div>
);
}Custom Animation Duration
You can use duration to set animation duration or turn off animation by setting motion to false.
设置动画时间:
Code
import { createSignal } from 'solid-js';
import { Button, Collapsible, InputNumber } from '@fibrous/semi-ui-solid';
export default function CollapsibleDemo() {
const [isOpen, setOpen] = createSignal(false);
const [duration, setDuration] = createSignal(250);
const toggle = () => {
setOpen(!isOpen());
};
return (
<div>
<span id="collapsible-duration-label">设置动画时间:</span>
<InputNumber aria-labelledby="collapsible-duration-label" min={0} defaultValue={250} style={{ width: '120px' }} onChange={(val) => setDuration(Number(val))} step={10} />
<br />
<Button onClick={toggle} aria-expanded={isOpen()} aria-controls="collapsible-duration">
Toggle
</Button>
<Collapsible isOpen={isOpen()} duration={duration()} id="collapsible-duration">
<ul>
<li>
<p>Semi Design 以内容优先进行设计。</p>
</li>
<li>
<p>更容易地自定义主题。</p>
</li>
<li>
<p>适用国际化场景。</p>
</li>
<li>
<p>效率场景加入人性化关怀。</p>
</li>
</ul>
</Collapsible>
</div>
);
}Nested use
Code
import { createSignal } from 'solid-js';
import { Button, Collapsible } from '@fibrous/semi-ui-solid';
export default function CollapsibleDemo() {
const [isOpen, setOpen] = createSignal(false);
const [isChildOpen, setChildOpen] = createSignal(false);
return (
<div>
<Button onClick={() => setOpen(!isOpen())} aria-expanded={isOpen()} aria-controls="collapsible-nested">
Toggle
</Button>
<br />
<Collapsible isOpen={isOpen()} id="collapsible-nested">
<div>
<span>Semi Design的设计原则包括:</span>
<Button onClick={() => setChildOpen(!isChildOpen())} aria-expanded={isChildOpen()} aria-controls="collapsible-nested-list">
Toggle List
</Button>
</div>
<Collapsible isOpen={isChildOpen()} id="collapsible-nested-list">
<ul>
<li>
<p>Semi Design 以内容优先进行设计。</p>
</li>
<li>
<p>更容易地自定义主题。</p>
</li>
<li>
<p>适用国际化场景。</p>
</li>
<li>
<p>效率场景加入人性化关怀。</p>
</li>
</ul>
</Collapsible>
</Collapsible>
</div>
);
}Custom CollapseHeight
You could use collapseHeight to customize collapsed height.
Code
import { createSignal, type JSX, Show } from 'solid-js';
import { Button, Collapsible } from '@fibrous/semi-ui-solid';
const linkStyle: JSX.CSSProperties = {
position: 'absolute',
left: '0',
right: '0',
width: '100%',
padding: '0',
border: 'none',
background: 'none',
'font-size': 'inherit',
'font-family': 'inherit',
'line-height': 'inherit',
'text-align': 'center',
bottom: '-10px',
'font-weight': '700',
cursor: 'pointer',
color: 'var(--semi-color-link)',
};
export default function CollapsibleDemo() {
const [isOpen, setOpen] = createSignal(false);
const toggle = () => {
setOpen(!isOpen());
};
return (
<>
<Button onClick={toggle} aria-expanded={isOpen()} aria-controls="collapsible-height">
Toggle
</Button>
<div style={{ position: 'relative' }}>
<Collapsible
isOpen={isOpen()}
collapseHeight={60}
style={
isOpen()
? {}
: {
'-webkit-mask-image': 'linear-gradient(to bottom, black 0%, rgba(0, 0, 0, 1) 60%, rgba(0, 0, 0, 0.2) 80%, transparent 100%)',
}
}
id="collapsible-height"
>
<ul>
<li>
<p>Semi Design 以内容优先进行设计。</p>
</li>
<li>
<p>更容易地自定义主题。</p>
</li>
<li>
<p>适用国际化场景。</p>
</li>
<li>
<p>效率场景加入人性化关怀。</p>
</li>
</ul>
</Collapsible>
<Show when={!isOpen()}>
<button type="button" onClick={toggle} aria-expanded={isOpen()} aria-controls="collapsible-height" style={linkStyle}>
+ Show More
</button>
</Show>
</div>
</>
);
}API reference
Props
| Property | Description | Type | Default |
|---|---|---|---|
| children | Content to expand or collapse. | JSX.Element | - |
| class | Class name of the outer wrapper. | string | - |
| collapseHeight | Height in pixels when collapsed. | number | 0 |
| collapseHeightAdaptive | Whether the collapsed height follows the content when it is shorter than collapseHeight. | boolean | false |
| duration | Animation duration in milliseconds. | number | 250 |
| fade | Whether to fade in and out. | boolean | false |
| id | id of the inner content element, for the trigger's aria-controls; it does not read the global default. | string | - |
| isOpen | Whether the content area is expanded. | boolean | false |
| keepDOM | Whether to keep the DOM tree of the hidden content; it is destroyed by default. | boolean | false |
| lazyRender | Used with keepDOM; when true, the content is not rendered on mount but after the first expansion. | boolean | false |
| motion | Whether to enable the animation. | boolean | true |
| onMotionEnd | Called when the expand or collapse animation ends. | Type() => void | - |
class, style, ref and other native attributes and events land on the outer wrapper; id is a declared prop and lands on the inner content element. An onTransitionEnd from the caller runs together with the component's own handler.
Accessibility
ARIA
- Collapsible has
idprops, the value passed in will be set as the id of the inner content element (not the outer wrapper). The trigger button points at it witharia-controlsand reports whether it is open witharia-expanded, see the usage example below.
import { createSignal } from 'solid-js';
import { Button, Collapsible } from '@fibrous/semi-ui-solid';
() => {
const collapseId = 'myCollapsible';
const [visible, setVisible] = createSignal(false);
return (
<>
<Button onClick={() => setVisible(!visible())} aria-expanded={visible()} aria-controls={collapseId}>
{visible() ? 'hide' : 'show'}
</Button>
<Collapsible isOpen={visible()} id={collapseId}>
<div>hide content</div>
</Collapsible>
</>
);
};
Focus
- With
collapseHeightof 0, the collapsed content isinert: screen readers skip it and Tab cannot reach it. - With
collapseHeightabove 0, the visible preview and the clipped part are the same element, and the clipped part cannot be hidden on its own, so the whole content stays readable and focusable and screen reader users get the full text. Do not put links, buttons or other focusable elements in the clipped part, or keyboard focus lands where it cannot be seen.
FAQ
- Why Collapsible does not expand as expected?
The expanded height ofCollapsibleis computed by CSS and does not depend on measuring the node, so togglingisOpenunder a parent withdisplay: nonestill gives the correct expanded height. First check thatisOpenfollows your state; withcollapseHeightabove 0, part of the content is visible while collapsed by design.