Skip to content

Containers & Layouts

Complete guide to container types (layouts) for organizing content in Wire-DSL wireframes.


Containers are structural elements that organize and position child components. Wire-DSL provides 5 main container types, each with specific use cases and properties.

ContainerPurposeChildrenUse Case
StackLinear arrangementMultipleVertical/horizontal lists
GridMulti-column layoutCellsResponsive layouts
SplitTwo-panel layoutTwo stacksSidebar + content
PanelSingle bordered containerSingleGrouped content sections
CardFlexible content boxMultipleProduct cards, profiles

Linear layout that stacks children in a single direction with consistent spacing.

Arrange elements vertically or horizontally with uniform spacing. The most common container for building layouts.

layout stack(direction: vertical, gap: md, padding: lg) {
component Heading text: "Title"
component Text content: "Content"
component Button text: "Action"
}
PropertyTypeOptionsDefaultDescription
directionstringvertical, horizontalverticalStack direction
gapstringxs, sm, md, lg, xlmdSpacing between children
paddingstringxs, sm, md, lg, xlnoneInternal padding
alignstringjustify, left, center, rightjustifyHorizontal alignment (horizontal stacks only)
  • xs: 4px
  • sm: 8px
  • md: 16px
  • lg: 24px
  • xl: 32px

Vertical Stack (Default):

layout stack(direction: vertical, gap: md) {
component Heading text: "Form"
component Input label: "Name"
component Input label: "Email"
component Button text: "Submit" variant: primary
}

Horizontal Stack with Equal Width (Default):

layout stack(direction: horizontal, gap: md, padding: md) {
component Button text: "Save" variant: primary
component Button text: "Cancel" variant: secondary
component Button text: "Delete" variant: danger
}

All buttons divide the width equally, filling 100% of the container.

Horizontal Stack - Left Aligned:

layout stack(direction: horizontal, gap: md, align: "left") {
component Button text: "Save" variant: primary
component Button text: "Cancel"
component Button text: "Reset"
}

Buttons group on the left with their natural width, useful for left-aligned action bars.

Horizontal Stack - Center Aligned:

layout stack(direction: horizontal, gap: md, align: "center") {
component Button text: "Agree" variant: primary
component Button text: "Disagree"
}

Buttons group in the center with their natural width, ideal for dialogs or confirmations.

Horizontal Stack - Right Aligned:

layout stack(direction: horizontal, gap: md, align: "right") {
component Button text: "Back"
component Button text: "Next" variant: primary
}

Buttons group on the right with their natural width, typical pattern for form navigation or dialog actions.

The align property controls how children are distributed horizontally in direction: horizontal stacks:

ValueBehaviorUse Case
justify (default)Equal width, fills 100%Standard layouts, button groups
leftNatural widths, grouped leftLeft-aligned action bars
centerNatural widths, centeredDialogs, centered confirmations
rightNatural widths, grouped rightForm navigation, right-aligned actions

⚠️ Padding Inheritance: Stacks without explicit padding have 0px padding by default (no inheritance from project style)

⚠️ Align in Horizontal Stacks Only: The align property only affects direction: horizontal stacks.

⚠️ Nesting: Avoid excessive nesting of the same layout type; use Grid for multi-column layouts instead


12-column responsive grid system for flexible multi-column layouts.

Create responsive column-based layouts. Ideal for dashboards, data tables, and flexible content arrangements.

layout grid(columns: 12, gap: md) {
cell span: 8 {
component Input label: "Search"
}
cell span: 4 align: end {
component Button text: "Create"
}
}
PropertyTypeDefaultDescription
columnsnumber12Number of columns in grid
gapstringmdSpacing between cells
PropertyTypeDefaultDescription
spannumber12Columns the cell occupies
alignstringstartCell alignment (start, center, end)

Responsive Dashboard:

layout grid(columns: 12, gap: md) {
cell span: 3 {
component Stat title: "Total Users" value: "1,234"
}
cell span: 3 {
component Stat title: "Active" value: "890"
}
cell span: 3 {
component Stat title: "Inactive" value: "344"
}
cell span: 3 {
component Stat title: "Pending" value: "100"
}
}

Sidebar + Content:

layout grid(columns: 12, gap: md) {
cell span: 3 {
component SidebarMenu items: "Dashboard,Users,Settings"
}
cell span: 9 {
layout stack(gap: md) {
component Heading text: "Main Content"
component Text content: "Dashboard content goes here"
}
}
}

Search + Results:

layout grid(columns: 12, gap: md) {
cell span: 8 {
component Input label: "Search" placeholder: "Search users..."
}
cell span: 4 align: end {
component Select label: "Status" items: "All,Active,Inactive"
}
}
component Table columns: "Name,Email,Status,Role" rows: 10

⚠️ 12-Column System: All spans reference a 12-column grid for consistency

⚠️ Gap vs Padding: Grid gap handles spacing between cells; cells have 0px padding by default

⚠️ Wrapping: Cells don’t wrap automatically; plan your layout accordingly


Two-panel layout with fixed sidebar and flexible main content area.

Create sidebar navigation layouts. Ideal for admin dashboards and application shells.

layout split(sidebar: 260, gap: md) {
layout stack {
component SidebarMenu items: "Home,Users,Settings"
}
layout stack {
// Main content here
}
}
PropertyTypeDefaultDescription
sidebarnumberrequiredWidth of left panel (px)
gapstringmdSpacing between panels

Split requires exactly 2 children, both typically stack layouts:

  1. Left panel: Usually sidebar navigation
  2. Right panel: Main content area

Admin Dashboard:

layout split(sidebar: 260, gap: md) {
layout stack(padding: lg) {
component Topbar title: "Dashboard"
component SidebarMenu items: "Dashboard,Users,Products,Analytics" active: 0
}
layout stack(padding: lg) {
component Heading text: "Dashboard"
layout grid(columns: 12, gap: md) {
cell span: 6 {
component Stat title: "Total Users" value: "1,234"
}
cell span: 6 {
component Stat title: "Revenue" value: "$89,012"
}
}
}
}

Content Management System:

layout split(sidebar: 280, gap: lg) {
layout stack(gap: md, padding: md) {
component Heading text: "CMS"
component SidebarMenu items: "Pages,Posts,Media,Settings" active: 1
}
layout stack(gap: md, padding: lg) {
component Breadcrumbs items: "Content,Posts"
component Table columns: "Title,Author,Date,Status" rows: 8
}
}

⚠️ Exactly 2 Children: Split requires exactly 2 child layouts

⚠️ Fixed Sidebar: Left panel has fixed width; right panel is flexible

⚠️ Width Values: Use pixel values for sidebar property (e.g., 260, 300, 280)


Single-child container with automatic padding and border styling.

Group related content with visual separation. Ideal for creating sectioned content areas.

layout panel(padding: md) {
component Text content: "Panel content"
}

Or with nested stack:

layout panel(padding: lg) {
layout stack(gap: md) {
component Heading text: "Panel Title"
component Text content: "Panel content"
}
}
PropertyTypeDefaultDescription
paddingstringmdInternal padding
backgroundstringwhiteBackground color

Single Component Panel:

layout panel(padding: md) {
component Text content: "Important information goes here"
}

Grouped Content:

layout panel(padding: lg) {
layout stack(gap: md) {
component Heading text: "User Information"
component Text content: "Name: John Doe"
component Text content: "Email: john@example.com"
component Text content: "Role: Administrator"
}
}

Form Section:

layout panel(padding: lg) {
layout stack(gap: md) {
component Heading text: "Contact Details"
component Input label: "Email"
component Input label: "Phone"
component Input label: "Address"
}
}

⚠️ Single Child Only: Panel accepts only one child element (stack, grid, component, or card)

⚠️ Auto Border: Panel automatically renders with gray border and background


Flexible vertical container for grouping related content with automatic styling.

Create self-contained content cards. Ideal for product displays, user profiles, and article previews.

layout card(padding: lg, gap: md, radius: md, border: true) {
component Image type: square height: 250
component Heading text: "Card Title"
component Text content: "Card description"
component Button text: "Action"
}
PropertyTypeOptionsDefaultDescription
paddingstringxs, sm, md, lg, xlmdInternal padding
gapstringxs, sm, md, lg, xlmdSpacing between children
radiusstringnone, sm, md, lgmdCorner radius
borderbooleantrue, falsetrueShow border
  • none: 0px
  • sm: 2px
  • md: 4px
  • lg: 8px

Product Card:

layout card(padding: md, gap: md, radius: lg, border: true) {
component Image type: square height: 200
component Heading text: "Premium Laptop"
component Text content: "High-performance with latest specs"
component Badge text: "In Stock" variant: success
layout stack(direction: horizontal, gap: sm, align: justify) {
component Button text: "Buy" variant: primary block: true
component Button text: "Details" variant: secondary
}
}

User Profile Card:

layout card(padding: lg, gap: md, radius: md) {
component Heading text: "John Doe"
component Text content: "Senior Software Engineer"
component Text content: "john@example.com"
component Divider
layout stack(direction: horizontal, gap: sm) {
component Button text: "Message"
component Button text: "Connect"
}
}

Blog Post Card:

layout card(padding: md, gap: md, radius: md, border: true) {
component Image type: landscape height: 180
component Heading text: "Getting Started with Wire-DSL"
component Text content: "Learn how to create interactive wireframes with Wire-DSL in 5 minutes"
component Badge text: "Tutorial"
component Button text: "Read More" block: true
}

⚠️ Automatic Stacking: Children stack vertically automatically

⚠️ Dynamic Height: Card height adjusts based on content

⚠️ Image Aspect Ratio: Images within cards maintain proper aspect ratios


Tabbed content container. Pairs with component Tabs to create a full tabbed interface.

component Tabs items: "Profile,Settings,Billing" initialActive: 0 tabsId: mainTabs
layout tabs(id: mainTabs) {
tab {
component Heading text: "Profile"
component Input label: "Full name"
}
tab {
component Heading text: "Settings"
component Toggle label: "Notifications"
}
tab {
component Heading text: "Billing"
component Table columns: "Date,Amount" rows: 4
}
}
PropertyTypeRequiredDescription
ididentifierYesLinks to component Tabs tabsId. Must be unique within the screen.
activenumberNoInitial active tab index (default: 0)

⚠️ id is required: Must match the tabsId on the paired component Tabs.

⚠️ tab is a keyword: tab { } is special syntax only valid inside layout tabs. It is not a component.

⚠️ Order defines index: First tab = index 0, second = index 1, etc.


Modal dialog overlay. Accepts child layouts inside body and footer sections.

layout modal(id: confirmDialog, title: "Confirm", closable: true) {
body {
component Text text: "Are you sure?"
}
footer {
component Button text: "Cancel" onClick: hide(self)
component Button text: "Confirm" variant: primary onClick: hide(self)
}
}
component Button text: "Open Modal" onClick: show(confirmDialog)
PropertyTypeRequiredDescription
ididentifierNoFor show/hide/toggle targeting
titlestringNoHeader text. Omit for a header-less modal.
visiblebooleanNoInitial visibility (default: true). When false, modal is not rendered and doesn’t occupy space.
closablebooleanNoShow close button (default: true). Requires title.
sizeenumNosm (380px) | md (520px) | lg (720px) (default: md)
onCloseactionNoFired when close button is clicked
  • body { } — main content area
  • footer { } — action area (buttons)

Without sections, direct children go into the content area (implicit mode).

⚠️ Overlay positioning: Modals float above all content regardless of DSL tree position.

⚠️ visible: false: Hidden modal doesn’t render and doesn’t affect sibling layout.


In addition to built-in containers, you can define reusable layout shells:

define Layout "screen_default" {
layout split(sidebar: prop_sidebar) {
component SidebarMenu
items: "Home,Users,Reports"
active: prop_active
component Children
}
}

Usage:

screen Main {
layout screen_default(sidebar: 220, active: 1) {
layout stack(gap: md) {
component Heading text: "Dashboard"
}
}
}

Rules:

  • define Layout name must match ^[a-z][a-z0-9_]*$
  • body must contain a single root layout
  • body must contain exactly one component Children
  • each invocation must provide exactly one child block
  • component Children is invalid outside define Layout

prop_* bindings in layout params/properties are resolved from invocation args. Missing required args are semantic errors; missing optional args are omitted with warnings.


✅ Use Stack for sequential content
✅ Use Grid for responsive multi-column layouts
✅ Use Split for navigation + content pattern
✅ Use Panel for grouped content sections
✅ Use Card for self-contained items
✅ Limit nesting depth to 3-4 levels
✅ Use consistent spacing with style tokens

❌ Don’t nest the same layout type excessively
❌ Don’t leave containers empty
❌ Don’t use absolute positioning
❌ Don’t mix text and components at same level
❌ Don’t ignore responsive design patterns