When to use
Use this when you have Figma frames or components and want them turned into structured Qt Quick QML components — layouts, rectangles, text, and images — that reference a theme singleton instead of literal values. Run token extraction first so generated components stay themeable.
Not for: extracting colors/typography/spacing into a theme (see qt-figma-token-extraction), or designing a UI from scratch without a Figma source (see qt-ui-design).
Method
- Fetch the target subtree with
GET /v1/files/:key/nodes?ids=...and traverse the node tree depth-first, reading each node'stype,name,absoluteBoundingBox,layoutMode,constraints,fills,strokes,cornerRadius, andcharacters. - Choose the container. Decision point: if a frame has
layoutModeofHORIZONTALmap it toRowLayout,VERTICALmap it toColumnLayout; iflayoutModeisNONE, keep a plainItem/Rectangleand position children with anchors from theirconstraints. - Map auto-layout spacing and padding: frame
itemSpacing→ layoutspacing;paddingLeft/Right/Top/Bottom→Layout.marginson children or an outerItemwith anchored margins. - Map constraints to anchors when not using a layout:
LEFT/RIGHT/CENTER/SCALE/TOP/BOTTOM→anchors.left/right/horizontalCenter/fill/top/bottom. Decision point: never place a child under both a*Layout(viaLayout.*) and manualanchorson the same item — pick one per item. - Map visual leaf nodes.
RECTANGLE/FRAMEfills →Rectangle.color;strokes+strokeWeight→border.color/border.width;cornerRadius(orrectangleCornerRadiifor per-corner) →radius. - Map text.
TEXTnodes →Text(orLabelfrom Controls) withtext: node.characters, andfontsourced from the theme singleton typography token that matches the node's text style. - Decide component boundaries. Decision point: if a Figma node is a
COMPONENT/INSTANCEor repeats, emit a separate reusable.qmlfile withpropertyinputs (text, colors, callbacks) and setimplicitWidth/implicitHeight; otherwise inline it. - Handle images/vectors. Decision point: if the node is a
VECTOR/boolean/star shape, export SVG and use it via anImage(orIconImage); if it is a raster fill (IMAGEpaint), export a PNG/@2x and reference it withImage { source }and afillMode. - Replace every literal with a token reference (
Theme.colorSurface,Theme.spacingMd,Theme.radiusLg) resolved from the extraction step; leave aTODOonly when no matching token exists. - Set sizing from content: give components
implicitWidth/implicitHeightso parents and layouts can size them, rather than hardcodingwidth/height.
Example
// PrimaryButton.qml (from a Figma COMPONENT with auto-layout)
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import MyApp.Theme
Rectangle {
id: root
property alias text: label.text
signal clicked()
implicitWidth: content.implicitWidth + Theme.spacingMd * 2
implicitHeight: content.implicitHeight + Theme.spacingSm * 2
radius: Theme.radiusSm
color: mouse.pressed ? Theme.colorBrandPressed : Theme.colorBrandPrimary
border.width: 1
border.color: Theme.colorBrandPrimary
RowLayout { // Figma layoutMode: HORIZONTAL
id: content
anchors.centerIn: parent
spacing: Theme.spacingXs
Image { // exported SVG vector
source: "qrc:/icons/plus.svg"
sourceSize: Qt.size(16, 16)
}
Label { // Figma TEXT node
id: label
font: Theme.titleLarge
color: Theme.colorOnBrand
}
}
MouseArea { id: mouse; anchors.fill: parent; onClicked: root.clicked() }
}
Pitfalls
- Anchors and Layout on one item. Mixing
anchors.*withLayout.*on the same child yields undefined geometry and console warnings. One positioning system per item. - Hardcoded width/height. Copying Figma
absoluteBoundingBoxas fixedwidth/heightbreaks inside layouts and on resize. PreferimplicitWidth/implicitHeightplusLayout.fillWidth. - Baking literal colors. Emitting raw hex instead of
Theme.*defeats the token pipeline; every fill/stroke should resolve to a token. - Per-corner radius lost.
cornerRadiusis a single value; Figma per-corner radii (rectangleCornerRadii) need Qt's per-cornertopLeftRadius/etc. (Qt 6.7+) or a shape, not oneradius. - Text elision and wrapping dropped. Figma text boxes clip/auto-resize; set
Text.wrapMode/elide/maximumLineCountdeliberately or long strings overflow. - Vector as font glyph. Don't approximate Figma vectors with characters; export SVG and render via
Image/IconImagefor fidelity and crisp scaling.
Output format
components/
PrimaryButton.qml # reusable COMPONENT → property-driven .qml
Card.qml
<Frame>.qml # one file per Figma component/instance
assets/
icons/*.svg # exported vectors
images/*@2x.png # exported rasters
qmldir # module registration for generated components
// each generated component follows this skeleton
import QtQuick
import QtQuick.Layouts
import MyApp.Theme
Item {
// public API: property aliases + signals
// layout: Row/Column/GridLayout OR anchored Item
// leaves: Rectangle (fill/border/radius), Text/Label (theme font), Image (svg/png)
// sizing: implicitWidth / implicitHeight
}
Reference
- Node traversal:
GET /v1/files/:key/nodes?ids=...returnsdocumentsubtrees; recursechildren. Relevant fields:type(FRAME,COMPONENT,INSTANCE,RECTANGLE,TEXT,VECTOR,GROUP),layoutMode,itemSpacing,padding*,constraints,fills,strokes,strokeWeight,cornerRadius/rectangleCornerRadii,characters,style. - Auto-layout → Qt Quick Layouts:
HORIZONTAL→RowLayout,VERTICAL→ColumnLayout; wrap grids inGridLayout.itemSpacing→spacing; useLayout.fillWidth/Layout.fillHeight/Layout.preferredWidth/Layout.alignmenton children (import QtQuick.Layouts). - Constraints → anchors:
MIN→left/top,MAX→right/bottom,CENTER→horizontalCenter/verticalCenter,STRETCH/SCALE→anchors.fillor left+right anchors. Anchors and Layouts are mutually exclusive per item. - Fills/strokes/radius: solid
fills[0]→Rectangle.color(convert Figma 0–1 RGBA per qt-figma-token-extraction);strokes[0]+strokeWeight→border.color/border.width;cornerRadius→radius(per-corner viatopLeftRadiusetc. in Qt 6.7+). - Text:
TEXT→Text(bare) orLabel(Controls, theme-aware). Settext,font(from theme typography token),color, and explicitwrapMode/elide. - Controls vs custom: use Qt Quick Controls (
Button,Label,TextField,Slider) for interactive/accessible widgets and style via a theme; build customRectangle+MouseAreaonly for bespoke visuals not covered by Controls. - Images/SVG:
Image { source; fillMode: Image.PreserveAspectFit; sourceSize }; SVG is supported by the built-in svg image provider; prefersourceSizeto rasterize crisply. Bundle assets via the Qt resource system (qrc:/). - Reusable components: a component is any
.qmlfile whose name is Capitalized; expose inputs withproperty/property aliasand outputs withsignal; setimplicitWidth/implicitHeightso it composes inside layouts. Register generated files withqt_add_qml_module/qmldir.