Overview

Day is a Rust framework for building applications that look and behave like native applications on every platform, because they are native applications.

You write your UI once, in Rust, as a declarative tree of Pieces (what SwiftUI calls a View and Flutter calls a Widget). Each Piece is realized by a real platform widget (an NSTextField, a UILabel, a Material button, a GtkEntry, a QSlider, a XAML TextBox) through a per-platform toolkit backend. Day owns layout, reactivity, localization, accessibility policy, and scripting; the platform owns pixels, text input, scrolling physics, and assistive technology.

use day::prelude::*;

fn counter() -> AnyPiece {
    let count = Signal::new(0i64);
    column((
        label(move || format!("{} clicks", count.get())),
        button("Tap me").action(move || count.update(|c| *c += 1)),
    ))
    .spacing(12.0)
    .padding(16.0)
    .any()
}

That function produces a native label above a native button on macOS, iOS, Android, Linux, Windows, and OpenHarmony. There is no web view or bundled renderer, and no per-platform fork.

The bet

Every cross-platform approach picks something to sacrifice. Web-view shells sacrifice native behavior and memory; custom renderers sacrifice native look-and-feel and inherit the burden of reimplementing text, scrolling, and accessibility; per-platform native sacrifices the single codebase. Day’s bet is that the platform’s own widgets already do most things better than any framework can imitate, so it keeps them, and spends its effort only on the parts native toolkits are bad at sharing:

  • a layout engine that works identically everywhere while deferring to native measurement (Layout);
  • fine-grained reactivity that builds the widget tree once and binds state directly to native attributes, with no virtual tree and no diffing (Reactivity);
  • localization (Fluent), accessibility, and scripting designed into the core from the start (how they compose);
  • a CLI that builds, runs, tests, and packages for every target from one machine.

That bet has a price. Because the widgets are the platform’s own, your app looks like a Mac app on a Mac and a Material app on Android whether you want that or not, and heavy visual branding is the wrong fit. Why Day (and why not) covers the tradeoffs and when to pick something else.

The targets

A target is an (OS, toolkit) pair. One binary is compiled per target, containing only that toolkit’s backend. The AppKit build has no GTK code in it, and there’s no runtime abstraction layer to pay for.

TargetOSToolkit
macos-appkitmacOSAppKit
ios-uikitiOSUIKit
android-mdcAndroidMaterial Components / android.view
linux-gtkLinuxGTK 4 · libadwaita
linux-qtLinuxQt 6 Widgets
windows-xamlWindowsXAML (XAML Islands)
harmony-arkuiOpenHarmony / HarmonyOSArkUI
web-domWeb (any modern browser)DOM — wasm32 + semantic HTML
macos-gtk, macos-qtmacOSGTK 4, Qt 6
windows-gtk, windows-qtWindowsGTK 4, Qt 6

The last two rows exist because GTK and Qt are themselves portable, useful for development (all five desktop toolkits run side by side on one Mac) and for teams that prefer one toolkit across Linux and Windows. Maturity varies by target; Platform support says exactly where each one stands rather than implying they’re all equal.

What it’s like day to day

Everything is one Cargo project plus a small Day.toml manifest. day launch -p <target> builds and runs; several -p flags launch targets in parallel. Tests run against a headless mock toolkit in ordinary cargo test, and dayscript drives the real app. The same YAML script taps buttons and asserts labels on every platform, which is also how the gallery screenshots on this site are captured in CI.

Rust compiles ahead of time, so there is no hot reload. The inner loop is an incremental compile and relaunch, usually seconds on desktop, with script replay to put you back on the screen you were working on. If sub-second hot reload is central to how you work, that is a reason to look elsewhere: better to know now than in week two.

What Day is not

  • Not a renderer: Day never rasterizes text or widgets itself. Even the canvas Piece records drawing commands and replays them through the platform’s native 2D API.
  • Not pixel-identical across platforms: the goal is consistent behavior and information architecture with native look and feel, not one skin everywhere.
  • Not a lowest common denominator: where platforms diverge, the API exposes the divergence (per-platform styling, capability flags) instead of hiding it; where a platform lacks a control, the backend composes one from primitives.
  • Not finished: Day is young. The core model is stable and exercised by a real Matrix chat client (Day-Matrix, a standalone Day app) running on five targets, but APIs still move and some designed features aren’t built yet. The docs mark those explicitly rather than describing the roadmap as the present.

Finding your way around

The documentation is sequenced so each section assumes only the ones before it:

  1. Start here — this page, the tradeoffs, and getting started.
  2. ConceptsPieces, Reactivity, Layout, Styling: the model in full.
  3. Guides — task-oriented pages on navigation, localization, accessibility, testing with dayscript, resources, and device capabilities.
  4. Build & ship — the CLI, project anatomy, packaging & signing, and platform status.
  5. Extendhow the extension model works and three worked tutorials.
  6. Under the hoodarchitecture and how rendering works, for when you want to see the machinery.
  7. Referenceper-widget and per-subsystem reference pages, and a condensed page for AI coding agents.