Composer text becomes unreadable after live terminal theme switch

Open 💬 3 comments Opened Mar 9, 2026 by 0xdeafbeef

## Repro

  1. Start Codex TUI in a terminal with a dark theme.
  2. Type in the composer.
  3. Switch the terminal to a light theme without restarting Codex.
  4. Return focus to Codex and keep typing.

## Actual
Composer input becomes nearly invisible, effectively white/light text on a white/light background.

## Expected
Composer text should stay readable after a terminal theme change.

## Suspected cause
The composer background is recomputed from terminal colors, but textarea text is rendered with default/inherited cell styling. After a dark -> light theme switch, stale
foreground styling can remain while the background updates, leaving the input white-on-white.

## Relevant files

  • codex-rs/tui/src/bottom_pane/chat_composer.rs
  • codex-rs/tui/src/bottom_pane/textarea.rs
  • codex-rs/tui/src/tui/event_stream.rs

Before switch:

<img width="2557" height="702" alt="Image" src="https://github.com/user-attachments/assets/4cdae374-f963-41c5-8b6c-8dac98093eb1" />
After:

<img width="2557" height="702" alt="Image" src="https://github.com/user-attachments/assets/39a368a8-48b0-49f5-bce7-ecd55b05a1c7" />

Same after dark to light switches

# Evidence:

  • Composer background uses user_message_style():

<https://github.com/openai/codex/blob/main/codex-rs/tui/src/bottom_pane/chat_composer.rs#L4380>
<https://github.com/openai/codex/blob/main/codex-rs/tui/src/style.rs#L8>

  • Typed text uses plain Style::default():

<https://github.com/openai/codex/blob/main/codex-rs/tui/src/bottom_pane/textarea.rs#L1373>

  • Palette refresh only happens on FocusGained:

<https://github.com/openai/codex/blob/main/codex-rs/tui/src/tui/event_stream.rs#L249>

  • Style guide warning about white/black assumptions:

<https://github.com/openai/codex/blob/main/codex-rs/tui/styles.md#L17>

View original on GitHub ↗

3 Comments

mvanhorn · 5 months ago

Analysis & Root Cause

I traced the rendering path through the TUI code.

Root cause: terminal_palette.rs captures the terminal's foreground/background colors at startup (or palette construction time). When the terminal theme changes externally (dark -> light), ratatui widgets that use Color::Reset or no explicit color inherit the new terminal defaults correctly. But the composer input widget in public_widgets/composer_input.rs appears to use explicit or cached foreground colors derived from the original palette, creating a stale-color-on-new-background mismatch.

Relevant files:

  • codex-rs/tui/src/terminal_palette.rs - initial color capture
  • codex-rs/tui/src/public_widgets/composer_input.rs - text rendering
  • codex-rs/tui/src/color.rs and codex-rs/tui/src/style.rs - color/style helpers
  • codex-rs/tui/src/bottom_pane/list_selection_view.rs - theme picker (syntax highlighting themes, separate concern)

The pattern: Any widget that caches a resolved foreground color from the palette at init time will break on theme switch. The fix needs to address the root (palette staleness), not just the symptom (composer text).

Proposed Fix

Simplest approach: In the composer input widget, use Color::Reset for text foreground instead of a cached color value. This delegates color choice to the terminal, which always reflects the current theme. This is the lowest-risk fix and matches how most ratatui apps handle default text colors.

More robust approach: Detect terminal theme changes via OSC 10/11 escape sequences (query terminal fg/bg colors) on each draw cycle or on SIGWINCH. If the resolved colors differ from the cached palette, rebuild the palette. This would fix the issue for all widgets, not just the composer.

The simpler Color::Reset approach is probably right for a first fix - it solves the reported problem with minimal blast radius. Happy to submit a PR if invited.

ctbeiser · 15 days ago

I can confirm this is still extant. It's particularly a problem if you have long running tasks and use auto-light mode.

piotrostr · 1 day ago

Working automatic reference implementation covering this repro is posted here: https://github.com/openai/codex/issues/38575#issuecomment-5425261944

It includes both live DEC mode 2031 refresh and the stale composer foreground fix. Validated on Ghostty 1.2.3 through tmux 3.6a. No command or config surface.

~ codex & piotr