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.
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
)
Information about the tab being formatted. Contains tab_title, active_pane, is_active, and more.
Array of all tabs in the window.
Array of all panes in the active tab.
Effective configuration for the window.
True if mouse is hovering over this tab. False on first pass (measurement).
Maximum cells available for this tab. Set to tab_max_width on first pass.
Return Values
Plain text for the tab title
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
)
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)
GUI window object with methods like set_left_status() and set_right_status()
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)
The URI that was activated
Return Value
Prevent default browser opening
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)
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