A Facet counter on AppKit
This example uses the 0.0.28 Facet application model. The component and its
tree are platform-neutral; facet_runtime selects the macOS facade and
facet_appkit mounts native AppKit controls. A named window owns the screen,
its navigation state, and its lifecycle.
Manifest
[package]
name = "counter"
version = "0.0.1"
edition = "2026"
[macos]
entry = "src/main.cplus"
[dependencies]
stdlib = "*"
facet = "*"
facet_runtime = "*"
flex_layout = "*"
events = "*"
[macos.dependencies]
facet_appkit = "*"
objc = "*"
appkit = "*"
quartzcore = "*"
webkit = "*"
The application entry is selected by the [macos] section. Version 0.0.28
does not use [[bin]]; a portable application can instead rely on the default
src/main.cplus entry.
Source
import "facet/facet" as core;
import "facet/elements" as ui;
import "facet/component" as component;
import "facet/label" as label;
import "facet/screen" as screen;
import "facet_runtime/runtime" as runtime;
import "stdlib/option" as option;
import "stdlib/status" as status;
import "stdlib/vec" as vec;
struct Counter {
clicks: i32,
}
impl Counter {
fn new() -> Counter {
return Counter { clicks: 0 };
}
fn on_click(ref this, sender: *u8) {
this.clicks = this.clicks +% 1;
match label::find("count") {
option::Option[label::Label]::Some(l) => {
let _updated: label::Label =
l.set_text("Clicked ${this.clicks} time(s)");
}
option::Option::None => { }
}
}
}
impl Counter: component::Component {
fn build(ref this) -> core::Node {
var body: core::Builder = core::Builder::new();
body.add(ui::label("Clicked 0 time(s)", key: "count"));
body.add(ui::button("Click me", key: "increment",
on_click: this.on_click));
return core::column(body).padding(20.0).gap(10.0);
}
}
impl Counter: component::Lifecycle {
fn on_attach(ref this, why: component::Attach) { return; }
fn on_detach(ref this, why: component::Detach) { return; }
}
impl Counter: screen::Screen {
fn menu_items(this) -> vec::Vec[screen::MenuItem] {
return vec::new::[screen::MenuItem]();
}
}
fn counter_screen() -> screen::ScreenBox {
return screen::screen_box(Counter::new());
}
fn main() -> i32 {
let app = runtime::App::new("counter");
app.window("main", counter_screen,
chrome: screen::Chrome::new(
title: "Counter", width: 360.0, height: 200.0));
if app.run("main") == status::Status::Ok { return 0; }
return 1;
}
The component owns clicks. The keyed label is found in the mounted tree and
updated in place by the handler. Window registration supplies the title and
size; screens no longer own chrome and applications no longer call
app.screen.
Build
cpc build
./target/debug/counter
Facet uses the same component, screen, named-window, and navigation model with facet_uikit, facet_android, facet_gtk, and facet_win32. Platform-specific dependencies and entries belong in their matching manifest sections.
‹ Back to all examples