B4A Library [B4X] B4XYogaLayout - The Power of CSS Flexbox in B4X

Hi Fam

Download

It is with pleasure to give you B4XYogaLayout b4xlib.

Yoga is an embeddable layout system used in popular UI frameworks like React Native. Yoga itself is not a UI framework, and does not do any drawing itself. Yoga's only responsibility is determining the size and position of boxes.

Yoga brings the power of CSS Flexbox to multiple platforms, natively calculating layout coordinates so you don't have to manually calculate X and Y positions. Because it is highly portable, it can theoretically be wrapped for use within our beloved B4X ecosystem (B4A, B4i, and B4J) to create responsive, web-standard UIs seamlessly.
Imagine defining a flexible, responsive UI once and letting Yoga do the heavy lifting to figure out exactly where each view should sit on any screen size.

1773229812908.png


Here is the code that produces this layout. We are using panels to demonstrate, however you can use any b4xview.


B4X:
Sub Class_Globals
    Private Root As B4XView 'ignore
    Private xui As XUI 'ignore
    Private fc As YogaContainer
    Private Styles As Map
End Sub
Public Sub Initialize As Object
    Return Me
End Sub
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    CreateStyles
    fc.Initialize(Root, Me, False)
    fc.SetStyle(Styles.Get("screen"))
    BuildUI
    fc.CalculateAndApply
End Sub
Private Sub CreateStyles
    Styles = YogaStyle.StyleSheet(Array( _
        "screen", CreateMap( _
            "flexDirection": "column", _
            "justifyContent": "center", _
            "alignItems": "center", _
            "backgroundColor": "#f8fafc", _
            "flex": 1), _
        _
        "shell", CreateMap( _
            "width": 250, _
            "height": 475, _
            "padding": 10, _
            "backgroundColor": "#e2e8f0", _
            "borderRadius": 18), _
        _
        "content", CreateMap( _
            "flex": 1, _
            "rowGap": 10), _
        _
        "headerBlock", CreateMap( _
            "height": 60, _
            "backgroundColor": "#0f172a", _
            "borderRadius": 12), _
        _
        "bodyBlockOne", CreateMap( _
            "flex": 1, _
            "marginInline": 10, _
            "backgroundColor": "#38bdf8", _
            "borderRadius": 14), _
        _
        "bodyBlockTwo", CreateMap( _
            "flex": 2, _
            "marginInline": 10, _
            "backgroundColor": "#818cf8", _
            "borderRadius": 14), _
        _
        "bottomBar", CreateMap( _
            "position": "absolute", _
            "width": "100%", _
            "bottom": 0, _
            "height": 64, _
            "flexDirection": "row", _
            "alignItems": "center", _
            "justifyContent": "space-around", _
            "backgroundColor": "#ffffff", _
            "borderRadius": 16), _
        _
        "navOne", CreateMap( _
            "width": 40, _
            "height": 40, _
            "backgroundColor": "#ef4444", _
            "borderRadius": 12), _
        _
        "navTwo", CreateMap( _
            "width": 40, _
            "height": 40, _
            "backgroundColor": "#f59e0b", _
            "borderRadius": 12), _
        _
        "navThree", CreateMap( _
            "width": 40, _
            "height": 40, _
            "backgroundColor": "#22c55e", _
            "borderRadius": 12), _
        _
        "navFour", CreateMap( _
            "width": 40, _
            "height": 40, _
            "backgroundColor": "#3b82f6", _
            "borderRadius": 12) _
    ))
End Sub
Private Sub BuildUI
    Dim shell As YogaView = fc.CreatePanel("shell", Styles.Get("shell"))
    Dim content As YogaView = fc.CreatePanel("content", Styles.Get("content"))
    Dim headerBlock As YogaView = fc.CreatePanel("headerBlock", Styles.Get("headerBlock"))
    Dim bodyBlockOne As YogaView = fc.CreatePanel("bodyBlockOne", Styles.Get("bodyBlockOne"))
    Dim bodyBlockTwo As YogaView = fc.CreatePanel("bodyBlockTwo", Styles.Get("bodyBlockTwo"))
    Dim bottomBar As YogaView = fc.CreatePanel("bottomBar", Styles.Get("bottomBar"))
    Dim navOne As YogaView = fc.CreatePanel("navOne", Styles.Get("navOne"))
    Dim navTwo As YogaView = fc.CreatePanel("navTwo", Styles.Get("navTwo"))
    Dim navThree As YogaView = fc.CreatePanel("navThree", Styles.Get("navThree"))
    Dim navFour As YogaView = fc.CreatePanel("navFour", Styles.Get("navFour"))
    
    fc.Root.AddChild(shell)
    shell.AddChild(content)
    content.AddChild(headerBlock)
    content.AddChild(bodyBlockOne)
    content.AddChild(bodyBlockTwo)
    content.AddChild(bottomBar)
    bottomBar.AddChild(navOne)
    bottomBar.AddChild(navTwo)
    bottomBar.AddChild(navThree)
    bottomBar.AddChild(navFour)
End Sub
Private Sub B4XPage_Resize(Width As Int, Height As Int)
    fc.Resize(Width, Height)
End Sub

All the demo examples from the Yoga Page have been reproduced in the attached source code.

You can also get more information on how this works from, https://www.yogalayout.dev/





When you run and install the code, you are provided with a screen to explore each of the outputs of each of the layouts created.

1773237273830.png
 
Last edited:

Mashiane

Expert
Licensed User
Longtime User
Settings Demo

1773231464880.png


B4X:
Sub Class_Globals
    Private Root As B4XView 'ignore
    Private xui As XUI 'ignore
        
    ' The YogaContainer manages our entire layout
    Private fc As YogaContainer
    
    ' ============================================================
    ' STYLES — Defined like React Native's StyleSheet.create()
    ' ============================================================
    Private Styles As Map
End Sub
'You can add more parameters here.
Public Sub Initialize As Object
    Return Me
End Sub
'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    'load the layout to Root
        
    ' ── Step 1: Define all styles (like StyleSheet.create) ──
    CreateStyles
    
    ' ── Step 2: Initialize YogaContainer with root panel ──
    fc.Initialize(Root, Me, False)
    fc.SetStyle(Styles.Get("container"))
    
    ' ── Step 3: Build the view tree ──
    BuildUI
    
    ' ── Step 4: Calculate layout and apply ──
    fc.CalculateAndApply
    
    ' Debug: Print the layout tree
    fc.DebugTree
End Sub

' ============================================================
' STYLES — All styles defined in one place
' Mirror of React Native's StyleSheet.create()
' ============================================================
Private Sub CreateStyles
    Styles = YogaStyle.StyleSheet(Array( _
        "container", CreateMap( _
            "flexDirection": "column", _
            "padding": 16, _
            "backgroundColor": "#0f172a", _
            "flex": 1), _
        _
        "header", CreateMap( _
            "flexDirection": "column", _
            "paddingBottom": 20, _
            "paddingTop": 8), _
        _
        "title", CreateMap( _
            "fontSize": 28, _
            "fontWeight": "bold", _
            "color": "#ffffff", _
            "marginBottom": 4), _
        _
        "subtitle", CreateMap( _
            "fontSize": 14, _
            "color": "#94a3b8"), _
        _
        "card", CreateMap( _
            "flexDirection": "column", _
            "backgroundColor": "#1e293b", _
            "borderRadius": 12, _
            "padding": 16, _
            "marginBottom": 12), _
        _
        "cardTitle", CreateMap( _
            "fontSize": 12, _
            "fontWeight": "bold", _
            "color": "#64748b", _
            "marginBottom": 12, _
            "textTransform": "uppercase"), _
        _
        "cardRow", CreateMap( _
            "flexDirection": "row", _
            "justifyContent": "space-between", _
            "alignItems": "center", _
            "paddingVertical": 8), _
        _
        "cardLabel", CreateMap( _
            "fontSize": 16, _
            "color": "#e2e8f0"), _
        _
        "cardValue", CreateMap( _
            "fontSize": 14, _
            "color": "#94a3b8"), _
        _
        "cardValueActive", CreateMap( _
            "fontSize": 14, _
            "color": "#818cf8"), _
        _
        "divider", CreateMap( _
            "height": 1, _
            "backgroundColor": "#334155"), _
        _
        "button", CreateMap( _
            "flexDirection": "row", _
            "justifyContent": "center", _
            "alignItems": "center", _
            "backgroundColor": "#6366f1", _
            "borderRadius": 12, _
            "height": 52, _
            "marginTop": 8), _
        _
        "buttonText", CreateMap( _
            "fontSize": 16, _
            "fontWeight": "bold", _
            "color": "#ffffff"), _
        _
        "dangerButton", CreateMap( _
            "flexDirection": "row", _
            "justifyContent": "center", _
            "alignItems": "center", _
            "backgroundColor": "transparent", _
            "borderRadius": 12, _
            "borderWidth": 1, _
            "borderColor": "#ef4444", _
            "height": 48, _
            "marginTop": 8), _
        _
        "dangerText", CreateMap( _
            "fontSize": 14, _
            "color": "#ef4444") _
    ))
End Sub
' ============================================================
' BUILD UI — Construct the view tree
' This mirrors React Native's render() / JSX
' ============================================================
Private Sub BuildUI
    
    ' ── Header Section ──
    Dim header As YogaView = fc.CreatePanel("header", Styles.Get("header"))
    Dim title As YogaView = fc.CreateLabel("title", "Settings", Styles.Get("title"))
    Dim subtitle As YogaView = fc.CreateLabel("subtitle", "Manage your preferences", Styles.Get("subtitle"))
    
    fc.Root.AddChild(header)
    header.AddChild(title)
    header.AddChild(subtitle)
    
    ' ── Appearance Card ──
    Dim card1 As YogaView = fc.CreatePanel("card1", Styles.Get("card"))
    Dim card1Title As YogaView = fc.CreateLabel("card1Title", "Appearance", Styles.Get("cardTitle"))
    
    fc.Root.AddChild(card1)
    card1.AddChild(card1Title)
    
    ' Dark Mode row
    AddSettingsRow(card1, "darkMode", "Dark Mode", "On", True)
    AddDivider(card1, "div1")
    ' Font Size row
    AddSettingsRow(card1, "fontSize", "Font Size", "Medium", False)
    AddDivider(card1, "div2")
    ' Language row
    AddSettingsRow(card1, "language", "Language", "English", False)
    
    ' ── Notifications Card ──
    Dim card2 As YogaView = fc.CreatePanel("card2", Styles.Get("card"))
    Dim card2Title As YogaView = fc.CreateLabel("card2Title", "Notifications", Styles.Get("cardTitle"))
    
    fc.Root.AddChild(card2)
    card2.AddChild(card2Title)
    
    ' Push Notifications row
    AddSettingsRow(card2, "push", "Push Notifications", "On", True)
    AddDivider(card2, "div3")
    ' Email row
    AddSettingsRow(card2, "email", "Email Notifications", "Off", False)
    AddDivider(card2, "div4")
    ' Sound row
    AddSettingsRow(card2, "sound", "Sound", "Default", False)
    
    ' ── Spacer (pushes buttons to bottom) ──
    Dim spacer As YogaView = fc.CreateSpacer("spacer", 1)
    fc.Root.AddChild(spacer)
    
    ' ── Save Button ──
    Dim saveBtn As YogaView = fc.CreatePanel("saveBtn", Styles.Get("button"))
    Dim saveBtnText As YogaView = fc.CreateLabel("saveBtnText", "Save Changes", Styles.Get("buttonText"))
    
    fc.Root.AddChild(saveBtn)
    saveBtn.AddChild(saveBtnText)
    
    ' ── Logout Button ──
    Dim logoutBtn As YogaView = fc.CreatePanel("logoutBtn", Styles.Get("dangerButton"))
    Dim logoutBtnText As YogaView = fc.CreateLabel("logoutBtnText", "Log Out", Styles.Get("dangerText"))
    
    fc.Root.AddChild(logoutBtn)
    logoutBtn.AddChild(logoutBtnText)
End Sub
' ============================================================
' HELPER: Add a settings row (label + value)
' ============================================================
Private Sub AddSettingsRow(parent As YogaView, tag As String, label As String, value As String, isActive As Boolean)
    Dim row As YogaView = fc.CreatePanel(tag & "Row", Styles.Get("cardRow"))
    Dim rowLabel As YogaView = fc.CreateLabel(tag & "Label", label, Styles.Get("cardLabel"))
    
    ' Use active style if flag is set (like RN conditional style)
    Dim valueStyle As Map
    If isActive Then
        valueStyle = Styles.Get("cardValueActive")
    Else
        valueStyle = Styles.Get("cardValue")
    End If
    Dim rowValue As YogaView = fc.CreateLabel(tag & "Value", value, valueStyle)
    
    parent.AddChild(row)
    row.AddChild(rowLabel)
    row.AddChild(rowValue)
End Sub
' ============================================================
' HELPER: Add a divider line
' ============================================================
Private Sub AddDivider(parent As YogaView, tag As String)
    Dim divider As YogaView = fc.CreatePanel(tag, Styles.Get("divider"))
    parent.AddChild(divider)
End Sub
' ============================================================
' RESIZE — Re-run layout when screen size changes
' ============================================================
Private Sub B4XPage_Resize(Width As Int, Height As Int)
    fc.Resize(Width, Height)
End Sub
' ============================================================
' EVENT HANDLERS — Click events for buttons
' ============================================================
' To handle clicks, add click events to the B4XViews:
' 
' In BuildUI, after creating the save button:
'   Dim savePnl As Panel = saveBtn.View
'   savePnl.SetOnClickListener(Me, "SaveBtn_Click")
'
' Private Sub SaveBtn_Click
'   Log("Save clicked!")
'   ' Update styles dynamically:
'   Dim fv As YogaView = fc.FindByTag("saveBtn")
'   fv.UpdateStyle(CreateMap("backgroundColor": "#4f46e5"))
' End Sub
' ============================================================
' DYNAMIC STYLE UPDATE EXAMPLE
' ============================================================
' To toggle dark mode value dynamically:
'
' Private Sub ToggleDarkMode
'   Dim valueFv As YogaView = fc.FindByTag("darkModeValue")
'   Dim currentText As String = valueFv.View.Text
'   
'   If currentText = "On" Then
'       valueFv.View.Text = "Off"
'       valueFv.UpdateStyle(Styles.Get("cardValue"))  ' inactive style
'   Else
'       valueFv.View.Text = "On"
'       valueFv.UpdateStyle(Styles.Get("cardValueActive"))  ' active style
'   End If
'   
'   ' Re-run layout if text size changed
'   fc.CalculateAndApply
' End Sub
 

Mashiane

Expert
Licensed User
Longtime User
Align Content Demo

Source: https://www.yogalayout.dev/docs/styling/align-content

1773232664121.png



B4X:
Sub Class_Globals
    Private Root As B4XView 'ignore
    Private xui As XUI 'ignore
    Private fc As YogaContainer
    Private Styles As Map
End Sub
Public Sub Initialize As Object
    Return Me
End Sub
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    CreateStyles
    fc.Initialize(Root, Me, False)
    fc.SetStyle(Styles.Get("screen"))
    BuildUI
    fc.CalculateAndApply
End Sub
Private Sub CreateStyles
    Styles = YogaStyle.StyleSheet(Array( _
        "screen", CreateMap( _
            "flexDirection": "column", _
            "justifyContent": "center", _
            "alignItems": "center", _
            "backgroundColor": "#f8fafc", _
            "flex": 1), _
        _
        "wrapDemo", CreateMap( _
            "width": 200, _
            "height": 250, _
            "padding": 10, _
            "alignContent": "flex-start", _
            "flexWrap": "wrap", _
            "backgroundColor": "#e2e8f0", _
            "borderRadius": 12), _
        _
        "boxRed", CreateMap( _
            "margin": 5, _
            "width": 50, _
            "height": 50, _
            "backgroundColor": "#ef4444"), _
        _
        "boxGreen", CreateMap( _
            "margin": 5, _
            "width": 50, _
            "height": 50, _
            "backgroundColor": "#22c55e"), _
        _
        "boxBlue", CreateMap( _
            "margin": 5, _
            "width": 50, _
            "height": 50, _
            "backgroundColor": "#3b82f6"), _
        _
        "boxAmber", CreateMap( _
            "margin": 5, _
            "width": 50, _
            "height": 50, _
            "backgroundColor": "#f59e0b") _
    ))
End Sub
Private Sub BuildUI
    Dim wrapDemo As YogaView = fc.CreatePanel("wrapDemo", Styles.Get("wrapDemo"))
    Dim boxRed As YogaView = fc.CreatePanel("boxRed", Styles.Get("boxRed"))
    Dim boxGreen As YogaView = fc.CreatePanel("boxGreen", Styles.Get("boxGreen"))
    Dim boxBlue As YogaView = fc.CreatePanel("boxBlue", Styles.Get("boxBlue"))
    Dim boxAmber As YogaView = fc.CreatePanel("boxAmber", Styles.Get("boxAmber"))
    
    fc.Root.AddChild(wrapDemo)
    wrapDemo.AddChild(boxRed)
    wrapDemo.AddChild(boxGreen)
    wrapDemo.AddChild(boxBlue)
    wrapDemo.AddChild(boxAmber)
End Sub
Private Sub B4XPage_Resize(Width As Int, Height As Int)
    fc.Resize(Width, Height)
End Sub
 

Mashiane

Expert
Licensed User
Longtime User
Min Max / Height Width

Source: https://www.yogalayout.dev/docs/styling/min-max-width-height

1773233050748.png


B4X:
Sub Class_Globals
    Private Root As B4XView 'ignore
    Private xui As XUI 'ignore
    Private fc As YogaContainer
    Private Styles As Map
End Sub
Public Sub Initialize As Object
    Return Me
End Sub
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    CreateStyles
    fc.Initialize(Root, Me, False)
    fc.SetStyle(Styles.Get("screen"))
    BuildUI
    fc.CalculateAndApply
End Sub
Private Sub CreateStyles
    Styles = YogaStyle.StyleSheet(Array( _
        "screen", CreateMap( _
            "flexDirection": "column", _
            "justifyContent": "center", _
            "alignItems": "center", _
            "backgroundColor": "#f8fafc", _
            "flex": 1), _
        _
        "shell", CreateMap( _
            "width": 200, _
            "height": 250, _
            "padding": 10, _
            "backgroundColor": "#e2e8f0", _
            "borderRadius": 16), _
        _
        "boxOne", CreateMap( _
            "margin": 5, _
            "height": 25, _
            "backgroundColor": "#0ea5e9", _
            "borderRadius": 8), _
        _
        "boxTwo", CreateMap( _
            "margin": 5, _
            "height": 100, _
            "maxHeight": 25, _
            "backgroundColor": "#f97316", _
            "borderRadius": 8), _
        _
        "boxThree", CreateMap( _
            "margin": 5, _
            "height": 25, _
            "minHeight": 50, _
            "backgroundColor": "#22c55e", _
            "borderRadius": 8), _
        _
        "boxFour", CreateMap( _
            "margin": 5, _
            "height": 25, _
            "maxWidth": 25, _
            "backgroundColor": "#a855f7", _
            "borderRadius": 8), _
        _
        "boxFive", CreateMap( _
            "margin": 5, _
            "height": 25, _
            "width": 25, _
            "minWidth": 50, _
            "backgroundColor": "#ef4444", _
            "borderRadius": 8) _
    ))
End Sub
Private Sub BuildUI
    Dim shell As YogaView = fc.CreatePanel("shell", Styles.Get("shell"))
    Dim boxOne As YogaView = fc.CreatePanel("boxOne", Styles.Get("boxOne"))
    Dim boxTwo As YogaView = fc.CreatePanel("boxTwo", Styles.Get("boxTwo"))
    Dim boxThree As YogaView = fc.CreatePanel("boxThree", Styles.Get("boxThree"))
    Dim boxFour As YogaView = fc.CreatePanel("boxFour", Styles.Get("boxFour"))
    Dim boxFive As YogaView = fc.CreatePanel("boxFive", Styles.Get("boxFive"))
    
    fc.Root.AddChild(shell)
    shell.AddChild(boxOne)
    shell.AddChild(boxTwo)
    shell.AddChild(boxThree)
    shell.AddChild(boxFour)
    shell.AddChild(boxFive)
End Sub
Private Sub B4XPage_Resize(Width As Int, Height As Int)
    fc.Resize(Width, Height)
End Sub
 

Sandman

Expert
Licensed User
Longtime User
This looks interesting, thanks for sharing.

Do you match Meta Yoga features exactly or is this a subset of what they provide? The reason I ask is because your top example differ from the example they have at https://www.yogalayout.dev/
 

Mashiane

Expert
Licensed User
Longtime User
This looks interesting, thanks for sharing.
Thanks, appreciated.

Do you match Meta Yoga features exactly or is this a subset of what they provide?

All features in the provided examples are covered and are showcased in each case in the source code.

1774388491943.png



The reason I ask is because your top example differ from the example they have at...

Yes, they are slightly different, that was by choice for my example.

Theirs (kinda boring)

1774388113661.png


Mine (tweaked a few settings on the demo example to suit my taste)

1774388152290.png


If the issue is, you cannot reproduce their example as is, lets see with your example code what is missed, I would be glad to fix any bug discovered.
 

Sandman

Expert
Licensed User
Longtime User
All features in the provided examples are covered and are showcased in each case in the source code.
Sorry, I can't fully parse this. Are you saying your match the functionality of Meta Yoga completely? (Let's assume there are no bugs in your code.)

Yes, they are slightly different, that was by choice for my example.
I understand. From my perspective it is unfortunate, as it would have a value to look at the code at https://www.yogalayout.dev/ and see exactly how you did that using your implementation. When I see your example, which looks simplified compared to theirs, my suspicion directly goes to "his implementation is probably simplifed and can't fully do what Meta does". (Which might be entirely fine, but then it would be good to know about it.)
 

Mashiane

Expert
Licensed User
Longtime User
I can't fully parse this.
In the yoga website, Styling tab, there are code examples that detail how each functionality of the Meta LayoutEngine works. These give the HTML like structure of each example.

1774509995514.png


So what I did was to cover all the functionality in those examples as per attached source code.

1774510028735.png


Do you now understand?

Unfortunately currently this is limited to those examples and nothing else, it would be nice to have other real world examples tested, perhaps based on real apps. I have not done that as yet.

If you happen to have more intensive examples we could test, please provide, it would be a good thing to test how this layout engine will fair.

PS: I will reproduce the example you have highlighted so that a new one has 100% parity.
 

Sandman

Expert
Licensed User
Longtime User
currently this is limited to those examples and nothing else
So it's a subset, got it. No complaints from me at all, I just wanted to understand the feature parity. I do find it interesting to be able to specify layouts in a more cross-platform way so I will take a closer look at this in a while. Are there known limitations that you can share? For instance, would this work with custom views?

it would be nice to have other real world examples tested, perhaps based on real apps. I have not done that as yet.
I agree, it would be nice to hear what other people make of it and how useful it is for them.

If you happen to have more intensive examples we could test, please provide, it would be a good thing to test how this layout engine will fair.
My most typical layout is very basic, but now and then we're getting things like nested layouts. Like when using the items in a xCustomListView - would Yoga even work for a case like that?

PS: I will reproduce the example you have highlighted so that a new one has 100% parity.
That's very kind of you, thank you.
 
Top