Collapsible
A collapsible is a component which expands and collapses a panel.
@Omikorin starred 4 repositories
@chakra-ui/zag-js
@chakra-ui/ark-ui
@chakra-ui/panda
@chakra-ui/chakra-ui
Features
- Full keyboard navigation.
Installation
To use the collapsible machine in your project, run the following command in your command line:
npm install @zag-js/collapsible @zag-js/react # or yarn add @zag-js/collapsible @zag-js/react
npm install @zag-js/collapsible @zag-js/vue # or yarn add @zag-js/collapsible @zag-js/vue
npm install @zag-js/collapsible @zag-js/vue # or yarn add @zag-js/collapsible @zag-js/vue
npm install @zag-js/collapsible @zag-js/solid # or yarn add @zag-js/collapsible @zag-js/solid
This command will install the framework agnostic collapsible logic and the reactive utilities for your framework of choice.
Usage
First, import the collapsible package into your project
import * as collapsible from "@zag-js/collapsible"
The collapsible package exports two key functions:
machine— The state machine logic for the collapsible widget.connect— The function that translates the machine's state to JSX attributes and event handlers.
You'll also need to provide a unique
idto theuseMachinehook. This is used to ensure that every part has a unique identifier.
Next, import the required hooks and functions for your framework and use the collapsible machine in your project 🔥
import * as collapsible from "@zag-js/collapsible" import { normalizeProps, useMachine } from "@zag-js/react" import { useId } from "react" const data = ["@chakra-ui/ark-ui", "@chakra-ui/panda", "@chakra-ui/chakra-ui"] function Collapsible() { const [state, send] = useMachine(collapsible.machine({ id: useId() })) const api = collapsible.connect(state, send, normalizeProps) return ( <div {...api.rootProps}> <button {...api.triggerProps}> {api.isOpen ? "Collapse" : "Expand"} </button> <div {...api.contentProps}> {data.map((item) => ( <div key={item}>{item}</div> ))} </div> </div> ) }
import * as collapsible from "@zag-js/collapsible" import { normalizeProps, useMachine } from "@zag-js/vue" import { defineComponent, computed } from "vue" const data = ["@chakra-ui/ark-ui", "@chakra-ui/panda", "@chakra-ui/chakra-ui"] export default defineComponent({ name: "Collapsible", setup() { const [state, send] = useMachine(collapsible.machine({ id: "1" })) const apiRef = computed(() => collapsible.connect(state.value, send, normalizeProps), ) return () => { const api = apiRef.value return ( <div {...api.rootProps}> <button {...api.triggerProps}> {api.isOpen ? "Collapse" : "Expand"} </button> <div {...api.contentProps}> {data.map((item) => ( <div>{item}</div> ))} </div> </div> ) } }, })
<script setup> import * as collapsible from "@zag-js/collapsible" import { normalizeProps, useMachine } from "@zag-js/vue" import { computed } from "vue" const data = ["@chakra-ui/ark-ui", "@chakra-ui/panda", "@chakra-ui/chakra-ui"] const [state, send] = useMachine(collapsible.machine({ id: "1" })) const api = computed(() => collapsible.connect(state.value, send, normalizeProps)) </script> <template> <div ref="ref" v-bind="api.rootProps"> <button v-if="api.isOpen" v-bind="api.triggerProps">Collapse</button> <button v-if="!api.isOpen" v-bind="api.triggerProps">Expand</button> <div v-bind="api.contentProps"> <div v-for="item in data" :key="item.id" > <div>{{ item }}</div> </div> </div> </div> </template>
import * as collapsible from "@zag-js/collapsible" import { normalizeProps, useMachine } from "@zag-js/solid" import { createMemo, createUniqueId } from "solid-js" const data = ["@chakra-ui/ark-ui", "@chakra-ui/panda", "@chakra-ui/chakra-ui"] function Collapsible() { const [state, send] = useMachine( collapsible.machine({ id: createUniqueId() }), ) const api = createMemo(() => collapsible.connect(state, send, normalizeProps)) return ( <div {...api().rootProps}> <button {...api().triggerProps}> {api().isOpen ? "Collapse" : "Expand"} </button> <div {...api().contentProps}> <Index each={items}>{(item) => <div>{item()}</div>}</Index> </div> </div> ) }
Listening for changes
When the collapsible state changes, the onOpenChange callback is invoked.
const [state, send] = useMachine( collapsible.machine({ onOpenChange(details) { // details => { open: boolean } console.log("collapsible open:", details.open) }, }), )
Disabling the entire collapsible
You can disable the entire collapsible by passing disabled to the machine's
context.
When a collapsible is disabled, it is skipped from keyboard navigation and can't be interacted with.
const [state, send] = useMachine( collapsible.machine({ disabled: true, }), )
Animating the collapsible
You can animate the collapsible by passing animate to the machine's context.
When a collapsible is animated, you need to pass the expandAnimationName and
collapseAnimationName which are names of the keyframes you have in your CSS.
You can also pass the animationDuration which is the duration of the animation
in milliseconds (by default 300 milliseconds).
const [state, send] = useMachine( collapsible.machine({ animate: true, expandAnimationName: "slideDown", collapseAnimationName: "slideUp", animationDuration: 300, }), )
Styling guide
Earlier, we mentioned that each collapsible part has a data-part attribute
added to them to select and style them in the DOM.
Open and closed state
When a collapsible is expanded or collapsed, a data-state attribute is set on
the root, trigger and content elements. This attribute is removed when it is
closed.
[data-part="root"][data-state="open|closed"] { /* styles for the collapsible is open or closed state */ } [data-part="trigger"][data-state="open|closed"] { /* styles for the collapsible is open or closed state */ } [data-part="content"][data-state="open|closed"] { /* styles for the collapsible is open or closed state */ }
Focused state
When a collapsible's trigger is focused, a data-focused attribute is set on
the root, trigger and content.
[data-part="root"][data-focus] { /* styles for the item's focus state */ } [data-part="trigger"][data-focus] { /* styles for the content's focus state */ } [data-part="content"][data-focus] { /* styles for the content's focus state */ }
Methods and Properties
The collapsible's api exposes the following methods and properties:
Machine Context
The collapsible machine exposes the following context properties:
idsPartial<{ root: string; content: string; trigger: string; }>The ids of the elements in the collapsible. Useful for composition.disabledbooleanIf `true`, the collapsible will be disabledonOpenChange(details: OpenChangeDetails) => voidFunction called when the popup is openedopenbooleanWhether the collapsible is openanimatebooleanWhether the collapsible is animatedexpandAnimationNamestringName of the expand animationcollapseAnimationNamestringName of the collapse animationanimationDurationnumberDuration of the animation in millisecondsdir"ltr" | "rtl"The document's text/writing direction.idstringThe unique identifier of the machine.getRootNode() => ShadowRoot | Node | DocumentA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.
Machine API
The collapsible api exposes the following methods:
isOpenbooleanWhether the collapsible is open.isDisabledbooleanWhether the collapsible is disabledisFocusedbooleanWhether the checkbox is focusedisAnimatedbooleanWhether the checkbox is animatedopen() => voidFunction to open the collapsible.close() => voidFunction to close the collapsible.
Edit this page on GitHub