---
id: "packages/active-state/getting-started"
title: "Getting started"
description: "Receive active-state in your repository, declare it, and build a first model with a store, a derived value and a React component."
url: "/packages/active-state/getting-started"
locale: "en"
revision: "a338652777ecb852"
---

# Getting started

## Receive the package

`active-state` depends on no other workspace package, so it travels alone. Ask the maintainer of
Foundation for a bundle (on the `development` channel while it is unreleased), then follow
[Receiving packages](/receiving-packages):

```bash
node tools/rps/rps-apply.mjs plan --bundle <bundle-folder> --development
node tools/rps/rps-apply.mjs apply --bundle <bundle-folder> --expect-plan <digest> --development
```

The bundle is composed in Foundation with
`pnpm rps:transfer bundle --products active-state --channel development --out <folder>`.

## Declare, install and verify

```json
{
  "dependencies": {
    "@workspace/active-state": "workspace:*",
    "react": "^19.0.0"
  }
}
```

```bash
pnpm install
node tools/rps/rps-apply.mjs verify-install --from <app-folder>
```

`verify-install` must list `@workspace/active-state` as `current`. In a Next.js app, add the
package to `transpilePackages`; Vite compiles it as it is.

## Build a model

A model is a few objects at module scope (or inside a `Scope` you own):

```ts
import {Derived, shallow, Store} from '@workspace/active-state';

export const lines = new Store<{product: string; price: number}[]>([], {
  equal: shallow,
});
export const total = new Derived({
  inputs: [lines],
  compute: (list) => list.reduce((sum, line) => sum + line.price, 0),
});

lines.update((list) => [...list, {product: 'Pen', price: 1.25}]);
total.state; // 1.25
```

## Read it in React

Import from `/react` in a component file; it repeats the core, so one import is enough:

```tsx
'use client';

import {useStore} from '@workspace/active-state/react';
import {total} from './model';

export function Total() {
  return <output>{useStore(total)}</output>;
}
```

The same model, running in your browser:

**Example: A store, derived values and useStore**

Client: Runs entirely in your browser. Source: `examples/state/cart-total.tsx`.

```tsx
// apps/docs/examples/state/cart-total.tsx
'use client';

import {Derived, shallow, Store, useStore} from '@workspace/active-state/react';
import {Button} from '@workspace/active-ui/components/primitives/button';

interface Line {
  product: string;
  price: number;
}

// Module scope: the model lives outside React and needs no provider.
const lines = new Store<Line[]>([{product: 'Notebook', price: 4.5}], {
  equal: shallow,
});
const total = new Derived({
  inputs: [lines],
  compute: (list) => list.reduce((sum, line) => sum + line.price, 0),
});
const count = new Derived({inputs: [lines], compute: (list) => list.length});

const PRODUCTS: Line[] = [
  {product: 'Pen', price: 1.25},
  {product: 'Folder', price: 2},
  {product: 'Stapler', price: 7.5},
];

/** A Store, two Derived values over it, and useStore in React. */
export default function CartTotal() {
  const items = useStore(lines);
  const sum = useStore(total);
  const n = useStore(count);
  return (
    <div className="flex flex-col gap-4">
      <div className="flex flex-wrap gap-2">
        {PRODUCTS.map((line) => (
          <Button
            key={line.product}
            variant="outline"
            size="sm"
            onClick={() => lines.update((list) => [...list, line])}
          >
            Add {line.product}
          </Button>
        ))}
        <Button
          variant="ghost"
          size="sm"
          onClick={() => lines.setState([])}
          disabled={n === 0}
        >
          Empty
        </Button>
      </div>
      <ul className="text-muted-foreground text-sm">
        {items.map((line, index) => (
          <li key={index}>
            {line.product}: {line.price.toFixed(2)}
          </li>
        ))}
      </ul>
      <p className="text-sm" aria-live="polite" data-cart-total>
        {n} item{n === 1 ? '' : 's'}, total {sum.toFixed(2)}
      </p>
    </div>
  );
}
```

## Next

[Stores and derived values](/packages/active-state/stores-and-derived) explains when a write is
published and how equality decides it.
