@chamie/container
v0.2.2
Published
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
Readme
@chamie/container (working title)
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>Install
npm install @chamie/container
# or
yarn add @chamie/containerHow it works
The Container component renders a flex-based grid. You describe it with two string props:
order (required)
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
layout (optional)
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.
layoutSlot prop
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.
Props
| 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) |
Examples
Equal columns, no layout prop needed
<Container order="Left|Center|Right">
<Nav layoutSlot="Left" />
<Main layoutSlot="Center" />
<Aside layoutSlot="Right" />
</Container>Fixed sidebar + fluid content
<Container
order="Sidebar|Content"
layout="240px|_"
>
<Sidebar layoutSlot="Sidebar" />
<Content layoutSlot="Content" />
</Container>Spacer cells
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>Nesting
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>Compile-time slot name safety
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>Error handling
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>CSS classes
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 |
License
MIT
