Install
$ agentstack add skill-bwbioinfo-skill-dioxus-dioxus-component-dev ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Dioxus Component Development
This skill helps you create, design, and optimize Dioxus components using best practices, proper patterns, and efficient RSX syntax.
When to use this skill
- Creating new Dioxus components with proper structure
- Implementing component props and state management
- Writing RSX markup with proper syntax and patterns
- Optimizing component performance and reactivity
- Implementing component composition and reusability patterns
- Debugging component lifecycle and rendering issues
Component Development Patterns
1. Basic Component Structure
Simple Functional Component:
#![allow(non_snake_case)]
use dioxus::prelude::*;
#[component]
fn MyComponent() -> Element {
rsx! {
div {
class: "my-component",
"Hello from MyComponent!"
}
}
}
Component with Props:
#[component]
fn UserCard(name: String, email: String, avatar_url: Option) -> Element {
rsx! {
div {
class: "user-card",
if let Some(avatar) = avatar_url {
img {
src: "{avatar}",
alt: "Avatar for {name}",
class: "avatar"
}
}
div {
class: "user-info",
h3 { "{name}" }
p { "{email}" }
}
}
}
}
2. Component State Management
Using Signals for Local State:
#[component]
fn Counter() -> Element {
let mut count = use_signal(|| 0);
rsx! {
div {
class: "counter",
h2 { "Count: {count}" }
div {
class: "counter-controls",
button {
onclick: move |_| count += 1,
"Increment"
}
button {
onclick: move |_| count -= 1,
"Decrement"
}
button {
onclick: move |_| count.set(0),
"Reset"
}
}
}
}
}
Complex State with use_memo:
#[component]
fn TodoList(todos: Vec) -> Element {
let mut filter = use_signal(|| TodoFilter::All);
let filtered_todos = use_memo(move || {
match filter() {
TodoFilter::All => todos.clone(),
TodoFilter::Active => todos.iter().filter(|t| !t.completed).cloned().collect(),
TodoFilter::Completed => todos.iter().filter(|t| t.completed).cloned().collect(),
}
});
rsx! {
div {
class: "todo-list",
FilterControls { filter }
ul {
for todo in filtered_todos() {
TodoItem { key: "{todo.id}", todo: todo.clone() }
}
}
}
}
}
3. Event Handling Patterns
Mouse Events:
#[component]
fn InteractiveButton() -> Element {
let mut is_pressed = use_signal(|| false);
let mut is_hovered = use_signal(|| false);
rsx! {
button {
class: "interactive-btn",
class: if is_pressed() { "pressed" },
class: if is_hovered() { "hovered" },
onmousedown: move |_| is_pressed.set(true),
onmouseup: move |_| is_pressed.set(false),
onmouseleave: move |_| {
is_pressed.set(false);
is_hovered.set(false);
},
onmouseenter: move |_| is_hovered.set(true),
onclick: move |_| {
// Handle click logic
println!("Button clicked!");
},
"Click me!"
}
}
}
Form Input Handling:
#[component]
fn LoginForm() -> Element {
let mut username = use_signal(|| String::new());
let mut password = use_signal(|| String::new());
let mut is_submitting = use_signal(|| false);
let submit_form = move |_| {
if !username().is_empty() && !password().is_empty() {
is_submitting.set(true);
// Perform async login logic here
spawn(async move {
// Simulate API call
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
is_submitting.set(false);
});
}
};
rsx! {
form {
class: "login-form",
onsubmit: submit_form,
div {
class: "form-group",
label { "Username:" }
input {
r#type: "text",
value: "{username}",
oninput: move |evt| username.set(evt.value()),
placeholder: "Enter username"
}
}
div {
class: "form-group",
label { "Password:" }
input {
r#type: "password",
value: "{password}",
oninput: move |evt| password.set(evt.value()),
placeholder: "Enter password"
}
}
button {
r#type: "submit",
disabled: is_submitting(),
if is_submitting() {
"Logging in..."
} else {
"Login"
}
}
}
}
}
4. Advanced Component Patterns
Higher-Order Components (Providers):
#[derive(Clone)]
pub struct ThemeContext {
pub theme: Signal,
pub toggle_theme: Callback,
}
#[component]
fn ThemeProvider(children: Element) -> Element {
let mut theme = use_signal(|| Theme::Light);
let toggle_theme = use_callback(move |_| {
theme.set(match theme() {
Theme::Light => Theme::Dark,
Theme::Dark => Theme::Light,
});
});
let context = ThemeContext {
theme,
toggle_theme,
};
use_context_provider(|| context);
rsx! {
div {
class: "theme-provider",
class: match theme() {
Theme::Light => "light-theme",
Theme::Dark => "dark-theme",
},
{children}
}
}
}
#[component]
fn ThemedComponent() -> Element {
let theme_ctx = use_context::();
rsx! {
div {
class: "themed-component",
p { "Current theme: {theme_ctx.theme():?}" }
button {
onclick: move |_| theme_ctx.toggle_theme.call(()),
"Toggle Theme"
}
}
}
}
Render Props Pattern:
#[component]
fn DataLoader(
url: String,
children: Element,
loading: Element,
error: Element,
) -> Element {
let mut data = use_signal(|| None::);
let mut is_loading = use_signal(|| true);
let mut error_state = use_signal(|| None::);
use_effect(move || {
let url = url.clone();
spawn(async move {
match fetch_data::(&url).await {
Ok(result) => {
data.set(Some(result));
is_loading.set(false);
}
Err(e) => {
error_state.set(Some(e.to_string()));
is_loading.set(false);
}
}
});
});
rsx! {
div {
class: "data-loader",
if is_loading() {
{loading}
} else if let Some(_error) = error_state() {
{error}
} else {
{children}
}
}
}
}
5. Component Lifecycle and Effects
Cleanup Effects:
#[component]
fn WebSocketComponent(url: String) -> Element {
let mut messages = use_signal(|| Vec::::new());
let mut connection_status = use_signal(|| "Connecting".to_string());
use_effect(move || {
let url = url.clone();
// Setup WebSocket connection
let ws = WebSocket::new(&url).unwrap();
// Handle connection open
let on_open = {
let connection_status = connection_status.clone();
Closure::wrap(Box::new(move |_: web_sys::Event| {
connection_status.set("Connected".to_string());
}) as Box)
};
ws.set_onopen(Some(on_open.as_ref().unchecked_ref()));
// Cleanup closure to prevent memory leaks
move || {
ws.close().ok();
on_open.forget();
}
});
rsx! {
div {
class: "websocket-component",
p { "Status: {connection_status}" }
ul {
for message in messages() {
li { "{message}" }
}
}
}
}
}
6. Performance Optimization
Memoized Components:
#[component]
fn ExpensiveList(items: Vec) -> Element {
// Memoize expensive computations
let processed_items = use_memo(move || {
items.iter()
.filter(|item| item.visible)
.map(|item| process_item(item))
.collect::>()
});
rsx! {
div {
class: "expensive-list",
for item in processed_items() {
MemoizedListItem {
key: "{item.id}",
item: item.clone()
}
}
}
}
}
#[component]
fn MemoizedListItem(item: ProcessedItem) -> Element {
// This component will only re-render if item changes
rsx! {
div {
class: "list-item",
h3 { "{item.title}" }
p { "{item.description}" }
}
}
}
7. Error Boundaries
#[component]
fn ErrorBoundary(children: Element) -> Element {
let error = use_signal(|| None::);
if let Some(error) = error() {
rsx! {
div {
class: "error-boundary",
h2 { "Something went wrong" }
p { "Error: {error}" }
button {
onclick: move |_| error.set(None),
"Try Again"
}
}
}
} else {
rsx! {
ErrorHandler {
on_error: move |e| error.set(Some(e)),
{children}
}
}
}
}
Best Practices
Component Design Principles
- Single Responsibility: Each component should have one clear purpose
- Composition over Inheritance: Build complex UIs by composing simple components
- Prop Validation: Use TypeScript-like prop types for better development experience
- Consistent Naming: Use PascalCase for components and camelCase for props
Performance Guidelines
- Minimize State: Keep state as local as possible
- Use Signals Wisely: Prefer
use_signaloveruse_statefor reactive data - Memoize Expensive Operations: Use
use_memofor heavy computations - Avoid Inline Functions: Extract event handlers to reduce re-renders
RSX Best Practices
- Conditional Rendering: Use
if let,match, or boolean expressions appropriately - List Rendering: Always provide
keyattributes for dynamic lists - Event Handling: Use move closures for event handlers that capture state
- Attribute Binding: Use string interpolation for dynamic attributes
Common Patterns and Solutions
Modal/Dialog Components
#[component]
fn Modal(is_open: bool, on_close: Callback, children: Element) -> Element {
if !is_open {
return rsx! { div { style: "display: none;" } };
}
rsx! {
div {
class: "modal-overlay",
onclick: move |_| on_close.call(()),
div {
class: "modal-content",
onclick: move |e| e.stop_propagation(),
button {
class: "modal-close",
onclick: move |_| on_close.call(()),
"×"
}
{children}
}
}
}
}
Loading States
#[component]
fn AsyncComponent() -> Element {
let mut data = use_resource(|| async {
fetch_data().await
});
match data() {
Some(Ok(data)) => rsx! {
div { "Data: {data:?}" }
},
Some(Err(e)) => rsx! {
div { class: "error", "Error: {e}" }
},
None => rsx! {
div { class: "loading", "Loading..." }
}
}
}
This skill provides comprehensive patterns for building robust, performant, and maintainable Dioxus components.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: bwbioinfo
- Source: bwbioinfo/skill_dioxus
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.