Skip to content

StackLayout

SM · 950B gzip budget

Vertical or horizontal stacking with consistent spacing.

Category
Media & layout
Budget
sm, single-purpose control
External runtime
React / React DOM only
axe fixtureSSR rendersource scanbundle budget

Preview

Live fixture
Preview locale
A
B

Try the component here. Locale-aware formatting and direction follow the selected language; example content and labels are not automatically translated. Overlay demos use interactive launchers.

Install

npx shadcn@latest add https://gear5-ui.vercel.app/r/stack-layout.json

Copies the source into your project.

New here? Set up Tailwind and import aliases first →

Source & props

Edit on GitHub ↗

Prop types and inline documentation are included below. This is repository source; the installer rewrites shared imports for your project.

"use client";

import React from "react";

export interface StackLayoutProps {
  children: React.ReactNode;
  direction?: "vertical" | "horizontal";
  gap?: string;
  dividers?: boolean;
  dividerColor?: string;
  className?: string;
  as?: "div" | "section" | "nav" | "ul" | "ol";
}

export function StackLayout({
  children,
  direction = "vertical",
  gap = "1rem",
  dividers = false,
  dividerColor = "var(--color-border, #e5e7eb)",
  className = "",
  as = "div",
}: StackLayoutProps) {
  const isHorizontal = direction === "horizontal";
  const childArray = React.Children.toArray(children);

  const containerStyle: React.CSSProperties = {
    display: "flex",
    flexDirection: isHorizontal ? "row" : "column",
    gap: dividers ? "0" : gap,
    margin: 0,
    padding: 0,
    listStyle: "none",
  };

  const itemStyle: React.CSSProperties = isHorizontal
    ? {
        borderInlineEnd: dividers
          ? `1px solid ${dividerColor}`
          : undefined,
        paddingInlineEnd: dividers ? gap : undefined,
      }
    : {
        borderBottom: dividers ? `1px solid ${dividerColor}` : undefined,
        paddingBottom: dividers ? gap : undefined,
      };

  const Tag = as;
  const isList = as === "ul" || as === "ol";
  const ItemTag = isList ? "li" : "div";

  return (
    <Tag className={className} style={containerStyle} role={isList ? "list" : undefined}>
      {childArray.map((child, index) => (
        <ItemTag key={index} style={{ ...itemStyle, display: "block" }} role={isList ? "listitem" : undefined}>
          {child}
        </ItemTag>
      ))}
    </Tag>
  );
}

What CI checks

Quality contract
  • Bundled, minified and gzipped against its tier budget
  • Audited by axe in the state previewed above
  • Rendered through react-dom/server with no browser globals
  • Scanned for network calls, dangerous sinks, and unguarded animation