Skip to main content
Window events are emitted throughout the lifecycle of WezTerm windows and panes. These events allow you to customize window behavior, format UI elements, and respond to user interactions.

Formatting and UI Events

format-tab-title

Since: 20210502-130208-bff6815d Emitted when tab title text needs to be computed or recomputed.

Characteristics

  • Synchronous event - Must return immediately to avoid blocking UI
  • Cannot call asynchronous functions like wezterm.run_child_process()
  • Called twice per tab: once for measurement, once for rendering
  • Only the first registered handler is executed

Event Signature

wezterm.on('format-tab-title', 
  function(tab, tabs, panes, config, hover, max_width)
    -- Return string or FormatItems table
  end
)
tab
TabInformation
Information about the tab being formatted. Contains tab_title, active_pane, is_active, and more.
tabs
TabInformation[]
Array of all tabs in the window.
panes
PaneInformation[]
Array of all panes in the active tab.
config
table
Effective configuration for the window.
hover
boolean
True if mouse is hovering over this tab. False on first pass (measurement).
max_width
number
Maximum cells available for this tab. Set to tab_max_width on first pass.

Return Values

string
string
Plain text for the tab title
FormatItems
table
Array of format items with text, colors, and attributes (same as wezterm.format())

Examples

Basic Tab Title
local wezterm = require 'wezterm'

function tab_title(tab_info)
  local title = tab_info.tab_title
  if title and #title > 0 then
    return title
  end
  return tab_info.active_pane.title
end

wezterm.on('format-tab-title',
  function(tab, tabs, panes, config, hover, max_width)
    local title = tab_title(tab)
    if tab.is_active then
      return {
        { Background = { Color = 'blue' } },
        { Text = ' ' .. title .. ' ' },
      }
    end
    return title
  end
)
Fancy Tab Bar with Icons
local SOLID_LEFT_ARROW = wezterm.nerdfonts.pl_right_hard_divider
local SOLID_RIGHT_ARROW = wezterm.nerdfonts.pl_left_hard_divider

wezterm.on('format-tab-title',
  function(tab, tabs, panes, config, hover, max_width)
    local edge_background = '#0b0022'
    local background = '#1b1032'
    local foreground = '#808080'

    if tab.is_active then
      background = '#2b2042'
      foreground = '#c0c0c0'
    elseif hover then
      background = '#3b3052'
      foreground = '#909090'
    end

    local edge_foreground = background
    local title = tab.active_pane.title

    -- Ensure titles fit, leaving room for edges
    title = wezterm.truncate_right(title, max_width - 2)

    return {
      { Background = { Color = edge_background } },
      { Foreground = { Color = edge_foreground } },
      { Text = SOLID_LEFT_ARROW },
      { Background = { Color = background } },
      { Foreground = { Color = foreground } },
      { Text = title },
      { Background = { Color = edge_background } },
      { Foreground = { Color = edge_foreground } },
      { Text = SOLID_RIGHT_ARROW },
    }
  end
)
Tab Index and Count
wezterm.on('format-tab-title',
  function(tab, tabs, panes, config, hover, max_width)
    local title = tab.active_pane.title
    local index = tab.tab_index + 1
    local count = #tabs
    
    return string.format('[%d/%d] %s', index, count, title)
  end
)

format-window-title

Since: 20210314-114017-04b7cedd Emitted when the window title needs to be formatted.
wezterm.on('format-window-title', function(tab, pane, tabs, panes, config)
  local title = tab.active_pane.title
  local workspace = tab.active_pane.user_vars.WORKSPACE or 'default'
  return string.format('%s - %s', workspace, title)
end)

Status Bar Events

update-status

Since: 20220903-194523-3bb1ed61 Emitted periodically based on status_update_interval configuration.

Characteristics

  • Asynchronous - can perform longer operations
  • Only one instance runs at a time (coalesced if handler is slow)
  • Won’t schedule next call until status_update_interval ms after previous call completes

Event Signature

wezterm.on('update-status', function(window, pane)
  -- Update status bars using window methods
end)
window
Window
GUI window object with methods like set_left_status() and set_right_status()
pane
Pane
Active pane in the window

Examples

Clock in Status Bar
wezterm.on('update-status', function(window, pane)
  local date = wezterm.strftime '%Y-%m-%d %H:%M:%S'
  window:set_right_status(wezterm.format {
    { Attribute = { Intensity = 'Bold' } },
    { Text = date },
  })
end)
Workspace Indicator
wezterm.on('update-status', function(window, pane)
  local workspace = window:active_workspace()
  local colors = {
    coding = '#00ff00',
    ops = '#ff0000',
    default = '#888888',
  }
  
  window:set_left_status(wezterm.format {
    { Background = { Color = colors[workspace] or colors.default } },
    { Foreground = { Color = '#000000' } },
    { Text = ' ' .. workspace .. ' ' },
  })
end)
Battery and System Info
wezterm.on('update-status', function(window, pane)
  local battery = ''
  for _, b in ipairs(wezterm.battery_info()) do
    battery = string.format('%.0f%%', b.state_of_charge * 100)
  end
  
  local date = wezterm.strftime '%H:%M'
  
  window:set_right_status(wezterm.format {
    { Text = battery .. ' | ' .. date },
  })
end)

update-right-status

Deprecated in favor of update-status. Use update-status instead.

Interaction Events

bell

Since: 20211204-082213-a66c61ee9 Emitted when ASCII BEL sequence is received by a pane.

Characteristics

  • Fire-and-forget event
  • Does not alter WezTerm’s bell handling (supplements it)
  • Pane may not be the active pane
wezterm.on('bell', function(window, pane)
  wezterm.log_info('Bell in pane ' .. pane:pane_id())
  -- Could show notification, flash colors, etc.
end)

open-uri

Emitted when a URI is activated (e.g., clicking a link).

Event Signature

wezterm.on('open-uri', function(window, pane, uri)
  -- Return false to prevent default action
end)
uri
string
The URI that was activated

Return Value

false
boolean
Prevent default browser opening
nil
nil
Allow default handling

Examples

Custom mailto Handler
wezterm.on('open-uri', function(window, pane, uri)
  local start, match_end = uri:find 'mailto:'
  if start == 1 then
    local recipient = uri:sub(match_end + 1)
    window:perform_action(
      wezterm.action.SpawnCommandInNewWindow {
        args = { 'mutt', recipient },
      },
      pane
    )
    return false -- Prevent browser opening
  end
  -- Allow default for other URIs
end)
JIRA Integration
wezterm.on('open-uri', function(window, pane, uri)
  -- Handle jira:PROJ-123 format
  local issue = uri:match('^jira:(.+)$')
  if issue then
    local url = 'https://jira.company.com/browse/' .. issue
    wezterm.open_with(url)
    return false
  end
end)

new-tab-button-click

Since: 20230326-111934-3666303c Emitted when the + button in the tab bar is clicked.
wezterm.on('new-tab-button-click',
  function(window, pane, button, default_action)
    -- button: "Left", "Right", or "Middle"
    -- default_action: KeyAssignment or nil
    
    if button == 'Right' then
      window:perform_action(
        wezterm.action.ShowLauncherArgs { flags = 'FUZZY|WORKSPACES' },
        pane
      )
      return false -- Prevent default
    end
    -- Allow default for left-click
  end
)

augment-command-palette

Since: 20230712-072601-f4abf8fd Emitted when Command Palette is shown. Add custom entries.

Characteristics

  • Synchronous - no async operations allowed
  • Returns array of command entries
wezterm.on('augment-command-palette', function(window, pane)
  return {
    {
      brief = 'Rename tab',
      icon = 'md_rename_box',
      action = wezterm.action.PromptInputLine {
        description = 'Enter new name for tab',
        action = wezterm.action_callback(function(window, pane, line)
          if line then
            window:active_tab():set_title(line)
          end
        end),
      },
    },
    {
      brief = 'Select workspace',
      icon = 'md_briefcase',
      action = wezterm.action.ShowLauncherArgs {
        flags = 'FUZZY|WORKSPACES',
      },
    },
  }
end)

Lifecycle Events

window-resized

Since: 20210314-114017-04b7cedd Emitted when window is resized or enters/exits fullscreen.

Characteristics

  • Asynchronous with respect to resize operation
  • Coalesced: max 1 executing + 1 buffered during live resize
wezterm.on('window-resized', function(window, pane)
  local dims = window:get_dimensions()
  wezterm.log_info('Window resized to ' .. dims.pixel_width .. 'x' .. dims.pixel_height)
end)
Adaptive Padding in Fullscreen
function recompute_padding(window)
  local window_dims = window:get_dimensions()
  local overrides = window:get_config_overrides() or {}

  if not window_dims.is_full_screen then
    if not overrides.window_padding then
      return -- No changes needed
    end
    overrides.window_padding = nil
  else
    -- Use middle third in fullscreen
    local third = math.floor(window_dims.pixel_width / 3)
    local new_padding = {
      left = third,
      right = third,
      top = 0,
      bottom = 0,
    }
    if overrides.window_padding
      and new_padding.left == overrides.window_padding.left then
      return -- Padding unchanged
    end
    overrides.window_padding = new_padding
  end
  window:set_config_overrides(overrides)
end

wezterm.on('window-resized', function(window, pane)
  recompute_padding(window)
end)

wezterm.on('window-config-reloaded', function(window)
  recompute_padding(window)
end)

window-config-reloaded

Since: 20210314-114017-04b7cedd Emitted when window configuration is reloaded.

Triggers

  • Configuration file changes (when automatically_reload_config is enabled)
  • ReloadConfiguration key action
  • window:set_config_overrides() is called

Important

Calling window:set_config_overrides() inside this event triggers another event. Avoid loops by only calling when values actually change.
wezterm.on('window-config-reloaded', function(window, pane)
  wezterm.log_info('Config reloaded for window ' .. window:window_id())
end)

window-focus-changed

Since: 20221119-145034-49b9839f Emitted when window focus state changes.
wezterm.on('window-focus-changed', function(window, pane)
  if window:is_focused() then
    wezterm.log_info('Window gained focus')
  else
    wezterm.log_info('Window lost focus')
  end
end)
Dim Unfocused Windows
wezterm.on('window-focus-changed', function(window, pane)
  local overrides = window:get_config_overrides() or {}
  
  if window:is_focused() then
    overrides.color_scheme = 'Tokyo Night'
  else
    overrides.color_scheme = 'Tokyo Night Storm'
  end
  
  window:set_config_overrides(overrides)
end)

user-var-changed

Since: 20220903-194523-3bb1ed61 Emitted when a user variable is set via escape sequence.

Setting User Vars

From shell:
printf "\033]1337;SetUserVar=%s=%s\007" foo `echo -n bar | base64`

Event Handler

wezterm.on('user-var-changed', function(window, pane, name, value)
  wezterm.log_info('User var: ' .. name .. ' = ' .. value)
  
  if name == 'BUILD_STATUS' then
    local colors = {
      success = 'green',
      failure = 'red',
      running = 'yellow',
    }
    window:set_left_status(wezterm.format {
      { Background = { Color = colors[value] or 'gray' } },
      { Text = ' ' .. value .. ' ' },
    })
  end
end)

Common Patterns

Status Bar with Multiple Sections

wezterm.on('update-status', function(window, pane)
  local workspace = window:active_workspace()
  local date = wezterm.strftime '%H:%M'
  local battery = ''
  
  for _, b in ipairs(wezterm.battery_info()) do
    battery = string.format('🔋%.0f%%', b.state_of_charge * 100)
  end
  
  window:set_left_status(workspace)
  window:set_right_status(battery .. ' | ' .. date)
end)

Conditional UI Based on Pane

wezterm.on('update-status', function(window, pane)
  local cwd = pane:get_current_working_dir()
  if cwd and cwd:find('/production') then
    window:set_left_status(wezterm.format {
      { Background = { Color = 'red' } },
      { Foreground = { Color = 'white' } },
      { Text = ' ⚠ PRODUCTION ⚠ ' },
    })
  else
    window:set_left_status('')
  end
end)

See Also