Back to Withastro

Share state between Astro components

src/content/docs/en/recipes/sharing-state.mdx

latest2.3 KB
Original Source

import { Steps } from '@astrojs/starlight/components'; import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro';

:::tip Using framework components? See how to share state between Islands! :::

When building an Astro website, you may need to share state across components. Astro recommends the use of Nano Stores for shared client storage.

Recipe

<Steps> 1. Install Nano Stores:
<PackageManagerTabs>
  <Fragment slot="npm">
  ```shell
  npm install nanostores
  ```
  </Fragment>
  <Fragment slot="pnpm">
  ```shell
  pnpm add nanostores
  ```
  </Fragment>
  <Fragment slot="yarn">
  ```shell
  yarn add nanostores
  ```
  </Fragment>
</PackageManagerTabs>

2. Create a store. In this example, the store tracks whether a dialog is open or not:

```ts title="src/store.js"
import { atom } from 'nanostores';

export const isOpen = atom(false);
```

3. Import and use the store in a <script> tag in the components that will share state.

The following `Button` and `Dialog` components each use the shared `isOpen` state to control whether a particular `<div>` is hidden or displayed:

```astro title="src/components/Button.astro"
<button id="openDialog">Open</button>

<script>
  import { isOpen } from '../store.js';
  
  // Set the store to true when the button is clicked
  function openDialog() {
    isOpen.set(true);
  }

  // Add an event listener to the button
  document.getElementById('openDialog').addEventListener('click', openDialog);
</script>
```

```astro title="src/components/Dialog.astro"
<div id="dialog" style="display: none">Hello world!</div>

<script>
  import { isOpen } from '../store.js';

  // Listen to changes in the store, and show/hide the dialog accordingly    
  isOpen.subscribe(open => {
    if (open) {
      document.getElementById('dialog').style.display = 'block';
    } else {
      document.getElementById('dialog').style.display = 'none';
    }
  })
</script>
```
</Steps>

Resources