robius-widget-patterns
CRITICAL: Use for Robius widget patterns. Triggers on: apply_over, TextOrImage, modal, 可复用, 模态, collapsible, drag drop, reusable widget, widget design, pageflip, 组件设计, 组件模式
Best use case
robius-widget-patterns is best used when you need a repeatable AI agent workflow instead of a one-off prompt. It is especially useful for teams working in multi. CRITICAL: Use for Robius widget patterns. Triggers on: apply_over, TextOrImage, modal, 可复用, 模态, collapsible, drag drop, reusable widget, widget design, pageflip, 组件设计, 组件模式
CRITICAL: Use for Robius widget patterns. Triggers on: apply_over, TextOrImage, modal, 可复用, 模态, collapsible, drag drop, reusable widget, widget design, pageflip, 组件设计, 组件模式
Users should expect a more consistent workflow output, faster repeated execution, and less time spent rewriting prompts from scratch.
Practical example
Example input
Use the "robius-widget-patterns" skill to help with this workflow task. Context: CRITICAL: Use for Robius widget patterns. Triggers on: apply_over, TextOrImage, modal, 可复用, 模态, collapsible, drag drop, reusable widget, widget design, pageflip, 组件设计, 组件模式
Example output
A structured workflow result with clearer steps, more consistent formatting, and an output that is easier to reuse in the next run.
When to use this skill
- Use this skill when you want a reusable workflow rather than writing the same prompt again and again.
When not to use this skill
- Do not use this when you only need a one-off answer and do not need a reusable workflow.
- Do not use it if you cannot install or maintain the related files, repository context, or supporting tools.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/robius-widget-patterns/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How robius-widget-patterns Compares
| Feature / Agent | robius-widget-patterns | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
CRITICAL: Use for Robius widget patterns. Triggers on: apply_over, TextOrImage, modal, 可复用, 模态, collapsible, drag drop, reusable widget, widget design, pageflip, 组件设计, 组件模式
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
Related Guides
AI Agents for Marketing
Discover AI agents for marketing workflows, from SEO and content production to campaign research, outreach, and analytics.
AI Agents for Startups
Explore AI agent skills for startup validation, product research, growth experiments, documentation, and fast execution with small teams.
AI Agents for Coding
Browse AI agent skills for coding, debugging, testing, refactoring, code review, and developer workflows across Claude, Cursor, and Codex.
SKILL.md Source
# Robius Widget Patterns Skill
Best practices for designing reusable Makepad widgets based on Robrix and Moly codebase patterns.
**Source codebases:**
- **Robrix**: Matrix chat client - Avatar, RoomsList, RoomScreen widgets
- **Moly**: AI chat application - Slot, ChatLine, PromptInput, AdaptiveView widgets
## When to Use
Use this skill when:
- Creating reusable Makepad widgets
- Designing widget component APIs
- Implementing text/image toggle patterns
- Dynamic styling in Makepad
- Keywords: robrix widget, makepad component, reusable widget, widget design pattern
## Production Patterns
For production-ready widget patterns, see the `_base/` directory:
| Pattern | Description |
|---------|-------------|
| 01-widget-extension | Add helper methods to widget references |
| 02-modal-overlay | Popups, dialogs using DrawList2d overlay |
| 03-collapsible | Expandable/collapsible sections |
| 04-list-template | Dynamic lists with LivePtr templates |
| 05-lru-view-cache | Memory-efficient view caching |
| 14-callout-tooltip | Tooltips with arrow positioning |
| 20-redraw-optimization | Efficient redraw patterns |
| 15-dock-studio-layout | IDE-style resizable panels |
| 16-hover-effect | Hover effects with instance variables |
| 17-row-based-grid-layout | Dynamic grid layouts |
| 18-drag-drop-reorder | Drag-and-drop widget reordering |
| 19-pageflip-optimization | PageFlip 切换优化,即刻销毁/缓存模式 |
| 21-collapsible-row-portal-list | Auto-grouping consecutive items in portal lists with FoldHeader |
| 22-dropdown-overlay | Dropdown popups using DrawList2d overlay (no layout push) |
## Standard Widget Structure
```rust
use makepad_widgets::*;
live_design! {
use link::theme::*;
use link::widgets::*;
pub MyWidget = {{MyWidget}} {
width: Fill, height: Fit,
flow: Down,
// Child widgets defined in DSL
inner_view = <View> {
// ...
}
}
}
#[derive(Live, LiveHook, Widget)]
pub struct MyWidget {
#[deref] view: View, // Delegate to inner View
#[live] some_property: f64, // DSL-configurable property
#[live(100.0)] default_val: f64, // With default value
#[rust] internal_state: State, // Rust-only state (not in DSL)
#[animator] animator: Animator, // For animations
}
impl Widget for MyWidget {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
self.view.handle_event(cx, event, scope);
// Custom event handling...
}
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
self.view.draw_walk(cx, scope, walk)
}
}
```
## Text/Image Toggle Pattern
A common pattern for widgets that show either text or an image (like avatars):
```rust
live_design! {
pub Avatar = {{Avatar}} {
width: 36.0, height: 36.0,
align: { x: 0.5, y: 0.5 }
flow: Overlay, // Stack views on top of each other
text_view = <View> {
visible: true, // Default visible
show_bg: true,
draw_bg: {
uniform background_color: #888888
fn pixel(self) -> vec4 {
let sdf = Sdf2d::viewport(self.pos * self.rect_size);
let c = self.rect_size * 0.5;
sdf.circle(c.x, c.x, c.x)
sdf.fill_keep(self.background_color);
return sdf.result
}
}
text = <Label> {
text: "?"
}
}
img_view = <View> {
visible: false, // Hidden by default
img = <Image> {
fit: Stretch,
width: Fill, height: Fill,
}
}
}
}
#[derive(LiveHook, Live, Widget)]
pub struct Avatar {
#[deref] view: View,
#[rust] info: Option<UserInfo>,
}
impl Avatar {
/// Show text content, hiding the image
pub fn show_text<T: AsRef<str>>(
&mut self,
cx: &mut Cx,
bg_color: Option<Vec4>,
info: Option<AvatarTextInfo>,
username: T,
) {
self.info = info.map(|i| i.into());
// Get first character
let first_char = utils::first_letter(username.as_ref())
.unwrap_or("?").to_uppercase();
self.label(ids!(text_view.text)).set_text(cx, &first_char);
// Toggle visibility
self.view(ids!(text_view)).set_visible(cx, true);
self.view(ids!(img_view)).set_visible(cx, false);
// Apply optional background color
if let Some(color) = bg_color {
self.view(ids!(text_view)).apply_over(cx, live! {
draw_bg: { background_color: (color) }
});
}
}
/// Show image content, hiding the text
pub fn show_image<F, E>(
&mut self,
cx: &mut Cx,
info: Option<AvatarImageInfo>,
image_set_fn: F,
) -> Result<(), E>
where
F: FnOnce(&mut Cx, ImageRef) -> Result<(), E>
{
let img_ref = self.image(ids!(img_view.img));
let res = image_set_fn(cx, img_ref);
if res.is_ok() {
self.view(ids!(img_view)).set_visible(cx, true);
self.view(ids!(text_view)).set_visible(cx, false);
self.info = info.map(|i| i.into());
}
res
}
/// Check current display status
pub fn status(&mut self) -> DisplayStatus {
if self.view(ids!(img_view)).visible() {
DisplayStatus::Image
} else {
DisplayStatus::Text
}
}
}
```
## Dynamic Styling with apply_over
Apply dynamic styles at runtime:
```rust
// Apply single property
self.view(ids!(content)).apply_over(cx, live! {
draw_bg: { color: #ff0000 }
});
// Apply multiple properties
self.view(ids!(message)).apply_over(cx, live! {
padding: { left: 20, right: 20 }
margin: { top: 10 }
});
// Apply with variables
let highlight_color = if is_selected { vec4(1.0, 0.0, 0.0, 1.0) } else { vec4(0.5, 0.5, 0.5, 1.0) };
self.view(ids!(item)).apply_over(cx, live! {
draw_bg: { color: (highlight_color) }
});
```
## Widget Reference Pattern
Implement `*Ref` methods for external API:
```rust
impl AvatarRef {
/// See [`Avatar::show_text()`].
pub fn show_text<T: AsRef<str>>(
&self,
cx: &mut Cx,
bg_color: Option<Vec4>,
info: Option<AvatarTextInfo>,
username: T,
) {
if let Some(mut inner) = self.borrow_mut() {
inner.show_text(cx, bg_color, info, username);
}
}
/// See [`Avatar::show_image()`].
pub fn show_image<F, E>(
&self,
cx: &mut Cx,
info: Option<AvatarImageInfo>,
image_set_fn: F,
) -> Result<(), E>
where
F: FnOnce(&mut Cx, ImageRef) -> Result<(), E>
{
if let Some(mut inner) = self.borrow_mut() {
inner.show_image(cx, info, image_set_fn)
} else {
Ok(())
}
}
}
```
## Collapsible/Expandable Pattern
```rust
live_design! {
pub CollapsibleSection = {{CollapsibleSection}} {
flow: Down,
header = <View> {
cursor: Hand,
icon = <Icon> { }
title = <Label> { text: "Section" }
}
content = <View> {
visible: false,
// Expandable content here
}
}
}
#[derive(Live, LiveHook, Widget)]
pub struct CollapsibleSection {
#[deref] view: View,
#[rust] is_expanded: bool,
}
impl CollapsibleSection {
pub fn toggle(&mut self, cx: &mut Cx) {
self.is_expanded = !self.is_expanded;
self.view(ids!(content)).set_visible(cx, self.is_expanded);
// Rotate icon
let rotation = if self.is_expanded { 90.0 } else { 0.0 };
self.view(ids!(header.icon)).apply_over(cx, live! {
draw_icon: { rotation: (rotation) }
});
self.redraw(cx);
}
}
```
## Loading State Pattern
```rust
live_design! {
pub LoadableContent = {{LoadableContent}} {
flow: Overlay,
content = <View> {
visible: true,
// Main content
}
loading_overlay = <View> {
visible: false,
show_bg: true,
draw_bg: { color: #00000088 }
align: { x: 0.5, y: 0.5 }
<BouncingDots> { }
}
error_view = <View> {
visible: false,
error_label = <Label> { }
}
}
}
#[derive(Live, LiveHook, Widget)]
pub struct LoadableContent {
#[deref] view: View,
#[rust] state: LoadingState,
}
pub enum LoadingState {
Idle,
Loading,
Loaded,
Error(String),
}
impl LoadableContent {
pub fn set_state(&mut self, cx: &mut Cx, state: LoadingState) {
self.state = state;
match &self.state {
LoadingState::Idle | LoadingState::Loaded => {
self.view(ids!(content)).set_visible(cx, true);
self.view(ids!(loading_overlay)).set_visible(cx, false);
self.view(ids!(error_view)).set_visible(cx, false);
}
LoadingState::Loading => {
self.view(ids!(content)).set_visible(cx, true);
self.view(ids!(loading_overlay)).set_visible(cx, true);
self.view(ids!(error_view)).set_visible(cx, false);
}
LoadingState::Error(msg) => {
self.view(ids!(content)).set_visible(cx, false);
self.view(ids!(loading_overlay)).set_visible(cx, false);
self.view(ids!(error_view)).set_visible(cx, true);
self.label(ids!(error_view.error_label)).set_text(cx, msg);
}
}
self.redraw(cx);
}
}
```
## PortalList Item Pattern
For virtual list items:
```rust
live_design! {
pub ItemsList = {{ItemsList}} {
list = <PortalList> {
keep_invisible: false,
auto_tail: false,
width: Fill, height: Fill,
flow: Down,
// Item templates
item_entry = <ItemEntry> {}
header = <SectionHeader> {}
empty = <View> {}
}
}
}
impl Widget for ItemsList {
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
while let Some(item) = self.view.draw_walk(cx, scope, walk).step() {
if let Some(mut list) = item.as_portal_list().borrow_mut() {
list.set_item_range(cx, 0, self.items.len());
while let Some(item_id) = list.next_visible_item(cx) {
let item = list.item(cx, item_id, live_id!(item_entry));
// Populate item with data
self.populate_item(cx, item, &self.items[item_id]);
item.draw_all(cx, scope);
}
}
}
DrawStep::done()
}
}
```
## Best Practices
1. **Use `#[deref]` for delegation**: Delegate to inner View for standard behavior
2. **Separate DSL properties (`#[live]`) from Rust state (`#[rust]`)**
3. **Implement both inner methods and `*Ref` wrappers**
4. **Use `apply_over` for dynamic runtime styling**
5. **Use `flow: Overlay` for toggle/swap patterns**
6. **Use `set_visible()` to toggle between alternative views**
7. **Always call `redraw(cx)` after state changes**
## Reference Files
- `references/widget-patterns.md` - Additional widget patterns (Robrix)
- `references/styling-patterns.md` - Dynamic styling patterns (Robrix)
- `references/moly-widget-patterns.md` - Moly-specific patterns
- `Slot` widget for runtime content replacement
- `MolyRoot` conditional rendering wrapper
- `AdaptiveView` for responsive Mobile/Desktop layouts
- Chat line variants (UserLine, BotLine, ErrorLine, etc.)
- `CommandTextInput` with action buttons
- Sidebar navigation with radio buttons
## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.Related Skills
multi-agent-patterns
This skill should be used when the user asks to "design multi-agent system", "implement supervisor pattern", "create swarm architecture", "coordinate multiple agents", or mentions multi-agent patterns, context isolation, agent handoffs, sub-agents, or parallel agent execution.
modern-javascript-patterns
Comprehensive guide for mastering modern JavaScript (ES6+) features, functional programming patterns, and best practices for writing clean, maintainable, and performant code.
microservices-patterns
Master microservices architecture patterns including service boundaries, inter-service communication, data management, and resilience patterns for building distributed systems.
llm-app-patterns
Production-ready patterns for building LLM applications, inspired by [Dify](https://github.com/langgenius/dify) and industry best practices.
javascript-testing-patterns
Comprehensive guide for implementing robust testing strategies in JavaScript/TypeScript applications using modern testing frameworks and best practices.
error-handling-patterns
Build resilient applications with robust error handling strategies that gracefully handle failures and provide excellent debugging experiences.
e2e-testing-patterns
Build reliable, fast, and maintainable end-to-end test suites that provide confidence to ship code quickly and catch regressions before users do.
dbt-transformation-patterns
Production-ready patterns for dbt (data build tool) including model organization, testing strategies, documentation, and incremental processing.
binary-analysis-patterns
Comprehensive patterns and techniques for analyzing compiled binaries, understanding assembly code, and reconstructing program logic.
bash-defensive-patterns
Master defensive Bash programming techniques for production-grade scripts. Use when writing robust shell scripts, CI/CD pipelines, or system utilities requiring fault tolerance and safety.
zapier-make-patterns
No-code automation democratizes workflow building. Zapier and Make (formerly Integromat) let non-developers automate business processes without writing code. But no-code doesn't mean no-complexity - these platforms have their own patterns, pitfalls, and breaking points.
workflow-patterns
Use this skill when implementing tasks according to Conductor's TDD workflow, handling phase checkpoints, managing git commits for tasks, or understanding the verification protocol.