> ## 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.

# Grid

> CSS grid container with configurable columns for equal or custom-width layouts.

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>;
};

Grid is a CSS grid with configurable columns. Pass an integer for equal-width columns (1-12), or a list for custom widths like `[1, 3]` or `[1, "auto", 1]`. Children fill cells left-to-right, wrapping to new rows.

## Basic Usage

<ComponentPreview json={{"view":{"cssClass":"gap-4 grid-cols-3","type":"Grid","children":[{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgKAogICAgRGl2LAogICAgR3JpZCwKKQoKd2l0aCBHcmlkKGNvbHVtbnM9MywgZ2FwPTQpOgogICAgZm9yIF8gaW4gcmFuZ2UoNik6CiAgICAgICAgRGl2KGNzc19jbGFzcz0iYmctZW1lcmFsZC01MDAgcm91bmRlZC1tZCBoLTEwIikK">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import (
        Div,
        Grid,
    )

    with Grid(columns=3, gap=4):
        for _ in range(6):
            Div(css_class="bg-emerald-500 rounded-md h-10")
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "gap-4 grid-cols-3",
        "type": "Grid",
        "children": [
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"}
        ]
      }
    }
    ```
  </CodeGroup>
</ComponentPreview>

## Columns

The same set of children reflows as the column count changes.

<Tabs>
  <Tab title="columns=2">
    <ComponentPreview json={{"view":{"cssClass":"gap-4 grid-cols-2 p-3 border-3 border-dashed","type":"Grid","children":[{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgRGl2LCBHcmlkCgp3aXRoIEdyaWQoY29sdW1ucz0yLCBnYXA9NCwgY3NzX2NsYXNzPSJwLTMgYm9yZGVyLTMgYm9yZGVyLWRhc2hlZCIpOgogICAgZm9yIF8gaW4gcmFuZ2UoNik6CiAgICAgICAgRGl2KGNzc19jbGFzcz0iYmctZW1lcmFsZC01MDAgcm91bmRlZC1tZCBoLTEwIikK">
      <CodeGroup>
        ```python Python highlight={3} icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
        from prefab_ui.components import Div, Grid

        with Grid(columns=2, gap=4, css_class="p-3 border-3 border-dashed"):
            for _ in range(6):
                Div(css_class="bg-emerald-500 rounded-md h-10")
        ```

        ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
        {
          "view": {
            "cssClass": "gap-4 grid-cols-2 p-3 border-3 border-dashed",
            "type": "Grid",
            "children": [
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"}
            ]
          }
        }
        ```
      </CodeGroup>
    </ComponentPreview>
  </Tab>

  <Tab title="columns=3">
    <ComponentPreview json={{"view":{"cssClass":"gap-4 grid-cols-3 p-3 border-3 border-dashed","type":"Grid","children":[{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgRGl2LCBHcmlkCgp3aXRoIEdyaWQoY29sdW1ucz0zLCBnYXA9NCwgY3NzX2NsYXNzPSJwLTMgYm9yZGVyLTMgYm9yZGVyLWRhc2hlZCIpOgogICAgZm9yIF8gaW4gcmFuZ2UoNik6CiAgICAgICAgRGl2KGNzc19jbGFzcz0iYmctZW1lcmFsZC01MDAgcm91bmRlZC1tZCBoLTEwIikK">
      <CodeGroup>
        ```python Python highlight={3} icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
        from prefab_ui.components import Div, Grid

        with Grid(columns=3, gap=4, css_class="p-3 border-3 border-dashed"):
            for _ in range(6):
                Div(css_class="bg-emerald-500 rounded-md h-10")
        ```

        ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
        {
          "view": {
            "cssClass": "gap-4 grid-cols-3 p-3 border-3 border-dashed",
            "type": "Grid",
            "children": [
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"}
            ]
          }
        }
        ```
      </CodeGroup>
    </ComponentPreview>
  </Tab>

  <Tab title="columns=4">
    <ComponentPreview json={{"view":{"cssClass":"gap-4 grid-cols-4 p-3 border-3 border-dashed","type":"Grid","children":[{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgRGl2LCBHcmlkCgp3aXRoIEdyaWQoY29sdW1ucz00LCBnYXA9NCwgY3NzX2NsYXNzPSJwLTMgYm9yZGVyLTMgYm9yZGVyLWRhc2hlZCIpOgogICAgZm9yIF8gaW4gcmFuZ2UoNik6CiAgICAgICAgRGl2KGNzc19jbGFzcz0iYmctZW1lcmFsZC01MDAgcm91bmRlZC1tZCBoLTEwIikK">
      <CodeGroup>
        ```python Python highlight={3} icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
        from prefab_ui.components import Div, Grid

        with Grid(columns=4, gap=4, css_class="p-3 border-3 border-dashed"):
            for _ in range(6):
                Div(css_class="bg-emerald-500 rounded-md h-10")
        ```

        ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
        {
          "view": {
            "cssClass": "gap-4 grid-cols-4 p-3 border-3 border-dashed",
            "type": "Grid",
            "children": [
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
              {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"}
            ]
          }
        }
        ```
      </CodeGroup>
    </ComponentPreview>
  </Tab>
</Tabs>

## Custom Column Widths

Pass a list to `columns` for unequal-width columns. Integers become fractional units (`1` → `1fr`, `2` → `2fr`) and strings pass through as CSS values (`"auto"`, `"200px"`).

<ComponentPreview json={{"view":{"cssClass":"gap-6 p-3 border-3 border-dashed","type":"Grid","columnTemplate":"1fr 3fr","children":[{"cssClass":"p-3 border-3 border-dashed","type":"Column","children":[{"content":"Sidebar","type":"H3"},{"content":"Navigation or filters.","type":"P"}]},{"cssClass":"p-3 border-3 border-dashed","type":"Column","children":[{"content":"Main Content","type":"H3"},{"content":"The sidebar gets 1/4 of the space; main content gets 3/4.","type":"P"}]}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ29sdW1uLCBHcmlkLCBIMywgUAoKd2l0aCBHcmlkKGNvbHVtbnM9WzEsIDNdLCBnYXA9NiwgY3NzX2NsYXNzPSJwLTMgYm9yZGVyLTMgYm9yZGVyLWRhc2hlZCIpOgogICAgd2l0aCBDb2x1bW4oY3NzX2NsYXNzPSJwLTMgYm9yZGVyLTMgYm9yZGVyLWRhc2hlZCIpOgogICAgICAgIEgzKCJTaWRlYmFyIikKICAgICAgICBQKCJOYXZpZ2F0aW9uIG9yIGZpbHRlcnMuIikKICAgIHdpdGggQ29sdW1uKGNzc19jbGFzcz0icC0zIGJvcmRlci0zIGJvcmRlci1kYXNoZWQiKToKICAgICAgICBIMygiTWFpbiBDb250ZW50IikKICAgICAgICBQKCJUaGUgc2lkZWJhciBnZXRzIDEvNCBvZiB0aGUgc3BhY2U7IG1haW4gY29udGVudCBnZXRzIDMvNC4iKQo">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Column, Grid, H3, P

    with Grid(columns=[1, 3], gap=6, css_class="p-3 border-3 border-dashed"):
        with Column(css_class="p-3 border-3 border-dashed"):
            H3("Sidebar")
            P("Navigation or filters.")
        with Column(css_class="p-3 border-3 border-dashed"):
            H3("Main Content")
            P("The sidebar gets 1/4 of the space; main content gets 3/4.")
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "gap-6 p-3 border-3 border-dashed",
        "type": "Grid",
        "columnTemplate": "1fr 3fr",
        "children": [
          {
            "cssClass": "p-3 border-3 border-dashed",
            "type": "Column",
            "children": [
              {"content": "Sidebar", "type": "H3"},
              {"content": "Navigation or filters.", "type": "P"}
            ]
          },
          {
            "cssClass": "p-3 border-3 border-dashed",
            "type": "Column",
            "children": [
              {"content": "Main Content", "type": "H3"},
              {
                "content": "The sidebar gets 1/4 of the space; main content gets 3/4.",
                "type": "P"
              }
            ]
          }
        ]
      }
    }
    ```
  </CodeGroup>
</ComponentPreview>

The `"auto"` keyword sizes a column to its content, which works well for separators or fixed-width controls between fluid areas.

<ComponentPreview json={{"view":{"cssClass":"gap-6 p-3 border-3 border-dashed","type":"Grid","columnTemplate":"1fr auto 1fr","children":[{"cssClass":"p-3 border-3 border-dashed","type":"Column","children":[{"content":"Panel A","type":"H3"},{"content":"Left side content.","type":"P"}]},{"type":"Separator","orientation":"vertical"},{"cssClass":"p-3 border-3 border-dashed","type":"Column","children":[{"content":"Panel B","type":"H3"},{"content":"Right side content.","type":"P"}]}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ29sdW1uLCBHcmlkLCBIMywgUCwgU2VwYXJhdG9yCgp3aXRoIEdyaWQoY29sdW1ucz1bMSwgImF1dG8iLCAxXSwgZ2FwPTYsIGNzc19jbGFzcz0icC0zIGJvcmRlci0zIGJvcmRlci1kYXNoZWQiKToKICAgIHdpdGggQ29sdW1uKGNzc19jbGFzcz0icC0zIGJvcmRlci0zIGJvcmRlci1kYXNoZWQiKToKICAgICAgICBIMygiUGFuZWwgQSIpCiAgICAgICAgUCgiTGVmdCBzaWRlIGNvbnRlbnQuIikKICAgIFNlcGFyYXRvcihvcmllbnRhdGlvbj0idmVydGljYWwiKQogICAgd2l0aCBDb2x1bW4oY3NzX2NsYXNzPSJwLTMgYm9yZGVyLTMgYm9yZGVyLWRhc2hlZCIpOgogICAgICAgIEgzKCJQYW5lbCBCIikKICAgICAgICBQKCJSaWdodCBzaWRlIGNvbnRlbnQuIikK">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Column, Grid, H3, P, Separator

    with Grid(columns=[1, "auto", 1], gap=6, css_class="p-3 border-3 border-dashed"):
        with Column(css_class="p-3 border-3 border-dashed"):
            H3("Panel A")
            P("Left side content.")
        Separator(orientation="vertical")
        with Column(css_class="p-3 border-3 border-dashed"):
            H3("Panel B")
            P("Right side content.")
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "gap-6 p-3 border-3 border-dashed",
        "type": "Grid",
        "columnTemplate": "1fr auto 1fr",
        "children": [
          {
            "cssClass": "p-3 border-3 border-dashed",
            "type": "Column",
            "children": [
              {"content": "Panel A", "type": "H3"},
              {"content": "Left side content.", "type": "P"}
            ]
          },
          {"type": "Separator", "orientation": "vertical"},
          {
            "cssClass": "p-3 border-3 border-dashed",
            "type": "Column",
            "children": [
              {"content": "Panel B", "type": "H3"},
              {"content": "Right side content.", "type": "P"}
            ]
          }
        ]
      }
    }
    ```
  </CodeGroup>
</ComponentPreview>

## Spanning Cells

Wrap a child in `GridItem` to make it span multiple columns or rows. Children without a `GridItem` wrapper take a single cell. The grid still auto-flows, so items reflow responsively as columns change.

<ComponentPreview json={{"view":{"cssClass":"gap-4 grid-cols-4","type":"Grid","children":[{"type":"GridItem","colSpan":2,"rowSpan":1,"children":[{"cssClass":"bg-blue-500 rounded-md h-10","type":"Div"}]},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"type":"GridItem","colSpan":3,"rowSpan":1,"children":[{"cssClass":"bg-purple-500 rounded-md h-10","type":"Div"}]}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgRGl2LCBHcmlkLCBHcmlkSXRlbQoKd2l0aCBHcmlkKGNvbHVtbnM9NCwgZ2FwPTQpOgogICAgd2l0aCBHcmlkSXRlbShjb2xfc3Bhbj0yKToKICAgICAgICBEaXYoY3NzX2NsYXNzPSJiZy1ibHVlLTUwMCByb3VuZGVkLW1kIGgtMTAiKQogICAgRGl2KGNzc19jbGFzcz0iYmctZW1lcmFsZC01MDAgcm91bmRlZC1tZCBoLTEwIikKICAgIERpdihjc3NfY2xhc3M9ImJnLWVtZXJhbGQtNTAwIHJvdW5kZWQtbWQgaC0xMCIpCiAgICBEaXYoY3NzX2NsYXNzPSJiZy1lbWVyYWxkLTUwMCByb3VuZGVkLW1kIGgtMTAiKQogICAgd2l0aCBHcmlkSXRlbShjb2xfc3Bhbj0zKToKICAgICAgICBEaXYoY3NzX2NsYXNzPSJiZy1wdXJwbGUtNTAwIHJvdW5kZWQtbWQgaC0xMCIpCg">
  <CodeGroup>
    ```python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Div, Grid, GridItem

    with Grid(columns=4, gap=4):
        with GridItem(col_span=2):
            Div(css_class="bg-blue-500 rounded-md h-10")
        Div(css_class="bg-emerald-500 rounded-md h-10")
        Div(css_class="bg-emerald-500 rounded-md h-10")
        Div(css_class="bg-emerald-500 rounded-md h-10")
        with GridItem(col_span=3):
            Div(css_class="bg-purple-500 rounded-md h-10")
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "gap-4 grid-cols-4",
        "type": "Grid",
        "children": [
          {
            "type": "GridItem",
            "colSpan": 2,
            "rowSpan": 1,
            "children": [{"cssClass": "bg-blue-500 rounded-md h-10", "type": "Div"}]
          },
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
          {
            "type": "GridItem",
            "colSpan": 3,
            "rowSpan": 1,
            "children": [{"cssClass": "bg-purple-500 rounded-md h-10", "type": "Div"}]
          }
        ]
      }
    }
    ```
  </CodeGroup>
</ComponentPreview>

`row_span` works the same way for vertical spanning. This is useful for tall cards alongside shorter ones in dashboard-style layouts.

<ComponentPreview json={{"view":{"cssClass":"gap-4 grid-cols-3","type":"Grid","children":[{"type":"GridItem","colSpan":1,"rowSpan":2,"children":[{"cssClass":"bg-blue-500 rounded-md h-full min-h-24 flex items-center justify-center","type":"Div","children":[{"cssClass":"text-white font-semibold","content":"Tall","type":"Text"}]}]},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-amber-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-amber-500 rounded-md h-10","type":"Div"}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgRGl2LCBHcmlkLCBHcmlkSXRlbSwgVGV4dAoKd2l0aCBHcmlkKGNvbHVtbnM9MywgZ2FwPTQpOgogICAgd2l0aCBHcmlkSXRlbShyb3dfc3Bhbj0yKToKICAgICAgICBEaXYoY3NzX2NsYXNzPSJiZy1ibHVlLTUwMCByb3VuZGVkLW1kIGgtZnVsbCBtaW4taC0yNCBmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciIsCiAgICAgICAgICAgIGNoaWxkcmVuPVtUZXh0KCJUYWxsIiwgY3NzX2NsYXNzPSJ0ZXh0LXdoaXRlIGZvbnQtc2VtaWJvbGQiKV0pCiAgICBEaXYoY3NzX2NsYXNzPSJiZy1lbWVyYWxkLTUwMCByb3VuZGVkLW1kIGgtMTAiKQogICAgRGl2KGNzc19jbGFzcz0iYmctYW1iZXItNTAwIHJvdW5kZWQtbWQgaC0xMCIpCiAgICBEaXYoY3NzX2NsYXNzPSJiZy1lbWVyYWxkLTUwMCByb3VuZGVkLW1kIGgtMTAiKQogICAgRGl2KGNzc19jbGFzcz0iYmctYW1iZXItNTAwIHJvdW5kZWQtbWQgaC0xMCIpCg">
  <CodeGroup>
    ```python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Div, Grid, GridItem, Text

    with Grid(columns=3, gap=4):
        with GridItem(row_span=2):
            Div(css_class="bg-blue-500 rounded-md h-full min-h-24 flex items-center justify-center",
                children=[Text("Tall", css_class="text-white font-semibold")])
        Div(css_class="bg-emerald-500 rounded-md h-10")
        Div(css_class="bg-amber-500 rounded-md h-10")
        Div(css_class="bg-emerald-500 rounded-md h-10")
        Div(css_class="bg-amber-500 rounded-md h-10")
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "gap-4 grid-cols-3",
        "type": "Grid",
        "children": [
          {
            "type": "GridItem",
            "colSpan": 1,
            "rowSpan": 2,
            "children": [
              {
                "cssClass": "bg-blue-500 rounded-md h-full min-h-24 flex items-center justify-center",
                "type": "Div",
                "children": [{"cssClass": "text-white font-semibold", "content": "Tall", "type": "Text"}]
              }
            ]
          },
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
          {"cssClass": "bg-amber-500 rounded-md h-10", "type": "Div"},
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
          {"cssClass": "bg-amber-500 rounded-md h-10", "type": "Div"}
        ]
      }
    }
    ```
  </CodeGroup>
</ComponentPreview>

<Tip>
  For explicit row/column placement (pinning items to exact coordinates), use [Dashboard](/components/dashboard-grid) instead. GridItem controls *size*; DashboardItem controls *size and position*.
</Tip>

## Auto-fill Columns

Set `min_column_width` instead of `columns` to let CSS Grid automatically fit as many columns as possible, each at least the given width. Drag the handle to see the grid reflow.

<ComponentPreview resizable json={{"view":{"cssClass":"gap-4","type":"Grid","minColumnWidth":"10rem","children":[{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"},{"cssClass":"bg-emerald-500 rounded-md h-10","type":"Div"}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgRGl2LCBHcmlkCgp3aXRoIEdyaWQobWluX2NvbHVtbl93aWR0aD0iMTByZW0iLCBnYXA9NCk6CiAgICBmb3IgXyBpbiByYW5nZSg2KToKICAgICAgICBEaXYoY3NzX2NsYXNzPSJiZy1lbWVyYWxkLTUwMCByb3VuZGVkLW1kIGgtMTAiKQo">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Div, Grid

    with Grid(min_column_width="10rem", gap=4):
        for _ in range(6):
            Div(css_class="bg-emerald-500 rounded-md h-10")
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "gap-4",
        "type": "Grid",
        "minColumnWidth": "10rem",
        "children": [
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"},
          {"cssClass": "bg-emerald-500 rounded-md h-10", "type": "Div"}
        ]
      }
    }
    ```
  </CodeGroup>
</ComponentPreview>

## Responsive Columns

Pass a dictionary of breakpoints to `columns` for precise control at specific viewport widths. The `default` key sets the base, and Tailwind breakpoints (`sm`, `md`, `lg`, `xl`, `2xl`) override it progressively.

```python theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
Grid(columns={"default": 1, "md": 2, "lg": 3})
```

See [Responsive Layout Props](/styling/css#responsive-layout-props) for responsive `gap`, `css_class`, and the `Responsive` helper.

## Nested Content

Grids nest naturally with other containers:

<ComponentPreview json={{"view":{"cssClass":"gap-6 grid-cols-2 p-3 border-3 border-dashed","type":"Grid","children":[{"cssClass":"p-3 border-3 border-dashed","type":"Column","children":[{"content":"Left Panel","type":"H3"},{"content":"Primary content goes here.","type":"P"}]},{"cssClass":"p-3 border-3 border-dashed","type":"Column","children":[{"content":"Right Panel","type":"H3"},{"content":"Secondary content goes here.","type":"P"}]}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgKAogICAgQ29sdW1uLAogICAgR3JpZCwKICAgIEgzLAogICAgUCwKKQoKd2l0aCBHcmlkKGNvbHVtbnM9MiwgZ2FwPTYsIGNzc19jbGFzcz0icC0zIGJvcmRlci0zIGJvcmRlci1kYXNoZWQiKToKICAgIHdpdGggQ29sdW1uKGNzc19jbGFzcz0icC0zIGJvcmRlci0zIGJvcmRlci1kYXNoZWQiKToKICAgICAgICBIMygiTGVmdCBQYW5lbCIpCiAgICAgICAgUCgiUHJpbWFyeSBjb250ZW50IGdvZXMgaGVyZS4iKQogICAgd2l0aCBDb2x1bW4oY3NzX2NsYXNzPSJwLTMgYm9yZGVyLTMgYm9yZGVyLWRhc2hlZCIpOgogICAgICAgIEgzKCJSaWdodCBQYW5lbCIpCiAgICAgICAgUCgiU2Vjb25kYXJ5IGNvbnRlbnQgZ29lcyBoZXJlLiIpCg">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import (
        Column,
        Grid,
        H3,
        P,
    )

    with Grid(columns=2, gap=6, css_class="p-3 border-3 border-dashed"):
        with Column(css_class="p-3 border-3 border-dashed"):
            H3("Left Panel")
            P("Primary content goes here.")
        with Column(css_class="p-3 border-3 border-dashed"):
            H3("Right Panel")
            P("Secondary content goes here.")
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "gap-6 grid-cols-2 p-3 border-3 border-dashed",
        "type": "Grid",
        "children": [
          {
            "cssClass": "p-3 border-3 border-dashed",
            "type": "Column",
            "children": [
              {"content": "Left Panel", "type": "H3"},
              {"content": "Primary content goes here.", "type": "P"}
            ]
          },
          {
            "cssClass": "p-3 border-3 border-dashed",
            "type": "Column",
            "children": [
              {"content": "Right Panel", "type": "H3"},
              {"content": "Secondary content goes here.", "type": "P"}
            ]
          }
        ]
      }
    }
    ```
  </CodeGroup>
</ComponentPreview>

## API Reference

<Card icon="code" title="Grid Parameters">
  <ParamField body="columns" type="int | list | dict | Responsive" default="3">
    Number of grid columns (1-12), or a list of column widths. Can be passed as a positional argument. In a list, integers become fractional units (`1` → `1fr`) and strings pass through (`"auto"`, `"200px"`). Pass a dict or `Responsive()` for breakpoint-aware column counts. Mutually exclusive with `min_column_width`.
  </ParamField>

  <ParamField body="min_column_width" type="str | None" default="None">
    Minimum column width for auto-fill responsive grids (e.g. `"16rem"`). CSS Grid fits as many columns as possible at this minimum width. Mutually exclusive with `columns`.
  </ParamField>

  <ParamField body="gap" type="int | tuple | Responsive | None" default="None">
    Gap between children. An int maps to `gap-{n}`. A tuple `(x, y)` sets per-axis gaps; use `None` to skip an axis. A `Responsive()` sets different gaps at different breakpoints.
  </ParamField>

  <ParamField body="align" type="str | None" default="None">
    Cross-axis alignment: `"start"`, `"center"`, `"end"`, `"stretch"`, `"baseline"`.
  </ParamField>

  <ParamField body="justify" type="str | None" default="None">
    Main-axis distribution: `"start"`, `"center"`, `"end"`, `"between"`, `"around"`, `"evenly"`, `"stretch"`.
  </ParamField>

  <ParamField body="css_class" type="str | Responsive | None" default="None">
    Additional Tailwind CSS classes. A `Responsive()` compiles breakpoint-prefixed classes.
  </ParamField>
</Card>

<Card icon="code" title="GridItem Parameters">
  <ParamField body="col_span" type="int" default="1">
    Number of columns to span.
  </ParamField>

  <ParamField body="row_span" type="int" default="1">
    Number of rows to span.
  </ParamField>

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

## Protocol Reference

```json Grid theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
{
  "type": "Grid",
  "id?": "string",
  "onMount?": "any",
  "children?": "[Component]",
  "let?": "object",
  "columns?": "number | number[] | object",
  "columnTemplate?": "string",
  "minColumnWidth?": "string",
  "gap?": "number | [number, number]",
  "align?": "start | center | end | stretch | baseline",
  "justify?": "start | center | end | between | around | evenly | stretch",
  "cssClass?": "string"
}
```

```json GridItem theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
{
  "type": "GridItem",
  "id?": "string",
  "onMount?": "any",
  "children?": "[Component]",
  "let?": "object",
  "colSpan?": 1,
  "rowSpan?": 1,
  "cssClass?": "string"
}
```

For the complete protocol schema, see [Grid](/protocol/grid), [GridItem](/protocol/grid-item).
