> For AI agents: the complete documentation index is available at /ooui-react/en/llms.txt, the full documentation bundle is available at /ooui-react/en/llms-full.txt.

# StackLayout

> [Source](https://github.com/BearBin1215/ooui-react/tree/main/src/layouts/StackLayout) | [Original component](https://doc.wikimedia.org/oojs-ui/master/js/OO.ui.StackLayout.html "OO.ui.StackLayout")

A stack layout: renders a set of [pages](/ooui-react/en/components/page-layout/index.md) from `options`, showing only the active page at a time; with `continuous`, all pages are visible and the container scrolls. Also the inner page stack of [BookletLayout](/ooui-react/en/components/booklet-layout/index.md).

## Basic usage

The active page rides the `value` / `defaultValue` / `onChange` channels; an option is a [PageLayout](/ooui-react/en/components/page-layout/index.md) prop set plus `value` (which doubles as the match key and the list key).

```tsx preview
import { useState } from "react";
import { Button, StackLayout } from "ooui-react";

const options = [
  { value: "a", label: "First page", padded: true, children: "First page content" },
  { value: "b", label: "Second page", padded: true, children: "Second page content" },
];

function App() {
  const [page, setPage] = useState<string | number>("a");

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
      <div style={{ display: "flex", gap: 8 }}>
        <Button onClick={() => setPage("a")}>First page</Button>
        <Button onClick={() => setPage("b")}>Second page</Button>
      </div>
      <div style={{ position: "relative", height: 120 }}>
        <StackLayout value={page} onChange={setPage} options={options} framed />
      </div>
    </div>
  );
}

export default App;
```

:::note Form premise
In the `expanded` form (on by default) the layout fills its parent via absolute positioning, so the parent must be positioned and sized (the demo wrapper above exists for exactly that); the whole-container scrolling of `continuous` rides on the same premise. The `expanded={false}` static form works only for [MenuLayout](/ooui-react/en/components/menu-layout/index.md)'s own flow content — this component's pages are absolutely positioned panels with no content height in static mode, so don't use it here.
:::

When the active value is missing or stale (e.g. its page was removed), a page is auto-selected: the next surviving page, or the new last page when the last one was removed; when no value was ever given or the value is not among the options, the first usable page is taken.

## Continuous mode

`continuous` makes all pages visible with the container scrolling as one; `onPageFocus` fires when focus enters a page (without changing the active value), which you can use for scroll-linked page selection.

```tsx preview
import { useState } from "react";
import { StackLayout } from "ooui-react";

function App() {
  const [focused, setFocused] = useState("");

  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
      <div style={{ height: 140 }}>
        <StackLayout
          continuous
          framed
          onPageFocus={(value) => setFocused(String(value))}
          options={[
            { value: "a", label: "First page", padded: true, children: "First page content" },
            { value: "b", label: "Second page", padded: true, children: "Second page content" },
            { value: "c", label: "Third page", padded: true, children: "Third page content" },
          ]}
        />
      </div>
      <div>Last focused page: {focused || "(click a page to try)"}</div>
    </div>
  );
}

export default App;
```

## API

Inherits all [PanelLayout](/ooui-react/en/components/panel-layout/index.md) props, plus:

| Prop           | Description                                                                                                                      | Type                                                                   | Default      |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ------------ |
| `options`      | The page set: [PageLayout](/ooui-react/en/components/page-layout/index.md) props plus `value`                                    | `(PageLayoutProps & { value: string \| number })[]`                    | —            |
| `value`        | Current active page (controlled; passing it enables controlled mode)                                                             | `string \| number`                                                     | —            |
| `defaultValue` | Initial active page for uncontrolled use                                                                                         | `string \| number`                                                     | —            |
| `onChange`     | Active-page change callback                                                                                                      | `ChangeHandler<string \| number>`                                      | —            |
| `onPageFocus`  | Fires when focus enters a page (with the page value; for focus linkage, does not change the active value)                        | `(value: string \| number, event: FocusEvent<HTMLDivElement>) => void` | —            |
| `continuous`   | Whether all pages show (`true` ignores `value`)                                                                                  | `boolean`                                                              | `false`      |
| `scrollable`   | Whether scrollable (defaults follow `continuous`: the container scrolls in continuous mode, pages scroll individually otherwise) | `boolean`                                                              | `continuous` |

## See also

- The fields of a single page: [PageLayout](/ooui-react/en/components/page-layout/index.md)
- The wrapper with an outline menu: [BookletLayout](/ooui-react/en/components/booklet-layout/index.md)
- The value-channel contract: [Controlled and uncontrolled](/ooui-react/en/guide/controlled.md)
