gpui-focus-handle

GPUI's focus system enables keyboard navigation and focus management.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "gpui-focus-handle" with this command: npx skills add longbridge/gpui-component/longbridge-gpui-component-gpui-focus-handle

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

struct FocusableComponent { focus_handle: FocusHandle, }

impl FocusableComponent { fn new(cx: &mut Context<Self>) -> Self { Self { focus_handle: cx.focus_handle(), } } }

Making Elements Focusable

impl Render for FocusableComponent { fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { div() .track_focus(&self.focus_handle) .on_action(cx.listener(Self::on_enter)) .child("Focusable content") }

fn on_enter(&#x26;mut self, _: &#x26;Enter, cx: &#x26;mut Context&#x3C;Self>) {
    // Handle Enter key when focused
    cx.notify();
}

}

Focus Management

impl MyComponent { fn focus(&mut self, cx: &mut Context<Self>) { self.focus_handle.focus(cx); }

fn is_focused(&#x26;self, cx: &#x26;App) -> bool {
    self.focus_handle.is_focused(cx)
}

fn blur(&#x26;mut self, cx: &#x26;mut Context&#x3C;Self>) {
    cx.blur();
}

}

Focus Events

Handling Focus Changes

impl Render for MyInput { fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { let is_focused = self.focus_handle.is_focused(cx);

    div()
        .track_focus(&#x26;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<Self>) { // Handle focus gained cx.notify(); }

fn on_blur(&#x26;mut self, cx: &#x26;mut Context&#x3C;Self>) {
    // Handle focus lost
    cx.notify();
}

}

Keyboard Navigation

Tab Order

Elements with track_focus() automatically participate in Tab navigation.

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

impl Container { fn focus_first(&mut self, cx: &mut Context<Self>) { if let Some(first) = self.children.first() { first.update(cx, |child, cx| { child.focus_handle.focus(cx); }); } }

fn focus_next(&#x26;mut self, cx: &#x26;mut Context&#x3C;Self>) {
    // Custom focus navigation logic
}

}

Common Patterns

  1. Auto-focus on Mount

impl MyDialog { fn new(cx: &mut Context<Self>) -> Self { let focus_handle = cx.focus_handle();

    // Focus when created
    focus_handle.focus(cx);

    Self { focus_handle }
}

}

  1. Focus Trap (Modal)

impl Modal { fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { 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()) } }

  1. Conditional Focus

impl Searchable { fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { 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

// ✅ Good: Track focus for keyboard interaction input() .track_focus(&self.focus_handle) .on_action(cx.listener(Self::on_enter))

✅ Provide Visual Focus Indicators

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

// ❌ 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

  • FocusHandle API, focus management

  • Events, keyboard navigation

  • Best practices

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

gpui-layout-and-style

No summary provided by upstream source.

Repository SourceNeeds Review
General

gpui-async

No summary provided by upstream source.

Repository SourceNeeds Review
General

gpui-context

No summary provided by upstream source.

Repository SourceNeeds Review