Skip to content
Back to skills

Qt Figma Component Generation

ASecurity

Extract component metadata from a Figma design system and generate production-ready QML controls. Use this skill whenever someone wants to turn Figma components into QML files — whether they say "generate components from Figma", "create QML controls based on a design system", "convert Figma components to QML", "build the component library", "extract button/input/checkbox from Figma", or anything similar. Requires design-tokens.json and QML design system singletons to already exist (from the t...

  • 458 stars
  • 0 votes
  • 0 copies
  • 7 views
  • Added August 31, 2026
ai-agentsgonodeexpressgitapi

Works with

  • claude code
  • cursor
  • cli
  • api
  • mcp

Security analysis

A100/100

Pro scans all 20 files and shows the line behind each finding

Scanned August 31, 2026

npx -y skills add TheQtCompanyRnD/agent-skills --skill qt-figma-component-generation --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Qt Figma Component Generation?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Qt Figma Component Generation
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/theqtcompanyrnd-qt-figma-component-generation/badge)](https://www.skillsdirectory.com/skills/theqtcompanyrnd-qt-figma-component-generation)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: qt-figma-component-generation
description: >
  Extract component metadata from a Figma design system and generate production-ready QML controls. Use this skill whenever someone wants to turn Figma components into QML files — whether they say "generate components from Figma", "create QML controls based on a design system", "convert Figma components to QML", "build the component library", "extract button/input/checkbox from Figma", or anything similar. Requires design-tokens.json and QML design system singletons to already exist (from the token extraction skill). Uses Figma MCP to inspect components one at a time and maps variants, states, sizing, and token usage to idiomatic Qt Quick Controls 2 patterns. Trigger this skill at the component generation step of any QML design-system workflow.
license: LicenseRef-Qt-Commercial OR BSD-3-Clause
compatibility: Works with Claude Code, Codex, and GitHub Copilot. Requires Figma MCP and design-tokens.json from qt-figma-token-extraction.
metadata:
  author: qt-ai-skills
  version: "1.0"
  qt-version: "6.x"
  category: process
---

# Figma Component Generation Skill

This skill reads component definitions from a Figma file via MCP and generates production-ready QML control files that consume the design-system singletons produced by the token-extraction skill.

---

## Prerequisites

Before generating any components, confirm all of the following exist in the project:

1. **`design-tokens.json`** — the merged token file from the token-extraction skill
2. **QML design system singletons** — `Primitives.qml`, `Theme.qml`, `Spacing.qml`, `FontInterface.qml` in a `design-system/` folder

If either is missing, stop and run the token-extraction skill first (`qt-figma-token-extraction`).

**Verify Figma MCP is connected** — confirm that `get_metadata` and `get_design_context` are available in the tool list. If not, tell the user:
> "The Figma MCP connector isn't connected yet. Connect it via your MCP configuration, then come back and we can start."

Do not proceed until the connection is confirmed.

---

## Step 1 — Component Discovery

Use `get_metadata` to fetch the file structure and identify which pages and frames contain components:

```
Tool: get_metadata
Input: { "fileKey": "<file key>" }
```

From the response, note all pages and frames or component sets named as component groups (e.g. "Button", "Text Field", "Checkbox").

Ask the user:
> "I can see the following component groups in the Figma file: [list]. Which ones should I generate QML files for? Or should I do all of them?"

Build a single component inventory table and keep it updated throughout the entire workflow — do not create a second table later:

| Figma component name | Node ID | QML file | Status |
|---|---|---|---|
| Button | 67:139 | Button.qml | pending |
| Text Field | ... | TextField.qml | pending |

Status values: `pending` → `extracting` → `mapping` → `done` / `blocked`

---

## Step 2 — Pattern Selection

Ask the user to choose an implementation pattern before reading any assets or writing any code. If the **AskUserQuestion tool** is available, use it:

```
tool: AskUserQuestion
question: "Which code style should the generated components use?"
options:
  - "Pattern A — Inline (self-contained file, all state logic inside the component)"
  - "Pattern B — Style singleton (ComponentStyle.qml + Component.qml, supports multiple themes)"
  - "I'm not sure — recommend one"
```

If the tool is not available (e.g. in Claude Code, Codex, or Copilot), ask the question in plain text and wait for a reply before proceeding.

If the user selects "I'm not sure", recommend **Pattern A** for most projects — it is simpler, self-contained, and easier to debug. Only recommend Pattern B if the project already has a `Qt.Themes` / `TokenInterface` layer or needs to support multiple swappable themes.

> **Pattern B uses integer enum variants, not strings.** Pattern A uses `property string variant: "primary"`. Pattern B uses `property int typeVariant: ButtonStyle.TypeVariant.Primary`. Do not mix the two approaches — pick one and use it consistently throughout all components.

---

## Step 3 — Prepare the Chosen Pattern

Before extracting or writing anything, make sure the structure for the chosen pattern is in front of you. Pattern B is read from the bundled assets; Pattern A is built from the inline snippets in Step 5.

### Pattern A assets — `references/`

This folder contains Figma-verified Pattern A controls. Each is a self-contained file where all state logic lives inside the component using conditional expressions on `readonly property` values.

| Reference file | Output file | Demonstrates |
|---|---|---|
| `references/Button.qml` | `Button.qml` | AbstractButton, multi-variant state machine, size helpers, accent family mapping |
| `references/TextField.qml` | `TextField.qml` | TextInput wrapped in ColumnLayout, label + error + helper text, clear button |
| `references/Checkbox.qml` | `Checkbox.qml` | CheckBox indicator, Canvas tick mark, indeterminate state |
| `references/Toggle.qml` | `Toggle.qml` | Switch track + animated thumb, NumberAnimation |
| `references/Select.qml` | `Select.qml` | Custom Item with Popup, ListView delegate, chevron |

**Read the file that most closely matches the component being generated before writing any code.** If a QML coding skill (`qt-development-skills:qt-qml`) is available, use it while writing so the output follows idiomatic Qt 6 patterns.

### Pattern B assets — `assets/qt-controls/`

This folder contains QML pairs from a production Qt controls library. Each component is split across two files:

- `Button.qml` — component logic, layout, base type, public API
- `ButtonStyle.qml` — `pragma Singleton` defining typed `component` objects for each state and size variant

**Read the asset pair for the component you are about to generate — before writing any code.** The generated file must follow the reference asset's structure, property ordering, and pattern choices. If the output deviates from the reference in a way that cannot be justified by the specific Figma component, ask yourself why and correct it. Do not invent a different structure when a reference exists.

Core pairs to read first (read the pair that matches the component being generated):
- `Button.qml` + `ButtonStyle.qml`
- `CheckBox.qml` + `CheckBoxStyle.qml`
- `ComboBox.qml` + `ComboBoxStyle.qml`
- `Switch.qml` + `SwitchStyle.qml`
- `TextField.qml` + `TextFieldStyle.qml`

---

## Step 4 — Per-Component Extraction

For each component in the inventory, extract its specification via MCP.

> **Always call `get_design_context` on an individual main component node — NOT the parent component set node.** Component sets return oversized JSON mixing all variants. Inspect the default/base variant first, then representative variants (Hover, Pressed, Disabled) individually.

```
Tool: get_design_context
Input: { "fileKey": "<key>", "nodeId": "<individual component node id>" }
```

If individual node IDs are not known yet, call `get_design_context` on the parent frame and scan for child component nodes, then re-call on each.

### What to extract per component

- **Variants / props** — Figma variant properties and allowed values → QML `property` declarations
- **States** — Default, Hover, Pressed, Disabled, Focus, Error → conditional expressions on `readonly property` values
- **Sizing** — height, padding (H + V), gap, font size, font weight, corner radius
- **Color tokens** — which semantic token appears in each state; record exact Figma name and resolved value from `design-tokens.json`
- **Typography** — font family, size, weight, line height per text element
- **Border** — stroke width, color token, which states it appears in
- **Icon / slot** — whether the component has an icon slot, its size, left/right/both position

Record all extracted data in a scratch note before writing any code.

---

## Step 5 — Figma → QML Mapping

> **Before writing any token reference, open `Theme.qml`, `Primitives.qml`, `Spacing.qml`, and `FontInterface.qml` and read the actual property names.** Do not copy token names from the reference assets — the project's token naming convention may differ from the examples. Every token name you write in a component must exist in the project's singletons.

### Base type selection

| Figma component | QML base type |
|---|---|
| Button (any style) | `AbstractButton` (from `QtQuick.Controls`) |
| Checkbox | `CheckBox` (from `QtQuick.Controls.Basic`) |
| Radio button | `RadioButton` (from `QtQuick.Controls.Basic`) |
| Toggle / switch | `Switch` (from `QtQuick.Controls.Basic`) |
| Text input / field | `ColumnLayout` wrapping a `Rectangle` + `TextInput` |
| Text area (multiline) | `ScrollView` wrapping `TextArea` (from `QtQuick.Controls.Basic`) — no reference asset yet; follow the TextField pattern but add `wrapMode: TextArea.Wrap` and remove fixed height |
| Select / dropdown | Custom `Item` with a `Popup` |
| Slider | `Slider` (from `QtQuick.Controls.Basic`) |
| Tab bar | `TabBar` + `TabButton` |
| Progress bar | `ProgressBar` (from `QtQuick.Controls.Basic`) |
| Spinner / spin box | `SpinBox` (from `QtQuick.Controls.Basic`) |
| Card / container | `Rectangle` or plain `Item` |
| Divider | `Rectangle` (1 px, fillWidth) |
| Badge | `Rectangle` wrapping a `Text` |
| Tooltip | `ToolTip` (from `QtQuick.Controls.Basic`) |

### Variant → property pattern (Pattern A)

```qml
property string variant: "primary"   // primary | secondary | ghost | tertiary | danger
property string size:    "medium"    // small | medium | large  (sm | md | lg accepted)
```

### Variant → enum pattern (Pattern B)

```qml
// Use integer enums, not strings — do not mix with Pattern A string variants
property int typeVariant: ButtonStyle.TypeVariant.Primary
```

### State → conditional expression pattern

```qml
readonly property color _bg: {
    if (!enabled) return Theme.background_muted
    return pressed ? Theme.accent_subtle
         : hovered ? Theme.accent_muted
         :            Theme.accent_default
}
```

### Icon slot pattern

```qml
// Icon slot — rendered via icon font glyph in a Text item
property string iconGlyph:     ""
property int    iconLayoutDir: Qt.LeftToRight   // Qt.LeftToRight | Qt.RightToLeft
                                                 // controls which side the icon appears on

contentItem: RowLayout {
    layoutDirection: root.iconLayoutDir
    spacing:         root._iconGap
    Text {
        text:        root.iconGlyph
        font.family: FontInterface.iconFont.name
        visible:     root.iconGlyph !== ""
    }
    Text {
        id:   _label
        text: root.label
        // ... font properties
    }
}
```

### Sizing — tokens first, literals as fallback

Check `Spacing.qml` and `FontInterface.qml` first. Only use a literal value when no token covers the dimension, and add a `// TODO: add to Spacing.qml` comment.

### Focus ring pattern

Focus rings apply only to `Control`-based components (`AbstractButton`, `CheckBox`, `Switch`, `Slider`, etc.). Text Field (`ColumnLayout` root) and Select (`Item` root) are not `Control` subclasses — use `activeFocus` and a fixed radius for those.

```qml
// For Control-based components (AbstractButton, CheckBox, Switch …)
Rectangle {
    anchors { fill: parent; margins: -2 }
    radius:       parent.radius + 2          // only valid when parent is a Rectangle
    color:        "transparent"
    border.color: Theme.stroke_focus         // use a token — never a literal color
    border.width: 2                          // TODO: promote to Spacing token if available
    visible:      root.visualFocus           // Control property — gives keyboard-only focus ring
}

// For non-Control roots (ColumnLayout, Item) — use activeFocus and fixed radius
Rectangle {
    anchors { fill: parent; margins: -2 }
    radius:       4                          // TODO: use Spacing token
    color:        "transparent"
    border.color: Theme.stroke_focus
    border.width: 2
    visible:      root.activeFocus
}
```

### Color animation pattern

Add `Behavior` blocks only on color properties that animate during interaction (hover, press). Skip them for the disabled state — a snap, not a fade, is usually correct there.

```qml
// On the Rectangle or contentItem that holds the interactive color:
Behavior on color        { ColorAnimation { duration: Theme.duration_fast } }
Behavior on border.color { ColorAnimation { duration: Theme.duration_fast } }
// If no duration token exists yet: duration: 100 — add a TODO to promote it
```

### Cursor pattern

```qml
HoverHandler { cursorShape: root.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor }
```

---

## Step 6 — Write the QML File

Place each component in the project's `components/` folder. Use PascalCase matching the Figma component name (`Button.qml`, `TextField.qml`, etc.).

### File header

```qml
// ComponentName.qml — [Project] Design System — [component description]
// Maps to Figma: [file name] → [component name] (node [id])
//
// Figma variants (inspected via MCP, [date]):
//   Prop1: "value1" | "value2"
//   Prop2: "valueA" | "valueB"
// States: Default | Hover | Pressed | Disabled [| Error | Focus]
// Sizes:  "small" | "medium" | "large"
//
// Usage:
//   import MyProject
//   ComponentName { prop: "value"; onAction: doThing() }
```

### Public API section

```qml
// ── Public API ────────────────────────────────────────────────────────────
property string variant: "primary"
property string size:    "medium"
property string label:   "Button"

// ── Private helpers ───────────────────────────────────────────────────────
readonly property bool  _isSmall: size === "small" || size === "sm"
readonly property color _bg: ...
```

### Missing values

```qml
// TODO: add Spacing.buttonIconGapSm to Spacing.qml (Figma: 0px for small buttons)
readonly property int _iconGap: _isSmall ? 0 : Spacing.x4
```

After generating all components, summarise the full TODO list for the user.

---

## Step 7 — Post-Generation Review

After all components are written, run a consistency pass:

- Every `readonly property color` referencing a theme token must use a name that **actually exists** in `Theme.qml` or `Primitives.qml`. Flag any that don't.
- Every numeric size must come from `Spacing.qml` or `FontInterface.qml`. Collect any literals that should be promoted to tokens.
- Every interactive component has a focus ring.
- Every interactive component has a `HoverHandler` with a cursor shape.
- File headers document the node IDs that were inspected.
- Update the inventory table from Step 1 — mark all components `done` or `blocked`.

Present a brief summary to the user:
- Components generated (count and names)
- Components skipped or blocked (with reason)
- Full TODO list: tokens that need to be added to the design-system singletons
- Recommended next step: add components to `qt_add_qml_module QML_FILES` in CMakeLists.txt and smoke-test in a gallery

---

## Common Pitfalls

**Inspecting the component set instead of a main component.** Component sets return all variants stacked. Always drill down to an individual component node.

**Using token names from reference assets instead of the project.** The reference assets use example token names that may not match the project's singletons. Always read the actual singleton files first.

**Hardcoding a value that exists in a token.** Check `Spacing.qml` and `FontInterface.qml` before writing any literal number.

**Missing the indeterminate / partial state.** Checkbox and radio buttons often have a third state. Always check for `Qt.PartiallyChecked`.

**Not zeroing out AbstractButton default padding.** `AbstractButton` and other `Control` subclasses have default padding that inflates rendered height. Zero them explicitly when managing geometry yourself.

**Forgetting `Behavior` blocks.** Add `Behavior on color { ColorAnimation { duration: Theme.duration_fast } }` on color properties that animate during interaction (hover, press). Use a token for duration — not a hardcoded `100`. Skip Behaviors on the disabled state; a snap transition is usually correct there.

**Popup z-ordering.** `Popup` items need `parent: Overlay.overlay` if clipped by a parent container.

**Mixing Pattern A strings and Pattern B enums.** Choose one variant approach and use it consistently across all components.

Files in this skill

  • README.md4.2 KB
  • SKILL.md16.3 KB
  • assets/qt-controls/BadgeLabel.qml4 KB
  • assets/qt-controls/BadgeLabelStyle.qml3.4 KB
  • assets/qt-controls/BadgeNotification.qml3.8 KB
  • assets/qt-controls/BadgeNotificationStyle.qml2.7 KB
  • assets/qt-controls/Button.qml5.6 KB
  • assets/qt-controls/ButtonStyle.qml8.2 KB
  • assets/qt-controls/Card.qml22.6 KB
  • assets/qt-controls/CardStyle.qml4.4 KB
  • assets/qt-controls/CheckBox.qml4.2 KB
  • assets/qt-controls/CheckBoxStyle.qml5.4 KB
  • assets/qt-controls/ComboBox.qml7.1 KB
  • assets/qt-controls/ComboBoxStyle.qml6.8 KB
  • assets/qt-controls/Dialog.qml4.2 KB
  • assets/qt-controls/DialogButtonBox.qml2 KB
  • assets/qt-controls/DialogButtonBoxStyle.qml1.2 KB
  • assets/qt-controls/DialogStyle.qml2.1 KB
  • assets/qt-controls/IconButton.qml4 KB
  • assets/qt-controls/IconButtonStyle.qml4.6 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.