gpui-focus-handle
π―Skillfrom longbridge/gpui-component
Enables keyboard-driven focus management and navigation between focusable elements in GPUI user interfaces.
Installation
npx skills add https://github.com/longbridge/gpui-component --skill gpui-focus-handleSkill Details
Focus management and keyboard navigation in GPUI. Use when handling focus, focus handles, or keyboard navigation. Enables keyboard-driven interfaces with proper focus tracking and navigation between focusable elements.
Overview
GPUI's focus system enables keyboard navigation and focus management.
Key Concepts:
- FocusHandle: Reference to focusable element
- Focus tracking: Current focused element
- Keyboard navigation: Tab/Shift-Tab between elements
- Focus events: on_focus, on_blur
Quick Start
Creating Focus Handles
```rust
struct FocusableComponent {
focus_handle: FocusHandle,
}
impl FocusableComponent {
fn new(cx: &mut Context
Self {
focus_handle: cx.focus_handle(),
}
}
}
```
Making Elements Focusable
```rust
impl Render for FocusableComponent {
fn render(&mut self, _: &mut Window, cx: &mut Context
div()
.track_focus(&self.focus_handle)
.on_action(cx.listener(Self::on_enter))
.child("Focusable content")
}
fn on_enter(&mut self, _: &Enter, cx: &mut Context
// Handle Enter key when focused
cx.notify();
}
}
```
Focus Management
```rust
impl MyComponent {
fn focus(&mut self, cx: &mut Context
self.focus_handle.focus(cx);
}
fn is_focused(&self, cx: &App) -> bool {
self.focus_handle.is_focused(cx)
}
fn blur(&mut self, cx: &mut Context
cx.blur();
}
}
```
Focus Events
Handling Focus Changes
```rust
impl Render for MyInput {
fn render(&mut self, _: &mut Window, cx: &mut Context
let is_focused = self.focus_handle.is_focused(cx);
div()
.track_focus(&self.focus_handle)
.on_focus(cx.listener(|this, _event, cx| {
this.on_focus(cx);
}))
.on_blur(cx.listener(|this, _event, cx| {
this.on_blur(cx);
}))
.when(is_focused, |el| {
el.bg(cx.theme().focused_background)
})
.child(self.render_content())
}
}
impl MyInput {
fn on_focus(&mut self, cx: &mut Context
// Handle focus gained
cx.notify();
}
fn on_blur(&mut self, cx: &mut Context
// Handle focus lost
cx.notify();
}
}
```
Keyboard Navigation
Tab Order
Elements with track_focus() automatically participate in Tab navigation.
```rust
div()
.child(
input1.track_focus(&focus1) // Tab order: 1
)
.child(
input2.track_focus(&focus2) // Tab order: 2
)
.child(
input3.track_focus(&focus3) // Tab order: 3
)
```
Focus Within Containers
```rust
impl Container {
fn focus_first(&mut self, cx: &mut Context
if let Some(first) = self.children.first() {
first.update(cx, |child, cx| {
child.focus_handle.focus(cx);
});
}
}
fn focus_next(&mut self, cx: &mut Context
// Custom focus navigation logic
}
}
```
Common Patterns
1. Auto-focus on Mount
```rust
impl MyDialog {
fn new(cx: &mut Context
let focus_handle = cx.focus_handle();
// Focus when created
focus_handle.focus(cx);
Self { focus_handle }
}
}
```
2. Focus Trap (Modal)
```rust
impl Modal {
fn render(&mut self, _: &mut Window, cx: &mut Context
div()
.track_focus(&self.focus_handle)
.on_key_down(cx.listener(|this, event: &KeyDownEvent, cx| {
if event.key == Key::Tab {
// Keep focus within modal
this.focus_next_in_modal(cx);
cx.stop_propagation();
}
}))
.child(self.render_content())
}
}
```
3. Conditional Focus
```rust
impl Searchable {
fn render(&mut self, _: &mut Window, cx: &mut Context
div()
.track_focus(&self.focus_handle)
.when(self.search_active, |el| {
el.on_mount(cx.listener(|this, _, cx| {
this.focus_handle.focus(cx);
}))
})
.child(self.search_input())
}
}
```
Best Practices
β Track Focus on Interactive Elements
```rust
// β Good: Track focus for keyboard interaction
input()
.track_focus(&self.focus_handle)
.on_action(cx.listener(Self::on_enter))
```
β Provide Visual Focus Indicators
```rust
let is_focused = self.focus_handle.is_focused(cx);
div()
.when(is_focused, |el| {
el.border_color(cx.theme().focused_border)
})
```
β Don't: Forget to Track Focus
```rust
// β Bad: No track_focus, keyboard navigation won't work
div()
.on_action(cx.listener(Self::on_enter))
```
Reference Documentation
- API Reference: See [api-reference.md](references/api-reference.md)
- FocusHandle API, focus management
- Events, keyboard navigation
- Best practices
More from this repository10
Enforces consistent GPUI component design patterns by providing a comprehensive style guide for creating and reviewing Rust UI components.
Enables asynchronous operations and background tasks in GPUI, allowing seamless coordination between UI updates and concurrent computations.
Provides CSS-like layout and styling for Rust GPUI components using type-safe, chainable methods for flexbox, sizing, colors, and spacing.
Manages application state through safe, concurrent entities with read, update, and weak reference capabilities for reactive and async-friendly state handling in GPUI.
Defines and manages keyboard-driven actions and key bindings for declarative UI interactions in GPUI applications.
Enables type-safe event handling, subscriptions, and observations for coordinating component interactions in GPUI applications.
gpui-context skill from longbridge/gpui-component
Enables comprehensive testing of GPUI applications with deterministic, single-threaded test execution for UI components and async operations.
Enables low-level, performance-critical custom UI element creation with precise control over layout, painting, and interaction phases in GPUI.
Manages global application state and configuration in GPUI, enabling centralized data access and sharing across components.