Gpui Focus Handle

Build keyboard-navigable interfaces with proper focus management

✨ The solution you've been looking for

Verified
Tested and verified by our team
9771 Stars

Focus management and keyboard navigation in GPUI. Use when handling focus, focus handles, or keyboard navigation.

focus keyboard-navigation ui accessibility gpui rust frontend interaction
Repository

See It In Action

Interactive preview & real-world examples

Live Demo
Skill Demo Animation

AI Conversation Simulator

See how users interact with this skill

User Prompt

I need to create a modal dialog that traps focus inside it when Tab is pressed and automatically focuses the first input field when opened

Skill Processing

Analyzing request...

Agent Response

Complete implementation with focus trap logic, auto-focus behavior, and proper keyboard navigation within the modal

Quick Start (3 Steps)

Get up and running in minutes

1

Install

claude-code skill install gpui-focus-handle

claude-code skill install gpui-focus-handle
2

Config

3

First Trigger

@gpui-focus-handle help

Commands

CommandDescriptionRequired Args
@gpui-focus-handle modal-dialog-with-focus-trapCreate a modal that keeps keyboard focus within its boundaries and auto-focuses the first inputNone
@gpui-focus-handle form-with-sequential-focus-navigationBuild a form where users can navigate between inputs using Tab/Shift-Tab with visual focus indicatorsNone
@gpui-focus-handle searchable-list-with-dynamic-focusImplement a search interface that focuses the input when activated and manages focus statesNone

Typical Use Cases

Modal Dialog with Focus Trap

Create a modal that keeps keyboard focus within its boundaries and auto-focuses the first input

Form with Sequential Focus Navigation

Build a form where users can navigate between inputs using Tab/Shift-Tab with visual focus indicators

Searchable List with Dynamic Focus

Implement a search interface that focuses the input when activated and manages focus states

Overview

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

 1struct FocusableComponent {
 2    focus_handle: FocusHandle,
 3}
 4
 5impl FocusableComponent {
 6    fn new(cx: &mut Context<Self>) -> Self {
 7        Self {
 8            focus_handle: cx.focus_handle(),
 9        }
10    }
11}

Making Elements Focusable

 1impl Render for FocusableComponent {
 2    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 3        div()
 4            .track_focus(&self.focus_handle)
 5            .on_action(cx.listener(Self::on_enter))
 6            .child("Focusable content")
 7    }
 8
 9    fn on_enter(&mut self, _: &Enter, cx: &mut Context<Self>) {
10        // Handle Enter key when focused
11        cx.notify();
12    }
13}

Focus Management

 1impl MyComponent {
 2    fn focus(&mut self, cx: &mut Context<Self>) {
 3        self.focus_handle.focus(cx);
 4    }
 5
 6    fn is_focused(&self, cx: &App) -> bool {
 7        self.focus_handle.is_focused(cx)
 8    }
 9
10    fn blur(&mut self, cx: &mut Context<Self>) {
11        cx.blur();
12    }
13}

Focus Events

Handling Focus Changes

 1impl Render for MyInput {
 2    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 3        let is_focused = self.focus_handle.is_focused(cx);
 4
 5        div()
 6            .track_focus(&self.focus_handle)
 7            .on_focus(cx.listener(|this, _event, cx| {
 8                this.on_focus(cx);
 9            }))
10            .on_blur(cx.listener(|this, _event, cx| {
11                this.on_blur(cx);
12            }))
13            .when(is_focused, |el| {
14                el.bg(cx.theme().focused_background)
15            })
16            .child(self.render_content())
17    }
18}
19
20impl MyInput {
21    fn on_focus(&mut self, cx: &mut Context<Self>) {
22        // Handle focus gained
23        cx.notify();
24    }
25
26    fn on_blur(&mut self, cx: &mut Context<Self>) {
27        // Handle focus lost
28        cx.notify();
29    }
30}

Keyboard Navigation

Tab Order

Elements with track_focus() automatically participate in Tab navigation.

 1div()
 2    .child(
 3        input1.track_focus(&focus1)  // Tab order: 1
 4    )
 5    .child(
 6        input2.track_focus(&focus2)  // Tab order: 2
 7    )
 8    .child(
 9        input3.track_focus(&focus3)  // Tab order: 3
10    )

Focus Within Containers

 1impl Container {
 2    fn focus_first(&mut self, cx: &mut Context<Self>) {
 3        if let Some(first) = self.children.first() {
 4            first.update(cx, |child, cx| {
 5                child.focus_handle.focus(cx);
 6            });
 7        }
 8    }
 9
10    fn focus_next(&mut self, cx: &mut Context<Self>) {
11        // Custom focus navigation logic
12    }
13}

Common Patterns

1. Auto-focus on Mount

 1impl MyDialog {
 2    fn new(cx: &mut Context<Self>) -> Self {
 3        let focus_handle = cx.focus_handle();
 4
 5        // Focus when created
 6        focus_handle.focus(cx);
 7
 8        Self { focus_handle }
 9    }
10}

2. Focus Trap (Modal)

 1impl Modal {
 2    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 3        div()
 4            .track_focus(&self.focus_handle)
 5            .on_key_down(cx.listener(|this, event: &KeyDownEvent, cx| {
 6                if event.key == Key::Tab {
 7                    // Keep focus within modal
 8                    this.focus_next_in_modal(cx);
 9                    cx.stop_propagation();
10                }
11            }))
12            .child(self.render_content())
13    }
14}

3. Conditional Focus

 1impl Searchable {
 2    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 3        div()
 4            .track_focus(&self.focus_handle)
 5            .when(self.search_active, |el| {
 6                el.on_mount(cx.listener(|this, _, cx| {
 7                    this.focus_handle.focus(cx);
 8                }))
 9            })
10            .child(self.search_input())
11    }
12}

Best Practices

✅ Track Focus on Interactive Elements

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

✅ Provide Visual Focus Indicators

1let is_focused = self.focus_handle.is_focused(cx);
2
3div()
4    .when(is_focused, |el| {
5        el.border_color(cx.theme().focused_border)
6    })

❌ Don’t: Forget to Track Focus

1// ❌ Bad: No track_focus, keyboard navigation won't work
2div()
3    .on_action(cx.listener(Self::on_enter))

Reference Documentation

  • API Reference: See api-reference.md
    • FocusHandle API, focus management
    • Events, keyboard navigation
    • Best practices

What Users Are Saying

Real feedback from the community

Environment Matrix

Dependencies

GPUI framework
Rust compiler

Framework Support

GPUI ✓ (required)

Context Window

Token Usage ~3K-6K tokens for typical focus management implementations

Security & Privacy

Information

Author
longbridge
Updated
2026-01-30
Category
frontend