Skip to content

Layout Components

Vulpis uses a Flexbox-inspired system to arrange elements. The core building blocks for layout are Box components. These containers group other elements and control their positioning, spacing, and alignment.

Components

el.VBox (Vertical Box)

A container that arranges its children in a vertical column (top to bottom).

  • Engine Type: "vbox"
lua
el.VBox({
    style = { gap = 10 },
    children = { el.Text("Top"), el.Text("Bottom") }
})

el.HBox (Horizontal Box)

A container that arranges its children in a horizontal row (left to right).

  • Engine Type: "hbox"
lua
el.HBox({
    style = { gap = 10 },
    children = { el.Text("Left"), el.Text("Right") }
})

el.Box (Generic Box)

A generic container. By default, it acts as an hbox, but you can override the type manually if needed.

  • Default Engine Type: "hbox"
lua
-- Equivalent to HBox
el.Box({
    children = { ... }
})

Native Engine Shorthands

To keep your code concise, the Vulpis C++ engine natively supports shorthand properties for dimensions and spacing inside your style table.

The Cascading Box Model

Spacing shorthands (padding and margin) use a smart Cascading Fallback system native to the C++ engine. The engine will prioritize specific sides, then axes, and finally the general value.

For example, if you write style = { p = 20, pb = 0 }, the engine understands that Top, Left, and Right are 20, but Bottom is overridden to 0.

  1. Specific Side: pt, pb, pl, pr (Overrides everything else)
  2. Axis: px (Left/Right), py (Top/Bottom)
  3. All Sides: p

Supported Shorthands

Shorthand PropEquivalent Style PropertyDescription
w, hw, hWidth and height (e.g., 200 or "100%").
p, px, pypadding, paddingLeft/paddingRight, paddingTop/paddingBottomPadding across all, horizontal, or vertical axes.
pt, pb, pl, prpaddingTop, paddingBottom, paddingLeft, paddingRightSpecific padding overrides.
m, mx, mymargin, marginLeft/marginRight, marginTop/marginBottomMargin across all, horizontal, or vertical axes.
mt, mb, ml, mrmarginTop, marginBottom, marginLeft, marginRightSpecific margin overrides.
gapspacingSpace between child elements.

(Note: Colors, borders, and flexbox alignments must use their full names like BGColor, borderRadius, alignItems, etc.)

Shorthand Example:

lua
el.VBox({
    style = {
        w = "100%", h = 200, 
        BGColor = "#222222", 
        borderRadius = 10,
        justifyContent = "center", 
        alignItems = "center", 
        gap = 15,
        p = 20, pb = 0 -- 20px padding everywhere except the bottom
    },
    children = { el.Text("Item 1"), el.Text("Item 2") }
})

Complete Styling Reference

All layout components accept the following properties inside their style table.

Dimensions

PropertyTypeDescription
w, hnumber | stringWidth and height in pixels or percentages (e.g., "100%").
minWidth, maxWidthnumberMinimum and maximum width in pixels.
minHeight, maxHeightnumberMinimum and maximum height in pixels.

Alignment (Flexbox)

Control how children are distributed inside the box.

PropertyOptionsDescription
justifyContent"start", "center", "end", "space-between", "space-around", "space-evenly"Alignment along the main axis (Vertical for VBox, Horizontal for HBox).
alignItems"start", "center", "end", "stretch"Alignment along the cross axis.
flexGrownumberIf > 0, the box will grow to fill available space relative to siblings.
flexShrinknumberIf > 0, the box will shrink if space is limited.
flexWrap"nowrap", "wrap", "wrap-reverse"Controls whether children are forced onto one line or can wrap onto multiple lines.

Spacing (Box Model)

All spacing values are in pixels.

PropertyDescription
gap (or spacing)Space between child elements.
paddingPadding on all four sides.
paddingTop, paddingBottomVertical padding overrides.
paddingLeft, paddingRightHorizontal padding overrides.
marginMargin on all four sides.
marginTop, marginBottomVertical margin overrides.
marginLeft, marginRightHorizontal margin overrides.

Positioning, Visuals & Scrolling

PropertyType/OptionsDescription
BGColorstring | tableBackground color of the box.
position"relative", "absolute"Layout position strategy. Absolute elements are removed from the flow.
left, top, right, bottomnumberOffset coordinates used when position is set to "absolute".
zIndexnumberRendering order. Higher numbers draw on top of lower numbers.
opacitynumberControls transparency from 0.0 (invisible) to 1.0 (opaque).
borderRadiusnumberRounds the corners of the box's background and borders.
borderWidthnumberThickness of the border in pixels.
borderColorstring | tableColor of the border.
overflow"visible", "hidden", "scroll", "auto"Controls clipping and scrollbars. "scroll"/"auto" enables vertical and horizontal scrolling if content exceeds the container.
autoScroll"none", "bottom", "top"Automatically scrolls the container when new content is added (useful for chat boxes or logs).

Examples

1. Centered Card

A fixed-size card centered within a full-screen container.

lua
el.VBox({
    style = {
        w = "100%", 
        h = "100%",
        BGColor = "#000000",
        justifyContent = "center",
        alignItems = "center"
    },
    children = {
        el.VBox({
            style = {
                w = 300,
                h = 200,
                BGColor = "#666666",
                p = 20,
                gap = 10,
                borderRadius = 12
            },
            children = {
                el.Text("Card Title"),
                el.Text("This is some content inside the card.")
            }
        })
    }
})

2. Scrollable Navigation Bar

A simple Scrollable container with many elements

lua
function Window()
	return {
		title = "Vulpis Scrolling Demo",
		w = 800,
		h = 600,
		resizable = true,
	}
end

function App()
	local listItems = {}

	for i = 1, 50 do
		table.insert(listItems, {
			type = "vbox",
			style = {
				w = "100%",
				p = 20, -- Padding inside the item box
				marginBottom = 10, -- Space between items
				BGColor = "#2A2A35", -- Dark slate background for the item
				borderRadius = 8, -- Rounded corners
			},
			children = {
				{
					type = "text",
					text = "Scrollable Item #" .. tostring(i),
					style = {
						color = "#FFFFFF",
						fontSize = 24,
						fontWeight = "bold",
					},
				},
				{
					type = "text",
					text = "This is some description text for the item.",
					style = {
						color = "#A0A0A0",
						fontSize = 16,
						marginTop = 5,
					},
				},
			},
		})
	end

	-- Return the root Virtual DOM node
	return {
		type = "vbox",
		style = {
			w = "100%",
			h = "100%", -- Force container to bounds of the window
			BGColor = "#18181E", -- Main app background
			p = 20,
			overflow = "auto", --Enables scrolling
		},
		children = listItems,
	}
end