No description
Find a file
Karl Wahlström fc9658902e
Some checks are pending
CI / check (push) Waiting to run
Big refactoring using ai.
2026-07-15 18:40:07 +02:00
.agents/skills/qtml Added Textarea component. 2026-07-15 17:10:20 +02:00
.github/workflows Added licence and stuff. 2026-07-14 17:44:58 +02:00
examples Updated counter example. 2026-07-15 00:49:37 +02:00
qtml_build Big refactoring using ai. 2026-07-15 18:40:07 +02:00
qtml_core Big refactoring using ai. 2026-07-15 18:40:07 +02:00
qtml_lsp Big refactoring using ai. 2026-07-15 18:40:07 +02:00
qtml_macro Added variables inside rust conditions. 2026-07-15 12:29:12 +02:00
qtml_tailwind Added utility blocks. 2026-07-15 15:27:16 +02:00
.gitignore First big commit. 2026-07-12 16:36:23 +02:00
AGENTS.md Added qtml skill and updated AGENTS.md. 2026-07-15 14:12:28 +02:00
Cargo.lock Added tailwind production building. 2026-07-14 16:45:49 +02:00
Cargo.toml Added tailwind production building. 2026-07-14 16:45:49 +02:00
LICENSE Added licence and stuff. 2026-07-14 17:44:58 +02:00
README.md Added list components. 2026-07-15 14:07:40 +02:00

QTML

QTML is a QML-inspired template language for compiling server-rendered Rust templates into HTML with Tailwind classes.

The primary entry point is the render_qtml! macro from qtml_macro.

use qtml_macro::render_qtml;

let page = render_qtml!("ui/dashboard.qtml");

Format source with qtml_core before writing it back to disk:

use qtml_core::compiler::format_document;

let formatted = format_document(source)?;
Column {
    spacing: 3
    horizontal_alignment: center

    Text {
        text: "Welcome, {user_name}"
        size: 2xl
        weight: bold
    }

    Button {
        text: "Save"
        background: blue-600
        color: white
        padding: 3
        border_radius: md
    }
}

Imports always name the component or style namespace they introduce:

import "components/page_card.qtml" as PageCard
import style "styles/theme.qtml" as theme

Imports are local to the file that declares them. Components and style namespaces must be imported in every file that uses them; imports are not re-exported to parents or siblings.

Imported components declare inputs with property and read them with $:

property title: "Untitled"

Box {
    Text { text: $title }
}

Transition utilities use normal properties:

Button {
    transition: all
    duration: 100
}

Use Rust boolean expressions to conditionally render QTML content. Branches support else if and else:

if user.is_admin {
    Text { text: "Admin access" }
} else if user.is_signed_in {
    Text { text: "Standard access" }
} else {
    Text { text: "Sign in" }
}

Use // for comments. Comments may appear anywhere whitespace is allowed:

// A reusable page heading.
Header1 {
    text: "Dashboard" // Rendered as escaped text.
}

For page structure, QTML provides Header, Footer, Section, Article, Nav, Aside, Text, and Span alongside Page, Box, Grid, Column, and Row. Use OrderedList, UnorderedList, and ListItem for lists; use Details and Summary for disclosures. Heading components run from Header1 through Header6.

Style modules use the same .qtml extension and declare reusable values with var:

// ui/styles/theme.qtml
var background: #f8fafc

dark {
    var background: #0f172a
}

Templates import a style module by its filename namespace:

import style "styles/theme.qtml" as theme

Page { background: $theme.background }

Generate the style definitions once in the application shell with render_qtml_styles!("ui/styles/theme.qtml"). Dark overrides set CSS custom properties under the dark class. Use a dark { ... } block in a component for a local Tailwind dark-mode override.

See examples/counter, examples/task_app, and examples/theme for working applications.

Tailwind production builds

QTML generates Tailwind utility classes during Rust compilation, so production Tailwind builds need an extracted class list. Scan each template entrypoint before running Tailwind:

cargo run -p qtml_tailwind -- scan ui/home.qtml --output target/qtml-tailwind.txt

Add the generated file to Tailwind's sources. For Tailwind v4:

@import "tailwindcss";
@source "../target/qtml-tailwind.txt";

For Tailwind v3, include ./target/qtml-tailwind.txt in content. The scanner follows imported QTML components and includes both branches of conditional classes.

License

QTML is available under the MIT License.