Python binding for Facebook Yoga layout engine
Project description
yoga-python
Python bindings for Facebook's Yoga layout engine — a cross-platform implementation of CSS Flexbox.
Yoga computes a layout tree of nodes with flexbox styles and outputs pixel-perfect positions. This package wraps the full C++ engine via pybind11, giving you the same layout behavior you get in React Native, Litho, and other Yoga-backed frameworks — directly from Python.
Installation
pip install yoga-python
Building from source requires a C++20 compiler, CMake 3.15+, and pybind11:
pip install scikit-build-core pybind11
pip install .
Quick start
from yoga import (
Node, Config, Direction, FlexDirection, Justify,
Align, Edge, YGValuePoint, YGValuePercent,
)
root = Node()
root.flex_direction = FlexDirection.Row
root.width = YGValuePoint(300)
root.height = YGValuePoint(200)
root.set_padding(Edge.All, 10)
child_a = Node()
child_a.flex_grow = 1
child_a.set_margin(Edge.Right, 10)
root.insert_child(child_a, 0)
child_b = Node()
child_b.flex_grow = 2
root.insert_child(child_b, 1)
root.calculate_layout(300, 200, Direction.LTR)
print(f"child_a: {child_a.layout_left}, {child_a.layout_top}, "
f"{child_a.layout_width}x{child_a.layout_height}")
# child_a: 10.0, 10.0, 90.0x180.0
print(f"child_b: {child_b.layout_left}, {child_b.layout_top}, "
f"{child_b.layout_width}x{child_b.layout_height}")
# child_b: 110.0, 10.0, 180.0x180.0
API overview
Node
The primary object. Create nodes, configure their styles, build a tree, then call calculate_layout.
node = Node() # default config
node = Node(config) # with explicit config
Style properties (set directly as attributes):
| Property | Type | Example |
|---|---|---|
flex_direction |
FlexDirection |
node.flex_direction = FlexDirection.Row |
justify_content |
Justify |
node.justify_content = Justify.Center |
align_items |
Align |
node.align_items = Align.Stretch |
align_self |
Align |
node.align_self = Align.FlexEnd |
align_content |
Align |
node.align_content = Align.SpaceBetween |
flex_wrap |
Wrap |
node.flex_wrap = Wrap.Wrap |
overflow |
Overflow |
node.overflow = Overflow.Hidden |
display |
Display |
node.display = Display.Flex |
position_type |
PositionType |
node.position_type = PositionType.Absolute |
flex_grow |
float |
node.flex_grow = 1.0 |
flex_shrink |
float |
node.flex_shrink = 0.0 |
flex_basis |
YGValue |
node.flex_basis = YGValuePoint(100) |
width / height |
YGValue |
node.width = YGValuePercent(50) |
min_width / max_width |
YGValue |
node.min_width = YGValuePoint(80) |
min_height / max_height |
YGValue |
node.max_height = YGValuePoint(400) |
aspect_ratio |
float |
node.aspect_ratio = 16 / 9 |
box_sizing |
BoxSizing |
node.box_sizing = BoxSizing.ContentBox |
direction |
Direction |
node.direction = Direction.LTR |
Edge-based properties (margin, padding, border, position):
node.set_margin(Edge.Left, 10) # points
node.set_margin(Edge.Top, YGValuePercent(5)) # percent
node.set_padding(Edge.All, 20)
node.set_border(Edge.Bottom, 1)
node.set_position(Edge.Left, YGValuePoint(50))
Tree manipulation:
node.insert_child(child, index)
node.remove_child(child)
node.remove_all_children()
node.set_children([child_a, child_b])
node.child_count # int
node[index] # Node (supports indexing)
Layout:
node.calculate_layout(width, height, Direction.LTR)
node.layout_left # float
node.layout_top # float
node.layout_width # float
node.layout_height # float
node.layout_direction # Direction
node.layout_margin(Edge.Left) # float
node.layout_padding(Edge.Top) # float
node.layout_border(Edge.Right) # float
Measure functions for leaf nodes with custom content sizing:
def measure(node, width, width_mode, height, height_mode):
return {"width": 100, "height": 50}
node.set_measure_func(measure)
Baseline functions for custom baseline alignment:
def baseline(node, width, height):
return height * 0.8
node.set_baseline_func(baseline)
Config
config = Config()
config.use_web_defaults = True
config.point_scale_factor = 2.0
config.errata = Errata.StretchFlexBasis
Values
YGValuePoint(100) # 100px
YGValuePercent(50) # 50%
YGValueAuto # auto
YGValueUndefined # undefined
Enums
All Yoga enums are available as Python enum types (pybind11 enums, int-convertible):
Direction, FlexDirection, Justify, Align, PositionType, Wrap, Overflow, Display, Edge, Unit, MeasureMode, Dimension, BoxSizing, Gutter, Errata, NodeType, LogLevel, ExperimentalFeature
Development
git clone https://github.com/banditburai/yoga-python.git
cd yoga-python
uv sync --dev
# Run tests
uv run pytest tests/ -v
# Lint & type checking
uv run ruff check
uv run ruff format --check
uv run pyright
Test coverage
The test suite is a 1:1 port of the Yoga C++ test suite — 822 tests covering all layout modes, edge cases, and behaviors. Tests that the C++ suite itself skips (GTEST_SKIP) are also skipped in Python.
License
MIT — same as Yoga.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file yoga_python-0.1.0.tar.gz.
File metadata
- Download URL: yoga_python-0.1.0.tar.gz
- Upload date:
- Size: 97.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3651f14b9656a1410706368f48041a6b0f3ea247bc834c94b2e7c35f60c1ee92
|
|
| MD5 |
3b374af7f236599a5cb8c87d377867ab
|
|
| BLAKE2b-256 |
5891489d217b465f6c5c067d34d1e177ed610d3dc7875e65ab94acb1cdf3811e
|
Provenance
The following attestation bundles were made for yoga_python-0.1.0.tar.gz:
Publisher:
release.yml on banditburai/yoga-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
yoga_python-0.1.0.tar.gz -
Subject digest:
3651f14b9656a1410706368f48041a6b0f3ea247bc834c94b2e7c35f60c1ee92 - Sigstore transparency entry: 1046058497
- Sigstore integration time:
-
Permalink:
banditburai/yoga-python@e8dbe35170a40a105e3ae0fe703c62f66dafab68 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/banditburai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e8dbe35170a40a105e3ae0fe703c62f66dafab68 -
Trigger Event:
push
-
Statement type:
File details
Details for the file yoga_python-0.1.0-cp312-cp312-manylinux_2_39_x86_64.whl.
File metadata
- Download URL: yoga_python-0.1.0-cp312-cp312-manylinux_2_39_x86_64.whl
- Upload date:
- Size: 310.1 kB
- Tags: CPython 3.12, manylinux: glibc 2.39+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
19f2c4bfb62e0bf5707467eff5016757092c8e999aed856d34178cda9219e4fe
|
|
| MD5 |
ed886515d8597db17da60e876d0cf39a
|
|
| BLAKE2b-256 |
043895956a83afac7a91aa9058c2aa636f4256bf4595769cc24af1c7628bc8dd
|
Provenance
The following attestation bundles were made for yoga_python-0.1.0-cp312-cp312-manylinux_2_39_x86_64.whl:
Publisher:
release.yml on banditburai/yoga-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
yoga_python-0.1.0-cp312-cp312-manylinux_2_39_x86_64.whl -
Subject digest:
19f2c4bfb62e0bf5707467eff5016757092c8e999aed856d34178cda9219e4fe - Sigstore transparency entry: 1046058668
- Sigstore integration time:
-
Permalink:
banditburai/yoga-python@e8dbe35170a40a105e3ae0fe703c62f66dafab68 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/banditburai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@e8dbe35170a40a105e3ae0fe703c62f66dafab68 -
Trigger Event:
push
-
Statement type: