# How Alacritty Controls Cursor Styles and Blinking Behavior: A Technical Deep Dive

> Explore how Alacritty controls cursor styles and blinking behavior with a technical deep dive into its configuration parsing, runtime resolution, and GPU-accelerated rendering. Learn more now.

- Repository: [Alacritty/alacritty](https://github.com/alacritty/alacritty)
- Tags: deep-dive
- Published: 2026-03-05

---

**Alacritty controls cursor styles and blinking behavior through a three-stage pipeline that parses configuration from [`alacritty.yml`](https://github.com/alacritty/alacritty/blob/main/alacritty.yml), resolves the effective cursor style at runtime in `Processor::update_cursor_blinking`, and renders GPU-accelerated geometry via the display module.**

The `alacritty/alacritty` repository implements cursor management as a coordinated system between user preferences, terminal state, and event-driven animations. Understanding how cursor styles and blinking behavior are controlled requires examining the configuration structs, the runtime decision logic in the event processor, and the final rendering path that generates visible cursor rectangles.

## Configuration Model and User Settings

Cursor customization begins in [`alacritty/src/config/cursor.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/config/cursor.rs), where the `Cursor` struct defines all user-configurable properties. These values are deserialized from [`alacritty.yml`](https://github.com/alacritty/alacritty/blob/main/alacritty.yml) into the running application's `UiConfig`.

### Core Configuration Fields

The `Cursor` struct (lines 18-36) exposes these primary fields:

- **style**: A `ConfigCursorStyle` defining the default shape and blinking mode (default: `Block`)
- **vi_mode_style**: An optional override applied when the terminal enters VI mode
- **unfocused_hollow**: Boolean flag rendering a hollow block when the window loses focus (default: `true`)
- **thickness**: A percentage (0.0–1.0) controlling cursor line width (default: `0.15`)
- **blink_interval**: Milliseconds for a single on/off blink cycle (default: `750`)
- **blink_timeout**: Seconds before blinking pauses; `0` disables the pause (default: `5`)

### ConfigCursorStyle Enum

The `ConfigCursorStyle` enum (lines 76-84) distinguishes between simple shapes and shapes with explicit blinking overrides:

```rust
pub enum ConfigCursorStyle {
    Shape(CursorShape),
    WithBlinking {
        shape: CursorShape,
        blinking: CursorBlinking,
    },
}

```

**CursorShape** variants include `Block`, `Underline`, `Beam`, and `Hidden`. The **CursorBlinking** enum provides four control levels:

- **Never**: Forces blinking off regardless of terminal state
- **Off**: Follows the terminal's native blinking flag (off by default)
- **On**: Follows the terminal's native blinking flag (on by default)
- **Always**: Forces blinking on regardless of terminal state

## Runtime Style Resolution

The effective cursor style is computed dynamically in [`alacritty/src/event.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/event.rs) within `Processor::update_cursor_blinking` (lines 1617-1645). This method reconciles configuration defaults with transient states like VI mode, IME composition, and window focus.

### The Resolution Algorithm

When the event loop prepares to redraw, Alacritty executes this priority chain:

1. **Base selection**: Start with `config.cursor.style`
2. **VI mode override**: If VI mode is active and `vi_mode_style` is set, substitute the base style
3. **Terminal query**: Inspect the terminal's native cursor style via `self.terminal.cursor_style().blinking`
4. **Blinking resolution**:
   - If the config specifies `Never` or `Always`, use that override
   - Otherwise, inherit the terminal's native blinking flag
5. **Constraint masking**: Enable blinking only if (VI mode OR SHOW_CURSOR mode) is active AND no IME preedit is in progress
6. **Timer scheduling**: If blinking is enabled and the window is focused, schedule `BlinkCursor` and `BlinkTimeout` events; otherwise, cancel timers and force visibility

The `blink_interval` value determines the `BlinkCursor` timer frequency, while `blink_timeout` controls an optional `BlinkTimeout` timer that pauses blinking after the specified duration to reduce CPU usage.

## Rendering Pipeline

Once the effective style is determined, the display module handles actual pixel generation and visibility toggling.

### Shape Selection

In [`alacritty/src/display/content.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/display/content.rs), the `Content::new` function (lines 51-62) selects the final shape to render:

- Returns `CursorShape::Hidden` if the terminal reports a hidden cursor or during IME pre-edit
- Renders `HollowBlock` when the window is unfocused and `unfocused_hollow` is enabled
- Otherwise, uses the shape reported by the terminal state machine

### Geometry Generation

The `display::cursor::IntoRects` trait (lines 29-86 in [`alacritty/src/display/cursor.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/display/cursor.rs)) converts the abstract cursor into GPU-ready `RenderRect` primitives:

- **Beam**: Single vertical rectangle using `thickness` percentage of cell width
- **Underline**: Single horizontal rectangle at the cell bottom
- **Block**: Filled rectangle covering the entire cell
- **HollowBlock**: Four perimeter rectangles forming an unfilled box

### Blink Toggling

The scheduler in `Processor::schedule_blinking` (lines 47-53) toggles the `display.cursor_hidden` boolean on each `BlinkCursor` event. During the next frame, `Content::new` checks this flag and treats the cursor as hidden when true, creating the visible blinking effect without regenerating geometry.

## Practical Configuration Examples

### Customizing alacritty.yml

To configure a blinking beam cursor that pauses after 10 seconds, with a block cursor for VI mode:

```yaml
cursor:
  style:
    shape: Beam
    blinking: On
  vi_mode_style:
    shape: Block
    blinking: Always
  thickness: 0.20
  blink_interval: 500
  blink_timeout: 10
  unfocused_hollow: true

```

### Accessing Cursor State in Rust

When integrating with Alacritty's internals, access resolved cursor properties through `UiConfig`:

```rust
use alacritty::config::UiConfig;
use std::rc::Rc;

fn inspect_cursor(config: &Rc<UiConfig>) {
    let style = config.cursor.style();
    let vi_override = config.cursor.vi_mode_style();
    let thickness = config.cursor.thickness();
    let blink_ms = config.cursor.blink_interval();
    
    println!("Base style: {:?}, VI override: {:?}", style, vi_override);
}

```

These methods are defined in [`alacritty/src/config/cursor.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/config/cursor.rs) (lines 41-63).

### Triggering Blink Updates

After a configuration reload, emit a cursor blinking change event to reset timers:

```rust
use alacritty::event::Event;
use alacritty::event::EventType;

let event = Event::new(EventType::CursorBlinkingChange, None);
processor.event_queue.push(event);

```

This mirrors the implementation in [`alacritty/src/window_context.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/window_context.rs) (lines 28-33).

## Key Source Files

The cursor control system spans these critical files in the `alacritty/alacritty` repository:

- **[`alacritty/src/config/cursor.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/config/cursor.rs)**: Defines `Cursor`, `ConfigCursorStyle`, and `CursorBlinking` enums with serde deserialization logic
- **[`alacritty/src/event.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/event.rs)**: Contains `Processor::update_cursor_blinking` and timer scheduling for cursor visibility toggling
- **[`alacritty/src/window_context.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/window_context.rs)**: Initializes cursor blinking on startup and handles configuration reload events
- **[`alacritty/src/display/content.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/display/content.rs)**: Implements shape selection logic including VI mode, focus state, and hidden checks
- **[`alacritty/src/display/cursor.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/display/cursor.rs)**: Generates GPU rectangles for each cursor shape with thickness calculations
- **[`alacritty/src/config/ui_config.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/config/ui_config.rs)**: Root configuration struct holding the `cursor: Cursor` field

## Summary

- **Cursor styles and blinking behavior** in Alacritty are defined by the `Cursor` struct in [`alacritty/src/config/cursor.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/config/cursor.rs), which supports three shapes and four blinking control levels.
- **Runtime resolution** occurs in `Processor::update_cursor_blinking` (event.rs), which reconciles configuration defaults with VI mode state, terminal flags, and IME status.
- **Blinking animation** is driven by scheduled timers (`BlinkCursor`, `BlinkTimeout`) that toggle the `cursor_hidden` display flag between frames.
- **GPU rendering** converts the final resolved style into rectangles via `IntoRects` in [`display/cursor.rs`](https://github.com/alacritty/alacritty/blob/main/display/cursor.rs), respecting the configured `thickness` percentage.
- **Window focus** triggers the hollow block visualization when `unfocused_hollow` is enabled, handled during shape selection in [`display/content.rs`](https://github.com/alacritty/alacritty/blob/main/display/content.rs).

## Frequently Asked Questions

### How do I disable cursor blinking completely in Alacritty?

Set the `blinking` field to `Never` in your [`alacritty.yml`](https://github.com/alacritty/alacritty/blob/main/alacritty.yml) cursor configuration. This forces the cursor to remain visible regardless of terminal application requests or VI mode state. According to the source code in [`alacritty/src/config/cursor.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/config/cursor.rs), the `Never` variant of `CursorBlinking` acts as an override that suppresses all blinking timers.

### Why does my cursor stop blinking after a few seconds?

This is controlled by the `blink_timeout` configuration option, which defaults to 5 seconds. When the timeout elapses, Alacritty's event processor (in [`alacritty/src/event.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/event.rs)) cancels the `BlinkCursor` timer and leaves the cursor visible to save CPU cycles. Set `blink_timeout: 0` to disable this behavior and blink indefinitely.

### Does VI mode use a different cursor style automatically?

Only if you explicitly configure `vi_mode_style` in [`alacritty.yml`](https://github.com/alacritty/alacritty/blob/main/alacritty.yml). If this field is `None` (the default), VI mode inherits the base `style` configuration. When provided, Alacritty's display content logic (in [`alacritty/src/display/content.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/display/content.rs)) checks the VI mode state and switches to the override style immediately upon mode entry.

### What controls the cursor thickness in Alacritty?

The `thickness` field in the cursor configuration accepts a percentage value between 0.0 and 1.0, defaulting to 0.15 (15% of the cell width or height). During rendering in [`alacritty/src/display/cursor.rs`](https://github.com/alacritty/alacritty/blob/main/alacritty/src/display/cursor.rs), this percentage is multiplied by the character cell dimensions to calculate the actual pixel width of beam and underline cursors, or the border width of hollow blocks.