> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metabind.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# useState

> Component-local state hook that persists across re-renders.

```typescript theme={null}
useState<T>(initialValue: T): [T, (value: T) => void];
```

<ParamField path="initialValue" type="T" required>
  The initial state value. Can be any type: number, string, boolean, object, or array.
</ParamField>

## Returns

A two-element array:

* `[0]` -- The current state value.
* `[1]` -- A setter function that updates the state and triggers a re-render.

## Usage

### Counter

```typescript theme={null}
const body = () => {
    const [count, setCount] = useState(0)

    return VStack({ spacing: 12 }, [
        Text(String(count)).font("largeTitle"),
        Button("Increment", () => setCount(count + 1))
    ])
}
```

### Toggle visibility

```typescript theme={null}
const body = () => {
    const [isVisible, setIsVisible] = useState(true)

    return VStack({ spacing: 16 }, [
        Button(isVisible ? "Hide" : "Show", () => {
            setIsVisible(!isVisible)
        }),
        isVisible ? Text("Now you see me").font("body") : Empty()
    ])
}
```

### Object state

```typescript theme={null}
const body = () => {
    const [form, setForm] = useState({ name: "", email: "" })

    return VStack({ spacing: 12 }, [
        TextField("Name", form.name, (value) => {
            setForm({ ...form, name: value })
        }),
        TextField("Email", form.email, (value) => {
            setForm({ ...form, email: value })
        }),
        Text("Hello, " + form.name)
    ])
}
```

## Notes

* Each component instance maintains its own independent state. Two instances of the same component do not share `useState` values.
* The `initialValue` is only used on the first render. Subsequent re-renders return the current state.
* Calling the setter with the same value may still trigger a re-render.
* For state shared across multiple components, use [useStore](/bindjs/functions/useStore) instead.
* `useState` must be called inside a component `body` function, not at the top level.

## See Also

* [useStore](/bindjs/functions/useStore) — global shared state
* [withAnimation](/bindjs/functions/withAnimation) — animate state changes
