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

# Tabs

> Tabbed interface for switching between panels of content.

export const ComponentPreview = ({json, height, resizable, bare, hideJson, playground, children}) => {
  const hostRef = React.useRef(null);
  const handleRef = React.useRef(null);
  const cardRef = React.useRef(null);
  const containerRef = React.useRef(null);
  const [previewWidth, setPreviewWidth] = React.useState(null);
  const [isDragging, setIsDragging] = React.useState(false);
  const [playgroundHref, setPlaygroundHref] = React.useState(null);
  React.useEffect(function () {
    if (!playground) return;
    var isLocal = location.hostname === "localhost" || location.hostname === "127.0.0.1";
    var path = isLocal ? "/playground" : "/docs/playground";
    var url = new URL(path, window.location.href);
    url.hash = "code=" + playground;
    setPlaygroundHref(url.href);
  }, [playground]);
  var jsonStr = typeof json === "string" ? json : JSON.stringify(json, null, 2);
  React.useEffect(function () {
    if (cardRef.current) {
      var card = cardRef.current.closest(".group");
      if (card) card.classList.remove("group");
    }
    var host = hostRef.current;
    if (!host || !json) return;
    function mount() {
      if (!window.__prefab || !host) return;
      var dark = document.documentElement.classList.contains("dark");
      handleRef.current = window.__prefab.mountPreview(host, jsonStr, {
        dark: dark
      });
      if (bare && host.shadowRoot) {
        var m = host.shadowRoot.querySelector("[data-prefab-mount]");
        if (m) m.style.background = "transparent";
      }
    }
    if (window.__prefab) {
      mount();
    } else {
      if (!window.__prefabLoading) {
        if (!window.__prefabReady) {
          var s = document.createElement("script");
          s.src = "/renderer.js";
          document.head.appendChild(s);
        }
        window.__prefabLoading = new Promise(function (resolve) {
          function check() {
            if (window.__prefabReady) {
              window.__prefabReady.then(resolve);
            } else {
              setTimeout(check, 10);
            }
          }
          check();
        });
      }
      window.__prefabLoading.then(mount);
    }
    var observer = new MutationObserver(function () {
      var dark = document.documentElement.classList.contains("dark");
      if (handleRef.current) handleRef.current.setDark(dark);
    });
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return function () {
      observer.disconnect();
      if (handleRef.current) {
        handleRef.current.unmount();
        handleRef.current = null;
      }
    };
  }, [json]);
  function startResize(e) {
    e.preventDefault();
    var startX = e.clientX;
    var startW = hostRef.current ? hostRef.current.offsetWidth : 0;
    var maxW = containerRef.current ? containerRef.current.offsetWidth - 10 : startW;
    setIsDragging(true);
    function onMove(ev) {
      var w = Math.max(260, Math.min(startW + (ev.clientX - startX), maxW));
      setPreviewWidth(w);
    }
    function onUp() {
      document.removeEventListener("mousemove", onMove);
      document.removeEventListener("mouseup", onUp);
      setIsDragging(false);
    }
    document.addEventListener("mousemove", onMove);
    document.addEventListener("mouseup", onUp);
  }
  if (bare) {
    return <div ref={hostRef} />;
  }
  if (resizable) {
    return <Card>
        <div ref={cardRef} />
        <div ref={containerRef} style={{
      display: "flex",
      position: "relative",
      overflow: "hidden"
    }}>
          <div ref={hostRef} style={{
      flex: previewWidth ? "none" : 1,
      width: previewWidth ? previewWidth + "px" : undefined,
      minWidth: 0
    }} />
          <div onMouseDown={startResize} style={{
      width: "14px",
      flexShrink: 0,
      cursor: "col-resize",
      background: isDragging ? "var(--border, #e5e7eb)" : "color-mix(in srgb, var(--border, #e5e7eb) 40%, transparent)",
      display: "flex",
      alignItems: "center",
      justifyContent: "center",
      transition: "background 0.15s",
      userSelect: "none"
    }}>
            <svg width="6" height="24" style={{
      opacity: 0.5
    }}>
              <circle cx="2" cy="4" r="1.2" fill="currentColor" />
              <circle cx="2" cy="9" r="1.2" fill="currentColor" />
              <circle cx="2" cy="14" r="1.2" fill="currentColor" />
              <circle cx="2" cy="19" r="1.2" fill="currentColor" />
              <circle cx="5" cy="4" r="1.2" fill="currentColor" />
              <circle cx="5" cy="9" r="1.2" fill="currentColor" />
              <circle cx="5" cy="14" r="1.2" fill="currentColor" />
              <circle cx="5" cy="19" r="1.2" fill="currentColor" />
            </svg>
          </div>
          <div style={{
      flex: previewWidth ? 1 : "0 0 24px",
      minWidth: "24px",
      background: "repeating-linear-gradient(-45deg, transparent, transparent 3px, var(--border, #e5e7eb) 3px, var(--border, #e5e7eb) 4px)",
      opacity: 0.4
    }} />
          {previewWidth && <div style={{
      position: "absolute",
      bottom: "8px",
      right: "8px",
      background: "var(--background, white)",
      border: "1px solid var(--border, #e5e7eb)",
      borderRadius: "4px",
      padding: "1px 6px",
      fontSize: "11px",
      fontFamily: "monospace",
      color: "var(--muted-foreground, #6b7280)",
      pointerEvents: "none"
    }}>
              {previewWidth}px
            </div>}
        </div>
        {playgroundHref && <div style={{
      display: "flex",
      justifyContent: "flex-end",
      padding: "4px 0 8px"
    }}>
            <a href={playgroundHref} target="_blank" rel="noopener noreferrer" style={{
      fontSize: "11px",
      opacity: 0.4,
      textDecoration: "none",
      textDecorationLine: "none",
      borderBottom: "none",
      boxShadow: "none",
      display: "inline-flex",
      alignItems: "center",
      gap: "3px",
      transition: "opacity 0.15s",
      fontWeight: 400
    }} onMouseOver={function (e) {
      e.currentTarget.style.opacity = "0.6";
    }} onMouseOut={function (e) {
      e.currentTarget.style.opacity = "0.4";
    }}>
              Edit in Playground
              <svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 3h6v6" /><path d="M10 14 21 3" /><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /></svg>
            </a>
          </div>}
        <div style={{
      marginBottom: "-2rem"
    }}>{children}</div>
      </Card>;
  }
  return <Card>
      <div ref={cardRef} />
      <div ref={hostRef} />
      {playgroundHref && <div style={{
    display: "flex",
    justifyContent: "flex-end",
    padding: "4px 0 8px"
  }}>
          <a href={playgroundHref} target="_blank" rel="noopener noreferrer" style={{
    fontSize: "11px",
    opacity: 0.4,
    textDecoration: "none",
    textDecorationLine: "none",
    borderBottom: "none",
    boxShadow: "none",
    display: "inline-flex",
    alignItems: "center",
    gap: "3px",
    transition: "opacity 0.15s",
    fontWeight: 400
  }} onMouseOver={function (e) {
    e.currentTarget.style.opacity = "0.6";
  }} onMouseOut={function (e) {
    e.currentTarget.style.opacity = "0.4";
  }}>
            Edit in Playground
            <svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 3h6v6" /><path d="M10 14 21 3" /><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /></svg>
          </a>
        </div>}
      <div style={{
    marginBottom: "-2rem"
  }}>{children}</div>
    </Card>;
};

Tabs organize content into panels that users switch between by clicking triggers. Each `Tab` child defines a trigger label and the content shown when that tab is active.

## Basic Usage

Tabs let you split related content across panels that share the same space, showing one at a time. Wrap a set of `Tab` blocks in a `Tabs` container; each `Tab` takes a visible `title` and a `value` that identifies it, and the `Tabs` `value` sets which panel opens first. Use tabs to keep a busy screen — like a settings page with separate account and password sections — organized without forcing the user to scroll past everything at once.

<ComponentPreview json={{"view":{"name":"tabs_1","value":"account","type":"Tabs","variant":"default","orientation":"horizontal","children":[{"type":"Tab","title":"Account","value":"account","disabled":false,"children":[{"type":"Card","children":[{"type":"CardHeader","children":[{"type":"CardTitle","content":"Account"},{"type":"CardDescription","content":"Make changes to your account here."}]},{"type":"CardContent","children":[{"cssClass":"gap-3","type":"Column","children":[{"type":"Label","text":"Name","optional":false},{"name":"input_18","type":"Input","inputType":"text","placeholder":"Your name","disabled":false,"readOnly":false,"required":false}]}]}]}]},{"type":"Tab","title":"Password","value":"password","disabled":false,"children":[{"type":"Card","children":[{"type":"CardHeader","children":[{"type":"CardTitle","content":"Password"},{"type":"CardDescription","content":"Change your password here."}]},{"type":"CardContent","children":[{"cssClass":"gap-3","type":"Column","children":[{"type":"Label","text":"Current Password","optional":false},{"name":"input_19","type":"Input","inputType":"password","disabled":false,"readOnly":false,"required":false},{"type":"Label","text":"New Password","optional":false},{"name":"input_20","type":"Input","inputType":"password","disabled":false,"readOnly":false,"required":false}]}]}]}]}]},"state":{"tabs_1":"account"}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgKAogICAgQ2FyZCwKICAgIENhcmRDb250ZW50LAogICAgQ2FyZERlc2NyaXB0aW9uLAogICAgQ2FyZEhlYWRlciwKICAgIENhcmRUaXRsZSwKICAgIENvbHVtbiwKICAgIElucHV0LAogICAgTGFiZWwsCiAgICBUYWIsCiAgICBUYWJzLAopCgp3aXRoIFRhYnModmFsdWU9ImFjY291bnQiKToKICAgIHdpdGggVGFiKCJBY2NvdW50IiwgdmFsdWU9ImFjY291bnQiKToKICAgICAgICB3aXRoIENhcmQoKToKICAgICAgICAgICAgd2l0aCBDYXJkSGVhZGVyKCk6CiAgICAgICAgICAgICAgICBDYXJkVGl0bGUoIkFjY291bnQiKQogICAgICAgICAgICAgICAgQ2FyZERlc2NyaXB0aW9uKCJNYWtlIGNoYW5nZXMgdG8geW91ciBhY2NvdW50IGhlcmUuIikKICAgICAgICAgICAgd2l0aCBDYXJkQ29udGVudCgpOgogICAgICAgICAgICAgICAgd2l0aCBDb2x1bW4oZ2FwPTMpOgogICAgICAgICAgICAgICAgICAgIExhYmVsKCJOYW1lIikKICAgICAgICAgICAgICAgICAgICBJbnB1dChwbGFjZWhvbGRlcj0iWW91ciBuYW1lIikKICAgIHdpdGggVGFiKCJQYXNzd29yZCIsIHZhbHVlPSJwYXNzd29yZCIpOgogICAgICAgIHdpdGggQ2FyZCgpOgogICAgICAgICAgICB3aXRoIENhcmRIZWFkZXIoKToKICAgICAgICAgICAgICAgIENhcmRUaXRsZSgiUGFzc3dvcmQiKQogICAgICAgICAgICAgICAgQ2FyZERlc2NyaXB0aW9uKCJDaGFuZ2UgeW91ciBwYXNzd29yZCBoZXJlLiIpCiAgICAgICAgICAgIHdpdGggQ2FyZENvbnRlbnQoKToKICAgICAgICAgICAgICAgIHdpdGggQ29sdW1uKGdhcD0zKToKICAgICAgICAgICAgICAgICAgICBMYWJlbCgiQ3VycmVudCBQYXNzd29yZCIpCiAgICAgICAgICAgICAgICAgICAgSW5wdXQoaW5wdXRfdHlwZT0icGFzc3dvcmQiKQogICAgICAgICAgICAgICAgICAgIExhYmVsKCJOZXcgUGFzc3dvcmQiKQogICAgICAgICAgICAgICAgICAgIElucHV0KGlucHV0X3R5cGU9InBhc3N3b3JkIikK">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import (
        Card,
        CardContent,
        CardDescription,
        CardHeader,
        CardTitle,
        Column,
        Input,
        Label,
        Tab,
        Tabs,
    )

    with Tabs(value="account"):
        with Tab("Account", value="account"):
            with Card():
                with CardHeader():
                    CardTitle("Account")
                    CardDescription("Make changes to your account here.")
                with CardContent():
                    with Column(gap=3):
                        Label("Name")
                        Input(placeholder="Your name")
        with Tab("Password", value="password"):
            with Card():
                with CardHeader():
                    CardTitle("Password")
                    CardDescription("Change your password here.")
                with CardContent():
                    with Column(gap=3):
                        Label("Current Password")
                        Input(input_type="password")
                        Label("New Password")
                        Input(input_type="password")
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "name": "tabs_1",
        "value": "account",
        "type": "Tabs",
        "variant": "default",
        "orientation": "horizontal",
        "children": [
          {
            "type": "Tab",
            "title": "Account",
            "value": "account",
            "disabled": false,
            "children": [
              {
                "type": "Card",
                "children": [
                  {
                    "type": "CardHeader",
                    "children": [
                      {"type": "CardTitle", "content": "Account"},
                      {"type": "CardDescription", "content": "Make changes to your account here."}
                    ]
                  },
                  {
                    "type": "CardContent",
                    "children": [
                      {
                        "cssClass": "gap-3",
                        "type": "Column",
                        "children": [
                          {"type": "Label", "text": "Name", "optional": false},
                          {
                            "name": "input_18",
                            "type": "Input",
                            "inputType": "text",
                            "placeholder": "Your name",
                            "disabled": false,
                            "readOnly": false,
                            "required": false
                          }
                        ]
                      }
                    ]
                  }
                ]
              }
            ]
          },
          {
            "type": "Tab",
            "title": "Password",
            "value": "password",
            "disabled": false,
            "children": [
              {
                "type": "Card",
                "children": [
                  {
                    "type": "CardHeader",
                    "children": [
                      {"type": "CardTitle", "content": "Password"},
                      {"type": "CardDescription", "content": "Change your password here."}
                    ]
                  },
                  {
                    "type": "CardContent",
                    "children": [
                      {
                        "cssClass": "gap-3",
                        "type": "Column",
                        "children": [
                          {"type": "Label", "text": "Current Password", "optional": false},
                          {
                            "name": "input_19",
                            "type": "Input",
                            "inputType": "password",
                            "disabled": false,
                            "readOnly": false,
                            "required": false
                          },
                          {"type": "Label", "text": "New Password", "optional": false},
                          {
                            "name": "input_20",
                            "type": "Input",
                            "inputType": "password",
                            "disabled": false,
                            "readOnly": false,
                            "required": false
                          }
                        ]
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      },
      "state": {"tabs_1": "account"}
    }
    ```
  </CodeGroup>
</ComponentPreview>

## Variants

The `variant` prop controls the visual style of the tab triggers. The default uses a pill-style background, while `"line"` uses an underline indicator.

<ComponentPreview json={{"view":{"cssClass":"gap-16 w-fit mx-auto","type":"Column","children":[{"name":"tabs_2","value":"one","type":"Tabs","variant":"default","orientation":"horizontal","children":[{"type":"Tab","title":"Mostly","value":"one","disabled":false,"children":[{"content":"Don't panic.","type":"Text"}]},{"type":"Tab","title":"Harmless","value":"two","disabled":false,"children":[{"content":"It's a wholly remarkable book.","type":"Text"}]},{"type":"Tab","title":"Guide","value":"three","disabled":false,"children":[{"content":"A towel is the most massively useful thing.","type":"Text"}]}]},{"name":"tabs_3","value":"one","type":"Tabs","variant":"line","orientation":"horizontal","children":[{"type":"Tab","title":"Mostly","value":"one","disabled":false,"children":[{"content":"Don't panic.","type":"Text"}]},{"type":"Tab","title":"Harmless","value":"two","disabled":false,"children":[{"content":"It's a wholly remarkable book.","type":"Text"}]},{"type":"Tab","title":"Guide","value":"three","disabled":false,"children":[{"content":"A towel is the most massively useful thing.","type":"Text"}]}]}]},"state":{"tabs_2":"one","tabs_3":"one"}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ29sdW1uLCBUYWIsIFRhYnMsIFRleHQKCndpdGggQ29sdW1uKGdhcD0xNiwgY3NzX2NsYXNzPSJ3LWZpdCBteC1hdXRvIik6CiAgICB3aXRoIFRhYnModmFsdWU9Im9uZSIpOgogICAgICAgIHdpdGggVGFiKCJNb3N0bHkiLCB2YWx1ZT0ib25lIik6CiAgICAgICAgICAgIFRleHQoIkRvbid0IHBhbmljLiIpCiAgICAgICAgd2l0aCBUYWIoIkhhcm1sZXNzIiwgdmFsdWU9InR3byIpOgogICAgICAgICAgICBUZXh0KCJJdCdzIGEgd2hvbGx5IHJlbWFya2FibGUgYm9vay4iKQogICAgICAgIHdpdGggVGFiKCJHdWlkZSIsIHZhbHVlPSJ0aHJlZSIpOgogICAgICAgICAgICBUZXh0KCJBIHRvd2VsIGlzIHRoZSBtb3N0IG1hc3NpdmVseSB1c2VmdWwgdGhpbmcuIikKCiAgICB3aXRoIFRhYnModmFyaWFudD0ibGluZSIsIHZhbHVlPSJvbmUiKToKICAgICAgICB3aXRoIFRhYigiTW9zdGx5IiwgdmFsdWU9Im9uZSIpOgogICAgICAgICAgICBUZXh0KCJEb24ndCBwYW5pYy4iKQogICAgICAgIHdpdGggVGFiKCJIYXJtbGVzcyIsIHZhbHVlPSJ0d28iKToKICAgICAgICAgICAgVGV4dCgiSXQncyBhIHdob2xseSByZW1hcmthYmxlIGJvb2suIikKICAgICAgICB3aXRoIFRhYigiR3VpZGUiLCB2YWx1ZT0idGhyZWUiKToKICAgICAgICAgICAgVGV4dCgiQSB0b3dlbCBpcyB0aGUgbW9zdCBtYXNzaXZlbHkgdXNlZnVsIHRoaW5nLiIpCg">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Column, Tab, Tabs, Text

    with Column(gap=16, css_class="w-fit mx-auto"):
        with Tabs(value="one"):
            with Tab("Mostly", value="one"):
                Text("Don't panic.")
            with Tab("Harmless", value="two"):
                Text("It's a wholly remarkable book.")
            with Tab("Guide", value="three"):
                Text("A towel is the most massively useful thing.")

        with Tabs(variant="line", value="one"):
            with Tab("Mostly", value="one"):
                Text("Don't panic.")
            with Tab("Harmless", value="two"):
                Text("It's a wholly remarkable book.")
            with Tab("Guide", value="three"):
                Text("A towel is the most massively useful thing.")
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "gap-16 w-fit mx-auto",
        "type": "Column",
        "children": [
          {
            "name": "tabs_2",
            "value": "one",
            "type": "Tabs",
            "variant": "default",
            "orientation": "horizontal",
            "children": [
              {
                "type": "Tab",
                "title": "Mostly",
                "value": "one",
                "disabled": false,
                "children": [{"content": "Don't panic.", "type": "Text"}]
              },
              {
                "type": "Tab",
                "title": "Harmless",
                "value": "two",
                "disabled": false,
                "children": [{"content": "It's a wholly remarkable book.", "type": "Text"}]
              },
              {
                "type": "Tab",
                "title": "Guide",
                "value": "three",
                "disabled": false,
                "children": [{"content": "A towel is the most massively useful thing.", "type": "Text"}]
              }
            ]
          },
          {
            "name": "tabs_3",
            "value": "one",
            "type": "Tabs",
            "variant": "line",
            "orientation": "horizontal",
            "children": [
              {
                "type": "Tab",
                "title": "Mostly",
                "value": "one",
                "disabled": false,
                "children": [{"content": "Don't panic.", "type": "Text"}]
              },
              {
                "type": "Tab",
                "title": "Harmless",
                "value": "two",
                "disabled": false,
                "children": [{"content": "It's a wholly remarkable book.", "type": "Text"}]
              },
              {
                "type": "Tab",
                "title": "Guide",
                "value": "three",
                "disabled": false,
                "children": [{"content": "A towel is the most massively useful thing.", "type": "Text"}]
              }
            ]
          }
        ]
      },
      "state": {"tabs_2": "one", "tabs_3": "one"}
    }
    ```
  </CodeGroup>
</ComponentPreview>

## Orientation

Set `orientation="vertical"` to stack the tab triggers in a column alongside the content.

<ComponentPreview json={{"view":{"cssClass":"gap-16 w-48 mx-auto","type":"Column","children":[{"name":"tabs_4","value":"one","type":"Tabs","variant":"default","orientation":"vertical","children":[{"type":"Tab","title":"Mostly","value":"one","disabled":false,"children":[{"content":"Don't panic.","type":"Text"}]},{"type":"Tab","title":"Harmless","value":"two","disabled":false,"children":[{"content":"It's a wholly remarkable book.","type":"Text"}]},{"type":"Tab","title":"Guide","value":"three","disabled":false,"children":[{"content":"A towel is the most massively useful thing.","type":"Text"}]}]},{"name":"tabs_5","value":"one","type":"Tabs","variant":"line","orientation":"vertical","children":[{"type":"Tab","title":"Mostly","value":"one","disabled":false,"children":[{"content":"Don't panic.","type":"Text"}]},{"type":"Tab","title":"Harmless","value":"two","disabled":false,"children":[{"content":"It's a wholly remarkable book.","type":"Text"}]},{"type":"Tab","title":"Guide","value":"three","disabled":false,"children":[{"content":"A towel is the most massively useful thing.","type":"Text"}]}]}]},"state":{"tabs_4":"one","tabs_5":"one"}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ29sdW1uLCBUYWIsIFRhYnMsIFRleHQKCndpdGggQ29sdW1uKGdhcD0xNiwgY3NzX2NsYXNzPSJ3LTQ4IG14LWF1dG8iKToKICAgIHdpdGggVGFicyhvcmllbnRhdGlvbj0idmVydGljYWwiLCB2YWx1ZT0ib25lIik6CiAgICAgICAgd2l0aCBUYWIoIk1vc3RseSIsIHZhbHVlPSJvbmUiKToKICAgICAgICAgICAgVGV4dCgiRG9uJ3QgcGFuaWMuIikKICAgICAgICB3aXRoIFRhYigiSGFybWxlc3MiLCB2YWx1ZT0idHdvIik6CiAgICAgICAgICAgIFRleHQoIkl0J3MgYSB3aG9sbHkgcmVtYXJrYWJsZSBib29rLiIpCiAgICAgICAgd2l0aCBUYWIoIkd1aWRlIiwgdmFsdWU9InRocmVlIik6CiAgICAgICAgICAgIFRleHQoIkEgdG93ZWwgaXMgdGhlIG1vc3QgbWFzc2l2ZWx5IHVzZWZ1bCB0aGluZy4iKQoKICAgIHdpdGggVGFicyh2YXJpYW50PSJsaW5lIiwgb3JpZW50YXRpb249InZlcnRpY2FsIiwgdmFsdWU9Im9uZSIpOgogICAgICAgIHdpdGggVGFiKCJNb3N0bHkiLCB2YWx1ZT0ib25lIik6CiAgICAgICAgICAgIFRleHQoIkRvbid0IHBhbmljLiIpCiAgICAgICAgd2l0aCBUYWIoIkhhcm1sZXNzIiwgdmFsdWU9InR3byIpOgogICAgICAgICAgICBUZXh0KCJJdCdzIGEgd2hvbGx5IHJlbWFya2FibGUgYm9vay4iKQogICAgICAgIHdpdGggVGFiKCJHdWlkZSIsIHZhbHVlPSJ0aHJlZSIpOgogICAgICAgICAgICBUZXh0KCJBIHRvd2VsIGlzIHRoZSBtb3N0IG1hc3NpdmVseSB1c2VmdWwgdGhpbmcuIikK">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Column, Tab, Tabs, Text

    with Column(gap=16, css_class="w-48 mx-auto"):
        with Tabs(orientation="vertical", value="one"):
            with Tab("Mostly", value="one"):
                Text("Don't panic.")
            with Tab("Harmless", value="two"):
                Text("It's a wholly remarkable book.")
            with Tab("Guide", value="three"):
                Text("A towel is the most massively useful thing.")

        with Tabs(variant="line", orientation="vertical", value="one"):
            with Tab("Mostly", value="one"):
                Text("Don't panic.")
            with Tab("Harmless", value="two"):
                Text("It's a wholly remarkable book.")
            with Tab("Guide", value="three"):
                Text("A towel is the most massively useful thing.")
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "gap-16 w-48 mx-auto",
        "type": "Column",
        "children": [
          {
            "name": "tabs_4",
            "value": "one",
            "type": "Tabs",
            "variant": "default",
            "orientation": "vertical",
            "children": [
              {
                "type": "Tab",
                "title": "Mostly",
                "value": "one",
                "disabled": false,
                "children": [{"content": "Don't panic.", "type": "Text"}]
              },
              {
                "type": "Tab",
                "title": "Harmless",
                "value": "two",
                "disabled": false,
                "children": [{"content": "It's a wholly remarkable book.", "type": "Text"}]
              },
              {
                "type": "Tab",
                "title": "Guide",
                "value": "three",
                "disabled": false,
                "children": [{"content": "A towel is the most massively useful thing.", "type": "Text"}]
              }
            ]
          },
          {
            "name": "tabs_5",
            "value": "one",
            "type": "Tabs",
            "variant": "line",
            "orientation": "vertical",
            "children": [
              {
                "type": "Tab",
                "title": "Mostly",
                "value": "one",
                "disabled": false,
                "children": [{"content": "Don't panic.", "type": "Text"}]
              },
              {
                "type": "Tab",
                "title": "Harmless",
                "value": "two",
                "disabled": false,
                "children": [{"content": "It's a wholly remarkable book.", "type": "Text"}]
              },
              {
                "type": "Tab",
                "title": "Guide",
                "value": "three",
                "disabled": false,
                "children": [{"content": "A towel is the most massively useful thing.", "type": "Text"}]
              }
            ]
          }
        ]
      },
      "state": {"tabs_4": "one", "tabs_5": "one"}
    }
    ```
  </CodeGroup>
</ComponentPreview>

## State Tracking

Give Tabs a `name` to sync the active tab with client state. Other components can then read or change which tab is active — useful for building wizard flows or linking navigation between different parts of the UI.

```python Tabs with State theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
from prefab_ui.components import Button, Column, Row, Tab, Tabs, Text
from prefab_ui.actions import SetState

with Column(gap=4):
    with Tabs(name="activeTab", value="general"):
        with Tab("General", value="general"):
            Text("General settings here.")
        with Tab("Advanced", value="advanced"):
            Text("Advanced settings here.")

    with Row(gap=2):
        Button("Go to General", on_click=SetState("activeTab", "general"))
        Button("Go to Advanced", on_click=SetState("activeTab", "advanced"))
```

## API Reference

<Card icon="code" title="Tabs Parameters">
  <ParamField body="variant" type="str" default="default">
    Visual style: `"default"` (pill background) or `"line"` (underline indicator).
  </ParamField>

  <ParamField body="orientation" type="str" default="horizontal">
    Layout direction: `"horizontal"` (triggers above content) or `"vertical"` (triggers beside content).
  </ParamField>

  <ParamField body="value" type="str | None" default="None">
    Value of the initially active tab. If omitted, the first tab is active.
  </ParamField>

  <ParamField body="name" type="str | None" default="None">
    State key for tracking the active tab. Enables reading/writing the active tab from other components.
  </ParamField>

  <ParamField body="on_change" type="Action | list[Action] | None" default="None">
    Action(s) triggered when the active tab changes.
  </ParamField>

  <ParamField body="css_class" type="str | None" default="None">
    Additional Tailwind CSS classes.
  </ParamField>
</Card>

<Card icon="code" title="Tab Parameters">
  <ParamField body="title" type="str" required>
    Tab trigger label. Can be passed as a positional argument.
  </ParamField>

  <ParamField body="value" type="str | None" default="None">
    Unique value identifying this tab. Defaults to the title.
  </ParamField>

  <ParamField body="disabled" type="bool" default="False">
    Whether this tab is disabled.
  </ParamField>
</Card>

## Protocol Reference

```json Tabs theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
{
  "type": "Tabs",
  "id?": "string",
  "onMount?": "any",
  "children?": "[Component]",
  "let?": "object",
  "name?": "string",
  "value?": "string",
  "variant?": "default | line | string",
  "orientation?": "horizontal | vertical",
  "onChange?": "Action | Action[]",
  "cssClass?": "string"
}
```

```json Tab theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
{
  "type": "Tab",
  "id?": "string",
  "onMount?": "any",
  "children?": "[Component]",
  "let?": "object",
  "title": "string (required)",
  "value?": "string",
  "disabled?": false,
  "cssClass?": "string"
}
```

For the complete protocol schema, see [Tabs](/protocol/tabs), [Tab](/protocol/tab).
