Auto Draft

Created on September 03, 2019, Last modified on June 08, 2021

Sometimes absolute positioning is not enough. You may want to position elements stacked horizontally or vertically, or wrap items when there are too much to fit in an area. This process is called layouting and Lightning has a simple solution for it.

Lightning does not contain the bloated HTML CSS toolbox. Instead, it only contains the useful Flexbox layout methodology. The Lightning layout engine has some smart performance optimizations. However it is still rather cpu-intensive so is best used for situations in which the flex items do not often change dimensions.

Flexbox allows for dynamically stacked items of rows and columns. In Lightning, the flex and flexItem properties define the flex-related layout settings. Notice that it's also possible to nest flex containers, making them both flex containers and flex items.

    MyFlexBox:{ x: 50, y: 50, w: 250, flex:{ direction: 'row', padding: 20, wrap: true }, rect: true,
        MyFlexItem: { w: 50, h: 100, flexItem:{ margin: 10 }, rect: true, color: 0xFF797979 },
        MyFlexBoxItemWithFlexItemChildren:{flex: {direction: 'column', padding: 20 }, flexItem: { margin: 10 }, rect: true,
            children: [
                { text: {text: "line 1"} },
                { text: {text: "line 2"} }

Instead of repeating everything there is to know about Flexbox, we advice you to have a look at this Flexbox Guide.

Differences with CSS Flexbox

Lightning's version of flexbox is almost completely identical to the one you'll find in Chrome and Firefox, though we made some intentional exceptions for improving consistency and usability. The tables below describe the major differences between the two.

Flex container

Specified in the element property: flex: {}.

LightningtypeCSSDifference (if any)
wrapbooleanflex-wraponly wrap (true) and nowrap (false) are supported
alignItemsstringalign-itemsbaseline not supported
paddingnumber (px)padding

Flex item

Specified in the element property: flexItem: {}.

LightningtypeCSSDifference (if any)
shrinknumberflex-shrinkNon-containers are not shrinkable by default
orderNot supported
flex-basisNot supported (behaves as set to 'auto')
minWidthnumber (px)min-width
minHeightnumber (px)min-height
maxWidthnumber (px)max-width
maxHeightnumber (px)max-height
marginnumber (px)margin

Disable flex item

All children of a flex container are by default flex items. However, it is possible to make one of the children behave as an absolutely positioned element by specifying flexItem: false. In this case, the item will not affect the flex layout and will be positioned absolutely.

Invisible elements

When an element is invisible (visible: false) it will be ignored in the flex layout. In contrast, when an element is fully transparent (alpha: 0) it will take space in the layout as normal.

Auto sizing

A flex container can have a fixed w and/or h specified. This may affect the positioning of the items within it. It is also possible to not specify it (or set it to 0). In that case the flex container will always fit to the contents on those axes. This is deliberately inconsistent to HTML CSS, where it depends on the axis (horizontal axis will usually fallback to the parent width), which feels as odd behavior.


When enabling flexbox, the x and y properties act as relative positions to the positions calculated by the layout engine.

Final coordinates

After the layout has been done, you can find the element's coordinates and size by using the finalX, finalY, finalW, finalH element properties.

To ensure a full stage layout (without rendering), you can use this.stage.update(). After that the finalX etc. properties will contain the correct value.

Live demo

Below an visualization of how flexbox works when you change the width of the flex-wrapper.

class FlexExample extends lng.Application {
    static _template() {
        return {
            Wrapper:{ x: 50, y: 50, w: 250,  flex:{ direction: 'row', padding: 20, wrap: true }, rect: true, color: 0xFF2D2D2D, paddingLeft: 200,
                Item1: { w: 50, h: 100, flexItem:{ margin: 10 }, rect: true, color: 0xFF797979 },
                Item2: { w: 50, h: 100, flexItem:{ margin: 10 }, rect: true, color: 0xFFA7A7A7 },
                Item3: { w: 50, h: 100, flexItem:{ margin: 10, alignSelf: 'stretch', grow: 1, maxWidth: 190, maxHeight: 100 }, rect: true, color: 0xFFD3D3D3 },
                Item4: { w: 90, h: 50, flexItem:{ margin: 10, alignSelf: 'stretch', grow: 1, maxWidth: 230, maxHeight: 100 }, rect: true, color: 0xFF74B4A7 },
                Sub: {flex: {direction: 'column', padding: 20}, flexItem: { margin: 10, alignSelf: 'stretch', grow: 1, maxWidth: 380 }, rect: true, color: 0xFF486f67,
                    children: [
                        { text: {text: "line 1"} },
                        { text: {text: "line 2"} },
                        { text: {text: "line 3"} },
                        { text: {text: "line 4"} }
         this._myFlexAnimation = this.tag('Wrapper').animation({
             duration: 4, repeat: -1, stopMethod: 'immediate',
             actions: [{ p: 'w', v: { 0: 250, 0.5: 430, 1: 250 } }]

const options = {stage: {w: window.innerWidth, h: window.innerHeight, useImageWorker: false}};
const app = new FlexExample(options);

Give feedback

Rating - 3 / 5. . Reviews - 2

No votes so far! Be the first to rate this post.

Go To Top