When to Use
Use the low-level Element trait when:
- Need fine-grained control over layout calculation
- Building complex, performance-critical components
- Implementing custom layout algorithms (masonry, circular, etc.)
- High-level
Render/RenderOnce APIs are insufficient
Prefer Render/RenderOnce for: Simple components, standard layouts, declarative UI
Quick Start
The Element trait provides direct control over three rendering phases:
impl Element for MyElement {
type RequestLayoutState = MyLayoutState; // Data passed to later phases
type PrepaintState = MyPaintState; // Data for painting
fn id(&self) -> Option<ElementId> {
Some(self.id.clone())
}
fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {
None
}
// Phase 1: Calculate sizes and positions
fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)
-> (LayoutId, Self::RequestLayoutState)
{
let layout_id = window.request_layout(
Style { size: size(px(200.), px(100.)), ..default() },
vec![],
cx
);
(layout_id, MyLayoutState { /* ... */ })
}
// Phase 2: Create hitboxes, prepare for painting
fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut Self::RequestLayoutState,
window: &mut Window, cx: &mut App) -> Self::PrepaintState
{
let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);
MyPaintState { hitbox }
}
// Phase 3: Render and handle interactions
fn paint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut Self::RequestLayoutState,
paint_state: &mut Self::PrepaintState, window: &mut Window, cx: &mut App)
{
window.paint_quad(paint_quad(bounds, Corners::all(px(4.)), cx.theme().background));
window.on_mouse_event({
let hitbox = paint_state.hitbox.clone();
move |event: &MouseDownEvent, phase, window, cx| {
if hitbox.is_hovered(window) && phase.bubble() {
// Handle interaction
cx.stop_propagation();
}
}
});
}
}
// Enable element to be used as child
impl IntoElement for MyElement {
type Element = Self;
fn into_element(self) -> Self::Element { self }
}
Core Concepts
Three-Phase Rendering
- request_layout: Calculate sizes and positions, return layout ID and state
- prepaint: Create hitboxes, compute final bounds, prepare for painting
- paint: Render element, set up interactions (mouse events, cursor styles)
State Flow
RequestLayoutState → PrepaintState → paint
State flows in one direction through associated types, passed as mutable references between phases.
Key Operations
- Layout:
window.request_layout(style, children, cx) - Create layout node
- Hitboxes:
window.insert_hitbox(bounds, behavior) - Create interaction area
- Painting:
window.paint_quad(...) - Render visual content
- Events:
window.on_mouse_event(handler) - Handle user input
Reference Documentation
Complete API Documentation
- Element Trait API: See api-reference.md
- Associated types, methods, parameters, return values
- Hitbox system, event handling, cursor styles
Implementation Guides
Examples: See examples.md
- Simple text element with highlighting
- Interactive element with selection
- Complex element with child management
Best Practices: See best-practices.md
- State management, performance optimization
- Interaction handling, layout strategies
- Error handling, testing, common pitfalls
Common Patterns: See patterns.md
- Text rendering, container, interactive, composite, scrollable patterns
- Pattern selection guide
Advanced Patterns: See advanced-patterns.md
- Custom layout algorithms (masonry, circular)
- Element composition with traits
- Async updates, memoization, virtual lists
Converted and distributed by TomeVault | Claim this content
1---2name: gpui-element3description: Implementing custom elements using GPUI's low-level Element API (vs. high-level Render/RenderOnce APIs). Use when you need maximum control over layout, prepaint, and paint phases for complex, performance-critical custom UI components that cannot be achieved with Render/RenderOnce traits.4---56## When to Use78Use the low-level `Element` trait when:9- Need fine-grained control over layout calculation10- Building complex, performance-critical components11- Implementing custom layout algorithms (masonry, circular, etc.)12- High-level `Render`/`RenderOnce` APIs are insufficient1314**Prefer `Render`/`RenderOnce` for:** Simple components, standard layouts, declarative UI1516## Quick Start1718The `Element` trait provides direct control over three rendering phases:1920```rust21impl Element for MyElement {22 type RequestLayoutState = MyLayoutState; // Data passed to later phases23 type PrepaintState = MyPaintState; // Data for painting2425 fn id(&self) -> Option<ElementId> {26 Some(self.id.clone())27 }2829 fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {30 None31 }3233 // Phase 1: Calculate sizes and positions34 fn request_layout(&mut self, .., window: &mut Window, cx: &mut App)35 -> (LayoutId, Self::RequestLayoutState)36 {37 let layout_id = window.request_layout(38 Style { size: size(px(200.), px(100.)), ..default() },39 vec![],40 cx41 );42 (layout_id, MyLayoutState { /* ... */ })43 }4445 // Phase 2: Create hitboxes, prepare for painting46 fn prepaint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut Self::RequestLayoutState,47 window: &mut Window, cx: &mut App) -> Self::PrepaintState48 {49 let hitbox = window.insert_hitbox(bounds, HitboxBehavior::Normal);50 MyPaintState { hitbox }51 }5253 // Phase 3: Render and handle interactions54 fn paint(&mut self, .., bounds: Bounds<Pixels>, layout: &mut Self::RequestLayoutState,55 paint_state: &mut Self::PrepaintState, window: &mut Window, cx: &mut App)56 {57 window.paint_quad(paint_quad(bounds, Corners::all(px(4.)), cx.theme().background));5859 window.on_mouse_event({60 let hitbox = paint_state.hitbox.clone();61 move |event: &MouseDownEvent, phase, window, cx| {62 if hitbox.is_hovered(window) && phase.bubble() {63 // Handle interaction64 cx.stop_propagation();65 }66 }67 });68 }69}7071// Enable element to be used as child72impl IntoElement for MyElement {73 type Element = Self;74 fn into_element(self) -> Self::Element { self }75}76```7778## Core Concepts7980### Three-Phase Rendering81821. **request_layout**: Calculate sizes and positions, return layout ID and state832. **prepaint**: Create hitboxes, compute final bounds, prepare for painting843. **paint**: Render element, set up interactions (mouse events, cursor styles)8586### State Flow8788```89RequestLayoutState → PrepaintState → paint90```9192State flows in one direction through associated types, passed as mutable references between phases.9394### Key Operations9596- **Layout**: `window.request_layout(style, children, cx)` - Create layout node97- **Hitboxes**: `window.insert_hitbox(bounds, behavior)` - Create interaction area98- **Painting**: `window.paint_quad(...)` - Render visual content99- **Events**: `window.on_mouse_event(handler)` - Handle user input100101## Reference Documentation102103### Complete API Documentation104- **Element Trait API**: See [api-reference.md](references/api-reference.md)105 - Associated types, methods, parameters, return values106 - Hitbox system, event handling, cursor styles107108### Implementation Guides109- **Examples**: See [examples.md](references/examples.md)110 - Simple text element with highlighting111 - Interactive element with selection112 - Complex element with child management113114- **Best Practices**: See [best-practices.md](references/best-practices.md)115 - State management, performance optimization116 - Interaction handling, layout strategies117 - Error handling, testing, common pitfalls118119- **Common Patterns**: See [patterns.md](references/patterns.md)120 - Text rendering, container, interactive, composite, scrollable patterns121 - Pattern selection guide122123- **Advanced Patterns**: See [advanced-patterns.md](references/advanced-patterns.md)124 - Custom layout algorithms (masonry, circular)125 - Element composition with traits126 - Async updates, memoization, virtual lists127128---129> Converted and distributed by [TomeVault](https://tomevault.io) | [Claim this content](https://tomevault.io/claim/longbridge/gpui-component)