From hackartist-plugins
Dioxus changes since training cutoff (latest: 0.7.4) — Signals replacing use_state, RSX macro overhaul, server functions, asset!() system, dx CLI, Element-as-Result. Load before working with Dioxus.
How this skill is triggered — by the user, by Claude, or both
Slash command
/hackartist-plugins:dioxus-knowledge-patchThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Claude's baseline knowledge covers Dioxus through 0.4.x. This skill provides features from 0.5 (2024) onwards.
Claude's baseline knowledge covers Dioxus through 0.4.x. This skill provides features from 0.5 (2024) onwards.
| Old (0.4) | New (0.5+) |
|---|---|
fn App(cx: Scope) -> Element | fn App() -> Element |
cx.use_hook() | use_signal(), use_memo() |
use_state, use_ref | Signal<T> (always Copy) |
| Per-platform launchers | dioxus::launch(App) |
| Operation | Syntax |
|---|---|
| Create | let count = use_signal(|| 0); |
| Read (subscribes) | count.read() or count() |
| Read (no subscribe) | count.peek() |
| Write | count.write(), count.set(5), count += 1 |
| Global | static THEME: GlobalSignal<T> = GlobalSignal::new(|| ...) |
| Mapped | user.map(|u| &u.name) |
See references/signals-hooks.md for hooks, effects, resources, coroutines.
| Pattern | Example |
|---|---|
| Conditional | if show { Header {} } |
| Conditional attr | class: if active { "active" } |
| List with key | for item in items { li { key: "{item.id}", ... } } |
| Children prop | fn Card(children: Element) -> Element |
| Optional prop | #[props(default)] disabled: bool |
| Prop into | #[props(into)] id: String |
See references/rsx-patterns.md for attributes, events, prop spreading.
const LOGO: Asset = asset!("/assets/logo.png");
const HERO: Asset = asset!(
"/hero.png",
ImageAssetOptions::new()
.format(ImageFormat::Avif)
.preload(true)
);
const STYLES: Asset = asset!("/app.css", CssAssetOptions::new().minify(true));
| Feature | Syntax |
|---|---|
| Basic | #[server] async fn get_data() -> Result<T> |
| Route params | #[get("/api/users/{id}")] async fn get_user(id: u32) |
| Query params | #[get("/search?query")] async fn search(query: String) |
| Middleware | #[server] #[middleware(AuthLayer)] |
| Extractors | async fn auth(headers: HeaderMap, cookies: Cookies) |
See references/fullstack.md for WebSocket, SSR, streaming, server config.
#[derive(Routable, Clone, PartialEq)]
enum Route {
#[route("/")]
Home {},
#[route("/user/:id")]
User { id: u32 },
#[route("/files/:..path")] // Catch-all
Files { path: Vec<String> },
}
See references/router.md for layouts, navigation, nested routes.
| Command | Purpose |
|---|---|
dx serve | Dev server with hot-reload |
dx serve --platform ios | iOS simulator |
dx build --release | Production build |
dx bundle | Package for distribution |
dx serve --wasm-split | Route-based code splitting |
See references/cli-desktop.md for desktop config, platform args.
| File | Contents |
|---|---|
signals-hooks.md | Signals, use_memo, use_effect, use_resource, context |
rsx-patterns.md | RSX syntax, props, events, conditionals, lists |
fullstack.md | Server functions, SSR, WebSocket, extractors |
router.md | Routes, layouts, navigation, parameters |
cli-desktop.md | CLI commands, desktop config, platforms |
Use ? anywhere - propagates to ErrorBoundary:
#[component]
fn Profile(id: u32) -> Element {
let user = get_user(id)?; // Early return on error
rsx! { "{user.name}" }
}
rsx! {
SuspenseBoundary {
fallback: |_| rsx! { "Loading..." },
AsyncChild {}
}
}
fn AsyncChild() -> Element {
let data = use_resource(fetch_data).suspend()?;
rsx! { "{data}" }
}
use dioxus::document::{Title, Link, Meta};
rsx! {
Title { "My Page" }
Meta { name: "description", content: "..." }
Link { rel: "stylesheet", href: asset!("/style.css") }
}
#[derive(Store)]
struct AppState {
users: BTreeMap<String, User>,
}
#[component]
fn UserList(state: Store<AppState>) -> Element {
let users = state.users();
rsx! {
for (id, user) in users.iter() {
UserRow { key: "{id}", user } // Only changed items re-render
}
}
}
css_module!(Styles = "/styles.module.css", AssetOptions::css_module());
rsx! {
div { class: Styles::container, // Typed, compile-checked
p { class: Styles::title, "Hello" }
}
}
use axum::Router;
use dioxus::prelude::*;
#[tokio::main]
async fn main() {
let app = Router::new()
.serve_static_assets("dist")
.serve_dioxus_application(ServeConfig::new(), App);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
Memos in attributes don't subscribe properly:
// BAD: Won't update
let style = use_memo(move || format!("color: {}", color()));
rsx! { div { style: style } }
// GOOD: Direct signal read
rsx! { div { style: format!("color: {}", color()) } }
Use individual CSS properties:
// GOOD: Proper reactivity
rsx! {
p {
font_weight: if bold() { "bold" } else { "normal" },
text_align: "{align}",
}
}
Write mobile plugins in Kotlin/Java/Swift with dioxus_platform_bridge. CLI auto-bundles via linker metadata:
#[cfg(all(feature = "metadata", target_os = "android"))]
dioxus_platform_bridge::android_plugin!(
plugin = "geolocation",
aar = { env = "DIOXUS_ANDROID_ARTIFACT" },
deps = ["implementation(\"com.google.android.gms:play-services-location:21.3.0\")"]
);
Instant reload: Literal values, text, formatted segments, attribute order, template structure
Requires rebuild: Rust logic, component structure, control flow conditions, struct field changes
Workspace hot-patching (0.7.4+): Subsecond now patches across workspace library crates, not just the tip crate.
npx claudepluginhub hackartists/plugin --plugin hackartistCreates bite-sized, testable implementation plans from specs or requirements, with file structure and task decomposition. Activates before coding multi-step tasks.