TakumiTakumi

Layout

Flexbox, Grid, Block, Float — what works and what to watch for.

Layout runs on Taffy, the same Rust implementation Dioxus and Bevy use. Flex and Grid are the most production-ready paths; Block works for simple stacks; Float is partial.

Flexbox

The default layout mode for most containers. Use it when the children flow along one axis with optional wrapping.

<div tw="flex items-center justify-between w-full h-full p-12 bg-slate-900 text-white">
  <div tw="flex items-center gap-4">
    <img src="/avatar.png" tw="w-16 h-16 rounded-full" />
    <span tw="text-3xl font-semibold">Takumi</span>
  </div>
  <span tw="text-xl text-slate-400">v1.2</span>
</div>

Flexbox example

Supported flex properties: flex-direction, flex-wrap, flex-flow, justify-content, align-items, align-self, align-content, gap / row-gap / column-gap, flex-grow, flex-shrink, flex-basis, flex shorthand, order.

Grid

CSS Grid runs end-to-end, including the features most JSX-to-image tools skip — named lines, template areas, repeat tracks, auto-flow.

<div
  style={{
    display: "grid",
    gridTemplateColumns: "200px 1fr 1fr",
    gridTemplateRows: "auto 1fr",
    gridTemplateAreas: `
      "header header header"
      "sidebar main aside"
    `,
    gap: 16,
    height: "100%",
  }}
>
  <div style={{ gridArea: "header" }}>Header</div>
  <div style={{ gridArea: "sidebar" }}>Sidebar</div>
  <div style={{ gridArea: "main" }}>Main</div>
  <div style={{ gridArea: "aside" }}>Aside</div>
</div>

Grid example

repeat() for symmetric track lists:

<div
  style={{
    display: "grid",
    gridTemplateColumns: "repeat(4, minmax(0, 1fr))",
    gridTemplateRows: "repeat(3, 200px)",
    gap: 12,
  }}
/>

Named lines for explicit placement without counting:

<div
  style={{
    display: "grid",
    gridTemplateColumns: "[full-start] 1fr [content-start] 800px [content-end] 1fr [full-end]",
  }}
>
  <header style={{ gridColumn: "full-start / full-end" }}>Full-bleed header</header>
  <article style={{ gridColumn: "content-start / content-end" }}>Content</article>
</div>

grid-auto-flow to control how implicit tracks fill:

<div
  style={{
    display: "grid",
    gridTemplateColumns: "repeat(3, 1fr)",
    gridAutoFlow: "dense", // pack gaps left by spanning items
    gridAutoRows: 120,
  }}
/>

Block & Float

Block stacks children vertically; each child is full-width by default. Useful for prose-like content where you just want one thing under the next.

<div style={{ display: "block" }}>
  <h1>Title</h1>
  <p>Paragraph</p>
  <p>Another paragraph</p>
</div>

float is partially supported — left and right work for simple wraps around an image, but multi-column flowing text and complex float interactions are not implemented. Reach for Flex or Grid when the layout gets non-trivial.

Common pitfalls

height: auto collapses to content. If a child uses percentage heights, it has no parent to resolve against and ends up zero-height. Either set an explicit parent height or use Flex/Grid to give the child a definite size.

Images need explicit dimensions. Without width and height on <img>, the layout pass measures the intrinsic source — fine for known assets, broken when the source URL fails to fetch (the box becomes zero). Set the dimensions you want and use object-fit to control the fit.

Percentage children require sized parents. width: 50% resolves against the parent's content box. If the parent is itself auto-sized, the percentage has nothing to bind to and falls back to content size.

drawDebugBorder shows what's actually happening. Pass drawDebugBorder: true in render options to overlay layout boxes on the output. Cheapest way to diagnose a layout that's not where you think it is.

Edit on GitHub

Last updated on

On this page