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, and this page is available as Markdown at /ooui-react/en/components/stack-layout/index.md.
  • English
  • StackLayout

    Source | Original component

    A stack layout: renders a set of pages 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.

    Basic usage

    The active page rides the value / defaultValue / onChange channels; an option is a PageLayout prop set plus value (which doubles as the match key and the list key).

    First page content
    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;
    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'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.

    First page content
    Second page content
    Third page content
    Last focused page: (click a page to try)
    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 props, plus:

    PropDescriptionTypeDefault
    optionsThe page set: PageLayout props plus value(PageLayoutProps & { value: string | number })[]—
    valueCurrent active page (controlled; passing it enables controlled mode)string | number—
    defaultValueInitial active page for uncontrolled usestring | number—
    onChangeActive-page change callbackChangeHandler<string | number>—
    onPageFocusFires 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—
    continuousWhether all pages show (true ignores value)booleanfalse
    scrollableWhether scrollable (defaults follow continuous: the container scrolls in continuous mode, pages scroll individually otherwise)booleancontinuous

    See also