Pure JavaScript CSS layout engine implementing flexbox and box model without DOM dependencies
npx @tessl/cli install tessl/npm-css-layout@1.1.0CSS Layout is a pure JavaScript implementation of CSS layout algorithms including flexbox and the box model. It provides a standalone layout engine that operates without DOM dependencies, making it ideal for native applications, server-side rendering, and any environment where CSS-style layout computation is needed without browser dependencies.
npm install css-layoutconst computeLayout = require("css-layout");For AMD/RequireJS:
define(["css-layout"], function(computeLayout) {
// use computeLayout
});For browser globals:
<script src="css-layout.js"></script>
<script>
// computeLayout is available globally
</script>const computeLayout = require("css-layout");
// Create a node tree with styles
const nodeTree = {
style: {
width: 100,
height: 100,
padding: 10,
flexDirection: "column"
},
children: [
{
style: {
height: 50,
margin: 5,
alignSelf: "stretch"
}
},
{
style: {
flex: 1,
marginTop: 10
}
}
]
};
// Compute layout - modifies the tree in-place
computeLayout(nodeTree);
// Access computed layout information
console.log(nodeTree.layout);
// {
// width: 100,
// height: 100,
// top: 0,
// left: 0,
// right: 0,
// bottom: 0,
// direction: "ltr"
// }
console.log(nodeTree.children[0].layout);
// {
// width: 80,
// height: 50,
// top: 10,
// left: 10,
// right: 10,
// bottom: 40,
// direction: "ltr"
// }Computes layout for a node tree and writes positioning information back to the nodes in-place.
/**
* Computes CSS layout for a node tree using flexbox and box model rules
* @param {LayoutNode} node - Root node of the tree to layout
* @returns {void} - Modifies the input node tree in-place
*/
function computeLayout(node);Usage Example:
const computeLayout = require("css-layout");
const node = {
style: { width: 200, height: 200, padding: 20 },
children: [
{ style: { flex: 1, margin: 10 } },
{ style: { height: 50, marginTop: 10 } }
]
};
computeLayout(node);
// Node tree now contains computed layout propertiesThe primary data structure representing a node in the layout tree.
/**
* @typedef {Object} LayoutNode
* @property {StyleProperties} [style] - Style properties defining the visual characteristics
* @property {LayoutNode[]} [children] - Array of child nodes
* @property {LayoutResult} [layout] - Computed layout information (populated after computeLayout)
* @property {function(number): {width: number, height: number}} [measure] - Custom measurement function for text content
* @property {boolean} [isDirty] - Internal: marks node as needing layout recalculation
* @property {Object} [lastLayout] - Internal: caches previous layout for optimization
* @property {number} [lineIndex] - Internal: line index for wrapped flex items
*/Style properties supported by the css-layout engine. These correspond exactly to the supported attributes documented in the original README.
/**
* @typedef {Object} StyleProperties
* @property {number} [width] - Fixed width in layout units (positive number)
* @property {number} [height] - Fixed height in layout units (positive number)
* @property {number} [minWidth] - Minimum width constraint (positive number)
* @property {number} [minHeight] - Minimum height constraint (positive number)
* @property {number} [maxWidth] - Maximum width constraint (positive number)
* @property {number} [maxHeight] - Maximum height constraint (positive number)
* @property {number} [left] - Left position offset (number)
* @property {number} [right] - Right position offset (number)
* @property {number} [top] - Top position offset (number)
* @property {number} [bottom] - Bottom position offset (number)
* @property {number} [margin] - Uniform margin on all sides (number)
* @property {number} [marginLeft] - Left margin (number)
* @property {number} [marginRight] - Right margin (number)
* @property {number} [marginTop] - Top margin (number)
* @property {number} [marginBottom] - Bottom margin (number)
* @property {number} [padding] - Uniform padding on all sides (positive number)
* @property {number} [paddingLeft] - Left padding (positive number)
* @property {number} [paddingRight] - Right padding (positive number)
* @property {number} [paddingTop] - Top padding (positive number)
* @property {number} [paddingBottom] - Bottom padding (positive number)
* @property {number} [borderWidth] - Uniform border width on all sides (positive number)
* @property {number} [borderLeftWidth] - Left border width (positive number)
* @property {number} [borderRightWidth] - Right border width (positive number)
* @property {number} [borderTopWidth] - Top border width (positive number)
* @property {number} [borderBottomWidth] - Bottom border width (positive number)
* @property {'column'|'row'|'column-reverse'|'row-reverse'} [flexDirection] - Flex direction: 'column' (default), 'row', 'column-reverse', or 'row-reverse'
* @property {'flex-start'|'center'|'flex-end'|'space-between'|'space-around'} [justifyContent] - Main axis alignment
* @property {'flex-start'|'center'|'flex-end'|'stretch'} [alignItems] - Cross axis alignment (default: 'stretch')
* @property {'flex-start'|'center'|'flex-end'|'stretch'} [alignSelf] - Individual cross axis alignment
* @property {number} [flex] - Flex grow/shrink factor (positive number)
* @property {'wrap'|'nowrap'} [flexWrap] - Flex wrap behavior (default: 'nowrap')
* @property {'relative'|'absolute'} [position] - Position type (default: 'relative')
*/The computed layout information populated by the layout engine.
/**
* @typedef {Object} LayoutResult
* @property {number} width - Computed width of the element
* @property {number} height - Computed height of the element
* @property {number} top - Distance from parent's top edge
* @property {number} left - Distance from parent's left edge
* @property {number} right - Distance from parent's right edge
* @property {number} bottom - Distance from parent's bottom edge
* @property {'ltr'|'rtl'} direction - Resolved direction
*/CSS Layout uses sensible defaults optimized for flexbox-based layouts:
These defaults work like CSS with box-sizing: border-box and display: flex applied to all elements.
For layouts involving text content, provide a measure function on nodes:
const nodeWithText = {
style: { padding: 10 },
measure: function(width) {
// Measure text content given available width
// Return actual dimensions needed
return { width: 150, height: 20 };
},
children: []
};
computeLayout(nodeWithText);The measure function is called during layout to determine the intrinsic size of content that cannot be determined from style properties alone. It receives the available width and should return an object with width and height properties.
CSS Layout is designed for maximum portability:
This makes it ideal for: