@bedrock-core/flexbox
Beta Status: Active development. Breaking changes may occur until 1.0.0. Pin exact versions for stability.
Flexbox layout engine for Minecraft Bedrock UI. Computes absolute texel positions and sizes for a tree of layout nodes using a CSS-compatible flexbox algorithm, targeting the Bedrock pocket screen (320×210 texels) as the canonical reference.
Installation
This package is typically installed as a dependency of @bedrock-core/ui:
yarn add @bedrock-core/uiOr directly:
yarn add @bedrock-core/flexboxQuick Start
import { createNode, computeLayout } from '@bedrock-core/flexbox';
// Build a layout tree
const root = createNode({
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
padding: 10,
});
const sidebar = createNode({ width: 80 });
const content = createNode({ flex: 1 });
root.children.push(sidebar, content);
// Compute layout (defaults to 320×210 pocket screen)
computeLayout(root);
// Read resolved absolute texel values
console.log(sidebar.layout); // { x, y, width, height, zIndex }
console.log(content.layout); // { x, y, width, height, zIndex }API
createNode(style?, children?)
Create a layout node with an optional style and pre-populated children.
const node = createNode(
{ flexDirection: 'column', padding: 5 },
[createNode({ height: 20 }), createNode({ flex: 1 })],
);The layout field is zeroed on creation and is filled only after computeLayout() runs.
computeLayout(root, refWidth?, refHeight?)
Compute absolute texel positions and sizes for the entire tree.
// Default: pocket screen (320×210)
computeLayout(root);
// Custom reference dimensions
computeLayout(root, 376, 250); // desktop screenAfter this call every node.layout holds absolute texel values:
x,y— top-left corner from screen origin (0, 0)width,height— dimensions in texelszIndex— resolved z-order (inherits from parent when not explicitly set)
The algorithm uses a 3-pass BFS approach:
- Pass 1 — build level-order list and parent map
- Pass 2 (bottom-up, 3 iterations) — resolve content-driven and explicit sizes; handles percent padding convergence
- Pass 3 (top-down) — resolve percent sizes, distribute flex grow/shrink, position children
CANONICAL_SCREEN / SCREEN
Reference screen dimensions in texels:
import { CANONICAL_SCREEN, SCREEN } from '@bedrock-core/flexbox';
SCREEN.POCKET // { width: 320, height: 210 }
SCREEN.DESKTOP // { width: 376, height: 250 }
CANONICAL_SCREEN // same as SCREEN.POCKETSupported Properties
Display & Positioning
| Property | Type | Default | Description |
|---|---|---|---|
display |
'flex' | 'none' |
'flex' |
Hide node and all descendants when 'none' |
position |
'relative' | 'absolute' |
'relative' |
Absolute nodes are removed from flow |
Sizing
Sizes are texels (integer) or percent strings ("50%") relative to the parent container.
| Property | Type | Default | Description |
|---|---|---|---|
width |
number | Percent |
auto | Explicit width |
height |
number | Percent |
auto | Explicit height |
minWidth |
number | Percent |
— | Minimum width constraint |
maxWidth |
number | Percent |
— | Maximum width constraint |
minHeight |
number | Percent |
— | Minimum height constraint |
maxHeight |
number | Percent |
— | Maximum height constraint |
Flex Container
| Property | Type | Default | Description |
|---|---|---|---|
flexDirection |
'row' | 'row-reverse' | 'column' | 'column-reverse' |
'column' |
Main axis direction |
wrap |
'nowrap' | 'wrap' | 'wrap-reverse' |
'nowrap' |
Multi-line wrapping |
justifyContent |
'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly' |
'flex-start' |
Main axis alignment |
alignItems |
'flex-start' | 'flex-end' | 'center' | 'stretch' |
'stretch' |
Cross axis alignment |
alignContent |
'flex-start' | 'flex-end' | 'center' | 'stretch' | 'space-between' | 'space-around' |
'stretch' |
Multi-line cross axis |
gap |
number | Percent |
0 |
Gap between items |
rowGap |
number | Percent |
0 |
Row gap override |
columnGap |
number | Percent |
0 |
Column gap override |
Flex Item
| Property | Type | Default | Description |
|---|---|---|---|
flex |
number |
— | Shorthand for flexGrow when flexGrow is not set |
flexGrow |
number |
0 |
Growth factor |
flexShrink |
number |
1 |
Shrink factor |
flexBasis |
number | Percent | 'auto' |
'auto' |
Initial main size |
alignSelf |
'auto' | AlignItems |
'auto' |
Override container's alignItems |
Spacing
Percent values resolve against the parent content-box width (all four sides for padding/margin). Gap percent resolves against the container's own content-box dimension on that axis.
| Property | Type | Default | Description |
|---|---|---|---|
padding |
number | Percent |
0 |
Inner spacing, all sides |
paddingTop/Right/Bottom/Left |
number | Percent |
0 |
Individual padding |
margin |
number | Percent |
0 |
Outer spacing, all sides |
marginTop/Right/Bottom/Left |
number | Percent |
0 |
Individual margin |
Absolute Positioning Offsets
Only applies when position: 'absolute'. Offsets are in texels relative to the parent.
| Property | Type | Description |
|---|---|---|
top |
number |
Distance from parent top |
right |
number |
Distance from parent right |
bottom |
number |
Distance from parent bottom |
left |
number |
Distance from parent left |
When both left + right are set without width, the node is stretched to fill the horizontal space. Same for top + bottom without height.
Z-order
| Property | Type | Default | Description |
|---|---|---|---|
zIndex |
number |
inherited | Z-order layer; inherits from parent when not set |
Examples
Centered content
const root = createNode({ justifyContent: 'center', alignItems: 'center' });
root.children.push(createNode({ width: 100, height: 60 }));
computeLayout(root);Sidebar layout
const root = createNode({ flexDirection: 'row' });
root.children.push(
createNode({ width: 80 }), // fixed sidebar
createNode({ flex: 1 }), // content fills remainder
);
computeLayout(root);Wrapping grid
const grid = createNode({ flexDirection: 'row', wrap: 'wrap', gap: 4 });
for (let i = 0; i < 9; i++) {
grid.children.push(createNode({ width: 100, height: 60 }));
}
computeLayout(grid);Absolute overlay
const root = createNode({});
root.children.push(
createNode({ flex: 1 }), // normal flow
createNode({ position: 'absolute', top: 0, right: 0, width: 40, height: 20 }), // overlay
);
computeLayout(root);Custom screen size
import { computeLayout, SCREEN } from '@bedrock-core/flexbox';
computeLayout(root, SCREEN.DESKTOP.width, SCREEN.DESKTOP.height);Output Format
After computeLayout(), each node exposes a layout property:
interface ComputedLayout {
x: number; // texels from screen left
y: number; // texels from screen top
width: number; // texels
height: number; // texels
zIndex: number; // resolved z-order
}All values are rounded integers.
License
MIT