Component State
Learn how to manage component state using Context and Provider components.
Need to access a component's state? You have three options:
| Approach | When to use it |
|---|---|
Component.Context | Quick inline access via named children |
use*Context hooks | Build custom child components that read state |
useComponent + RootProvider | Control the component from outside |
Context Components
Use Component.Context to access state inline via named children. Here, Avatar.Fallback reads the loaded state to
show different content:
import { Avatar } from 'ark-ripple/avatar';
import styles from './index.module.css';
export component Context() {
<Avatar.Root class={styles.Root}>
<Avatar.Context>
component children({ context }) {
<Avatar.Fallback class={styles.Fallback}>
{@context.loaded ? 'PA' : 'Loading'}
</Avatar.Fallback>
}
</Avatar.Context>
<Avatar.Image class={styles.Image} src="https://i.pravatar.cc/300?u=a" alt="avatar" />
</Avatar.Root>
}
Context Hooks
Every component exports a use*Context hook (like useDialogContext or useMenuContext). Call it from any child
component to access state and methods—no render props needed.
import { Dialog, useDialogContext } from 'ark-ripple/dialog'
component CustomCloseButton() {
const dialog = useDialogContext()
<button onClick={() => dialog.setOpen(false)}>
{"Close "} {dialog.open ? 'open' : 'closed'}
</button>
}
export component Demo() {
<Dialog.Root>
<Dialog.Trigger>Open</Dialog.Trigger>
<Dialog.Content>
<CustomCloseButton />
</Dialog.Content>
</Dialog.Root>
}
The hook returns the same API as Component.Context, just without the nesting.
Provider Components
Need to control a component from outside its tree? Use a useComponent hook (like useDialog) with RootProvider.
When you use
RootProvider, skip theRootcomponent—you don't need both.
import { Accordion } from 'ark-ripple/accordion';
import { useAccordion } from 'ark-ripple/accordion';
import { ChevronDown } from 'lucide-ripple';
import styles from './index.module.css';
export component RootProvider() {
const accordion = useAccordion({ multiple: true, defaultValue: ['ark-ui'] });
<div class="stack">
<output>
{'Value: '}
{JSON.stringify(@accordion.value)}
</output>
<Accordion.RootProvider class={styles.Root} value={accordion}>
for (const item of items; key item.value) {
<Accordion.Item class={styles.Item} value={item.value}>
<Accordion.ItemTrigger class={styles.ItemTrigger}>
{item.title}
<Accordion.ItemIndicator class={styles.ItemIndicator}>
<ChevronDown />
</Accordion.ItemIndicator>
</Accordion.ItemTrigger>
<Accordion.ItemContent class={styles.ItemContent}>
<div class={styles.ItemBody}>{item.content}</div>
</Accordion.ItemContent>
</Accordion.Item>
}
</Accordion.RootProvider>
</div>
}
const items = [
{
value: 'ark-ui',
title: 'What is Ark UI?',
content: 'A headless component library for building accessible web apps.',
},
{
value: 'getting-started',
title: 'How to get started?',
content: 'Install the package and import the components you need.',
},
{
value: 'maintainers',
title: 'Who maintains this project?',
content: 'Ark UI is maintained by the Chakra UI team.',
},
];
Choosing the Right Approach
Component.Context— Quick inline access for conditional renderinguse*Contexthooks — Build reusable child components that need parent stateuseComponent+RootProvider— Trigger actions from outside (like opening a dialog from a menu item)