A React container component that lets you define complex grid layouts using ASCII-art-style strings. Stop mentally executing walls of JSX to figure out what your UI looks like — just draw it.
<Container
order={`
Title_________|ActionButtons
==
HitsTitle_____|HitsMeter
TotalLoadTitle|TotalLoadMeter
`}
layout={`
_|
==
_|__
_|__
`}
>
<Header layoutSlot="Title" />
<ActionButtons layoutSlot="ActionButtons" />
<div layoutSlot="HitsTitle">Hits:</div>
<Meter layoutSlot="HitsMeter" />
<div layoutSlot="TotalLoadTitle">Total Load:</div>
<Meter layoutSlot="TotalLoadMeter" />
</Container>npm install @chamie/container
# or
yarn add @chamie/containerThe Container component renders a flex-based grid. You describe it with two string props:
Defines which components go where. Each line is a row, cells are separated by |. Underscores are visual padding and are ignored during parsing.
Title_________|ActionButtons
==
HitsTitle_____|HitsMeter
|separates cells in a row==lines (or any line starting with==) are ignored — use them as visual separators. Or adding comments, if you feel like those are needed for some reason- Underscores in component names are stripped, so
HitsTitle_____andHitsTitleresolve to the same slot - An empty cell (only underscores, no name) renders as a spacer with no matching child required
Defines the size of each cell, row by row, matching the structure of order. If omitted, cells share space equally.
_|
==
_|__
_|__
Each cell value can be:
| Format | Meaning | Example |
|---|---|---|
| Underscores | Flex ratio by character count | ___ → flex: 3 |
| Plain number | Explicit flex value | 5 → flex: 5 |
| CSS size unit | Fixed width | 20px, 10%, 4vw |
Mixed formats are supported per row:
___|10%|20px
== lines are ignored here too, so you can keep order and layout visually aligned.
Every child that should be placed by the container needs a layoutSlot prop matching the name used in order. Works on any element — custom components, plain <div>s, anything React can render.
<div layoutSlot="HitsTitle">Hits:</div>
<Meter layoutSlot="HitsMeter" value={hits} />Children without a layoutSlot are ignored.
| Prop | Type | Required | Description |
|---|---|---|---|
order |
string |
✓ | ASCII-art slot layout |
layout |
string |
Cell sizing configuration | |
children |
ReactElement[] |
✓ | Components with layoutSlot props |
strict |
boolean |
Throw on mismatches instead of warning | |
classNamePrefix |
string |
Prefix for generated class names (container, row, col) |
<Container order="Left|Center|Right">
<Nav layoutSlot="Left" />
<Main layoutSlot="Center" />
<Aside layoutSlot="Right" />
</Container><Container
order="Sidebar|Content"
layout="240px|_"
>
<Sidebar layoutSlot="Sidebar" />
<Content layoutSlot="Content" />
</Container>Empty cells (pure underscores) render as unstyled divs with no child required:
<Container
order={`
Logo___|_|NavLinks
`}
layout={`
__|_|__
`}
>
<Logo layoutSlot="Logo" />
<NavLinks layoutSlot="NavLinks" />
{/* middle cell is a spacer, no child needed */}
</Container>And of course you can nest them if you want a more complex layout:
<Container order="Sidebar|Main">
<Sidebar layoutSlot="Sidebar" />
<Container layoutSlot="Main"
order={`
Header
Content
`}
>
<Header layoutSlot="Header" />
<Content layoutSlot="Content" />
</Container>
</Container>If you want typos caught by TypeScript:
const slots = {
Title: "Title",
Actions: "Actions",
Chart: "Chart",
} as const;
<Container
order={`
${slots.Title}__|${slots.Actions}
==
${slots.Chart}
`}
>
<Header layoutSlot={slots.Title} />
<Toolbar layoutSlot={slots.Actions} />
<Chart layoutSlot={slots.Chart} />
</Container>By default, mismatches warn to the console and render a red Missing: SlotName placeholder in place of the absent child.
Pass strict to throw instead — useful for catching layout/child mismatches at development time:
<Container order="A|B" strict>
<A layoutSlot="A" />
{/* B missing → throws */}
</Container>The container generates three class names, optionally prefixed via classNamePrefix:
| Element | Default class | With classNamePrefix="my" |
|---|---|---|
| Root div | container |
my-container |
| Row div | row |
my-row |
| Cell div | col |
my-col |
MIT