Write a native app the way you write a web page.

Rux is a pure-Rust UI language: familiar template / style / script sections and literal CSS, laid out by a real flexbox and grid engine and painted on the GPU. No browser. No webview. No JavaScript.

Early and experimental (0.x) · MIT · desktop today, mobile next

A Rux window: a gradient card with a heading, a text field bound to it, a button with a live counter, and a row of pill-shaped tags.

examples/showcase.rux, running in a native window

The whole app, in one file

That window is this file, all of it. No layout widgets, no JSX, no .slint DSL, no JavaScript. <template> says what the content is, <style> is literal CSS that says where it goes and how it looks, <script> holds the state.

<template>
  <screen class="app">
    <view class="card">
      <text class="eyebrow">RUX</text>
      <text class="title">Hello, {{ name }}</text>

      <input class="field" r-model="name" placeholder="your name" />

      <view class="row">
        <button class="btn" @tap="taps = taps + 1">
          <text class="btn-label">Tap me</text>
        </button>
        <text class="count">{{ taps }}</text>
      </view>

      <view class="tags">
        <view class="tag" r-for="t in tags">
          <text class="tag-label">{{ t }}</text>
        </view>
      </view>
    </view>
  </screen>
</template>

<style>
  .app  { display: flex; justify-content: center; padding: 28px; background: #181825; }
  .card {
    display: flex;
    flex-direction: column;
    gap: 14px;
    width: 100%;
    padding: 24px;
    background: linear-gradient(160deg, #313244, #1e1e2e);
    border-radius: 16px;
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.45);
  }
  .title { color: #cdd6f4; font-size: 28px; font-weight: 700; }
  .btn   { padding: 10px 18px; background: #89b4fa; border-radius: 10px; cursor: pointer; }
  .count { color: #a6e3a1; font-size: 28px; font-weight: 700; }
  .tags  { display: flex; flex-wrap: wrap; gap: 8px; }
  .tag   { padding: 5px 11px; background: #45475a; border-radius: 999px; }
</style>

<script>
  let name = signal("world");
  let taps = signal(0);
  let tags = signal(["no browser", "no JS", "literal CSS", "hot reload"]);
</script>

Type in the field and the heading changes as you type. r-model binds it to the signal, and {{ name }} reads it back. Tap the button and the count moves. Edit the file with the window open and it reloads live.

The full file is examples/showcase.rux (the CSS above is trimmed a little for length).

Run it

git clone https://github.com/Aine-dickson/rux
cd rux
cargo run -p rux-cli -- examples/showcase.rux

That opens a real native window. There is no browser and no webview anywhere in the stack: taffy lays it out, parley shapes the text, vello paints it on the GPU, winit holds the window.

What works today

The exact honored-CSS set lives in the reference, the authoritative "what actually works" doc. What's missing is written down just as plainly: CSS custom properties, @media, and pseudo-classes (:hover, :focus, :checked) are the biggest gaps. There's also no true inline text-flow, text editing lacks word-wise movement and triple-click selection, and the reactive tier has no effects or computed values.

Rux is 0.x and experimental. It is not trying to replace Flutter, React Native, or Slint. Those are mature, and if you need to ship an app this quarter you should use one of them. Rux exists to find out whether one specific corner (CSS-authored, Rust-native, no DSL, no JS) is a nicer place to build. The honest version of that argument, including where Rux isn't novel, is here.

Read on