# Component State

URL: https://ark-ui.com/docs/guides/component-state
Source: https://raw.githubusercontent.com/chakra-ui/ark/refs/heads/main/website/src/content/pages/guides/component-state.mdx

Learn how to manage component state using Context and Provider components.

---

## Context Components

Context components expose state and functions to child components. In this example, `Avatar.Fallback` renders based on
`loaded` state.

**Example: context**

#### React

```tsx
import { Avatar } from '@ark-ui/react/avatar'
import styles from 'styles/avatar.module.css'

export const Context = () => (
  <Avatar.Root className={styles.Root}>
    <Avatar.Context>
      {(avatar) => <Avatar.Fallback className={styles.Fallback}>{avatar.loaded ? 'PA' : 'Loading'}</Avatar.Fallback>}
    </Avatar.Context>
    <Avatar.Image className={styles.Image} src="https://i.pravatar.cc/300" alt="avatar" />
  </Avatar.Root>
)

```

#### Solid

```tsx
import { Avatar } from '@ark-ui/solid/avatar'
import styles from 'styles/avatar.module.css'

export const Context = () => (
  <Avatar.Root class={styles.Root}>
    <Avatar.Context>
      {(avatar) => <Avatar.Fallback class={styles.Fallback}>{avatar().loaded ? 'PA' : 'Loading'}</Avatar.Fallback>}
    </Avatar.Context>
    <Avatar.Image class={styles.Image} src="https://i.pravatar.cc/300" alt="avatar" />
  </Avatar.Root>
)

```

#### Vue

```vue
<script setup lang="ts">
import { Avatar } from '@ark-ui/vue/avatar'
import styles from 'styles/avatar.module.css'
</script>

<template>
  <Avatar.Root :class="styles.Root">
    <Avatar.Context v-slot="avatar">
      <Avatar.Fallback :class="styles.Fallback">
        {{ avatar.loaded ? 'PA' : 'Loading' }}
      </Avatar.Fallback>
    </Avatar.Context>
    <Avatar.Image :class="styles.Image" src="https://i.pravatar.cc/300" alt="avatar" />
  </Avatar.Root>
</template>

```

#### Svelte

```svelte
<script lang="ts">
  import { Avatar } from '@ark-ui/svelte/avatar'
  import styles from 'styles/avatar.module.css'
</script>

<Avatar.Root class={styles.Root}>
  <Avatar.Context>
    {#snippet api(avatar)}
      <Avatar.Fallback class={styles.Fallback}>
        {#if avatar().loaded}
          <p>PA</p>
        {:else}
          <p>Loading</p>
        {/if}
      </Avatar.Fallback>
    {/snippet}
  </Avatar.Context>
  <Avatar.Image class={styles.Image} src="https://i.pravatar.cc/3000?u=b" alt="avatar" />
</Avatar.Root>

```

> **Good to know (RSC)**: Due to the usage of render prop, you might need to add the `'use client'` directive at the top
> of your file when using React Server Components.

## Provider Components

Provider components can help coordinate state and behavior between multiple components, enabling interactions that
aren't possible with `Context` components alone. They are used alongside component hooks.

**Example: root-provider**

#### React

```tsx
import { Accordion, useAccordion } from '@ark-ui/react/accordion'
import { ChevronDownIcon } from 'lucide-react'
import styles from 'styles/accordion.module.css'

export const RootProvider = () => {
  const accordion = useAccordion({
    multiple: true,
    defaultValue: ['ark-ui'],
  })

  return (
    <>
      <button onClick={() => accordion.setValue(['maintainers'])}>Set to Maintainers</button>

      <Accordion.RootProvider className={styles.Root} value={accordion}>
        {items.map((item) => (
          <Accordion.Item className={styles.Item} key={item.value} value={item.value}>
            <Accordion.ItemTrigger className={styles.ItemTrigger}>
              {item.title}
              <Accordion.ItemIndicator className={styles.ItemIndicator}>
                <ChevronDownIcon />
              </Accordion.ItemIndicator>
            </Accordion.ItemTrigger>
            <Accordion.ItemContent className={styles.ItemContent}>
              <div className={styles.ItemBody}>{item.content}</div>
            </Accordion.ItemContent>
          </Accordion.Item>
        ))}
      </Accordion.RootProvider>
    </>
  )
}

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.',
  },
]

```

#### Solid

```tsx
import { Accordion, useAccordion } from '@ark-ui/solid/accordion'
import { ChevronDownIcon } from 'lucide-solid'
import { Index } from 'solid-js'
import styles from 'styles/accordion.module.css'

export const RootProvider = () => {
  const accordion = useAccordion({
    multiple: true,
    defaultValue: ['ark-ui'],
  })

  return (
    <>
      <button onClick={() => accordion().setValue(['maintainers'])}>Set to Maintainers</button>

      <Accordion.RootProvider class={styles.Root} value={accordion}>
        <Index each={items}>
          {(item) => (
            <Accordion.Item class={styles.Item} value={item().value}>
              <Accordion.ItemTrigger class={styles.ItemTrigger}>
                {item().title}
                <Accordion.ItemIndicator class={styles.ItemIndicator}>
                  <ChevronDownIcon />
                </Accordion.ItemIndicator>
              </Accordion.ItemTrigger>
              <Accordion.ItemContent class={styles.ItemContent}>
                <div class={styles.ItemBody}>{item().content}</div>
              </Accordion.ItemContent>
            </Accordion.Item>
          )}
        </Index>
      </Accordion.RootProvider>
    </>
  )
}

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.',
  },
]

```

#### Vue

```vue
<script setup lang="ts">
import { Accordion, useAccordion } from '@ark-ui/vue/accordion'
import { ChevronDownIcon } from 'lucide-vue-next'
import styles from 'styles/accordion.module.css'

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.',
  },
]

const accordion = useAccordion({
  multiple: true,
  defaultValue: ['ark-ui'],
})
</script>

<template>
  <button @click="accordion.setValue(['maintainers'])">Set to Maintainers</button>

  <Accordion.RootProvider :class="styles.Root" :value="accordion">
    <Accordion.Item v-for="item in items" :key="item.value" :class="styles.Item" :value="item.value">
      <Accordion.ItemTrigger :class="styles.ItemTrigger">
        {{ item.title }}
        <Accordion.ItemIndicator :class="styles.ItemIndicator">
          <ChevronDownIcon />
        </Accordion.ItemIndicator>
      </Accordion.ItemTrigger>
      <Accordion.ItemContent :class="styles.ItemContent">
        <div :class="styles.ItemBody">{{ item.content }}</div>
      </Accordion.ItemContent>
    </Accordion.Item>
  </Accordion.RootProvider>
</template>

```

#### Svelte

```svelte
<script lang="ts">
  import { Accordion, useAccordion } from '@ark-ui/svelte/accordion'
  import { ChevronDownIcon } from 'lucide-svelte'
  import styles from 'styles/accordion.module.css'

  const id = $props.id()
  const accordion = useAccordion({
    id,
    defaultValue: ['ark-ui'],
  })

  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.',
    },
  ]
</script>

<div>
  <button onclick={() => accordion().setValue(['maintainers'])}>Set to Maintainers</button>
  <Accordion.RootProvider class={styles.Root} value={accordion}>
    {#each items as item (item.value)}
      <Accordion.Item class={styles.Item} value={item.value}>
        <Accordion.ItemTrigger class={styles.ItemTrigger}>
          {item.title}
          <Accordion.ItemIndicator class={styles.ItemIndicator}>
            <ChevronDownIcon />
          </Accordion.ItemIndicator>
        </Accordion.ItemTrigger>
        <Accordion.ItemContent class={styles.ItemContent}>
          <div class={styles.ItemBody}>{item.content}</div>
        </Accordion.ItemContent>
      </Accordion.Item>
    {/each}
  </Accordion.RootProvider>
</div>

```

> When using the `RootProvider` component, you don't need to use the `Root` component.

See more in [Examples](/examples/popover-selection).