Window Rules
Syntax
hl.window_rule({
name? = string,
match = {
prop = some_prop_value,
},
effect = some_effect_value,
})Window Rules
You can set window rules to achieve different window behaviors based on their properties.
Props
The supported fields for the match table are:
| Prop | Description | Type |
|---|---|---|
| class | Windows with class matching RegEx | [RegEx] |
| content | Windows with specified content type (none, photo, video, game) | string |
| focus | Currently focused window | bool |
| fullscreen | Fullscreen (covering or non-covering) windows | bool |
| fullscreen_state_client | Windows with matching fullscreenstate. 0 - none, 1 - maximize, 2 - fullscreen, 3 - maximize and fullscreen | int |
| fullscreen_state_internal | Windows with matching fullscreenstate. 0 - none, 1 - maximize, 2 - fullscreen, 3 - maximize and fullscreen | int |
| float | Floating windows | bool |
| group | Grouped windows | bool |
| initial_class | Windows with initialClass matching RegEx | [RegEx] |
| initial_title | Windows with initialTitle matching RegEx | [RegEx] |
| modal | Modal windows (e.g., “Are you sure” popups) | bool |
| pin | Pins the window (i.e. show it on all workspaces). Important: pinning is ignored for non-floating windows | bool |
| tag | Windows with matching tag | string |
| title | Windows with title matching RegEx | [RegEx] |
| workspace | Windows on matching workspace | workspace selector |
| xdg_tag | Match a window by its xdgTag | [RegEx] |
| xwayland | Xwayland windows | bool |
Effects
Static effects
Warning
It is not possible to float (or any other static rule) a window based on a change in the title after the window has been created.
This applies to all static effects listed here.
Instead, use a dispatch triggered by an event listener to apply the effect after the window has been created:
hl.on("window.title", function(w)
if w ~= nil and w.title == "foo" then
hl.dispatch(hl.dsp.window.float({ action = "set" }))
end
end)Static effects are evaluated once when the window is opened and never again.
This essentially means that it is always the initialTitle and initialClass which will be found when matching on title and class, respectively.
| Effect | Description | Type |
|---|---|---|
| center | If the window is floating, will center it on the monitor | bool |
| content | Sets content type: "none", "photo", "video", or "game" | string |
| float | Floats a window | bool |
| fullscreen | Fullscreens a window | bool |
| fullscreen_state | Sets the fullscreen mode for the internal client (e.g., "1 2"). Values: 0 none, 1 maximize, 2 fullscreen, 3 maximize and fullscreen | string |
| group | Sets window group properties. See group options below | string |
| maximize | Maximizes a window | bool |
| monitor | Sets the monitor on which a window should open (e.g., "1", "DP-1"). Can be suffixed with " silent" | string |
| move | Moves a floating window to the given monitor-local coordinates. See position and size below | table or string |
| no_close_for | Makes the window uncloseable with killactive for a given number of ms on open | int |
| no_initial_focus | Disables the initial focus to the window | bool |
| pin | Pins the window (i.e. show it on all workspaces). Note: pinning is ignored for non-floating windows. You most likely want to use this together with float = true | bool |
| pseudo | Pseudotiles a window | bool |
| scrolling_width | Set column width for window when starting on a workspace with the scrolling layout | float |
| size | Resizes a floating window. See position and size below | table or string |
| suppress_event | Ignores specific events. Space-separated: "fullscreen", "maximize", "activate", "activatefocus", "fullscreenoutput", "x11configurerequest" | string |
| tile | Tiles a window | bool |
| workspace | Sets the workspace on which a window should open. Can also be "unset" or suffixed with " silent" | string |
Position and size
Position and size arguments take a Lua table or a string. Value can be a number or an expression. The string argument is split at the first whitespace.
A single value, a table without exactly two elements, and any separator other than a whitespace, e.g.:"800,600", "800x600", are config errors.
Expressions
Expressions are simple shortcodes for basic information. All position variables are monitor-local. To be correctly parsed in a string argument, they should not contain spaces.
monitor_wandmonitor_hfor monitor sizewindow_xandwindow_yfor window positionwindow_wandwindow_hfor window sizecursor_xandcursor_yfor cursor position
Examples
-- Set size to x = 800, y = 600
size = { 800, 600 }
-- Same size, but via string
size = "800 600"
-- Move window center to the cursor position
move = { "cursor_x - (window_w * 0.5)", "cursor_y - (window_h * 0.5)" }
-- Align window with the left monitor border and 17 pixels below monitor center
move = { "window_w * 0.5", "(monitor_h / 2) + 17" }
-- Set windiw suze to the half monitor resolution
size = { "monitor_w * 0.5", "monitor_h * 0.5" }
-- Set max_size as half of the monitor width and height
max_size = "monitor_w*0.5 monitor_h*0.5"Dynamic effects
Dynamic effects are re-evaluated every time a property changes.
| Effect | Description | Argument | Limits |
|---|---|---|---|
| allows_input | Forces an Xwayland window to receive input even if it requests not to | bool | |
| animation | Forces an animation onto a window with an optional style (e.g., "popin", "popin 80%") | string | |
| border_color | Sets the window’s border to a color or gradient. See border_color below | gradient | |
| border_size | Sets the border size | int | |
| confine_pointer | Locks the mouse cursor to the window. Mostly useful for keeping your mouse cursor locked to one monitor during gaming | bool | |
| dim_around | Dims everything around the window. Meant for floating windows | bool | |
| decorate | Whether to draw window decorations. (default: true) | bool | |
| focus_on_activate | Whether Hyprland should focus an app that requests to be focused | bool | |
| idle_inhibit | Sets an idle inhibit rule. Modes: "none", "always", "focus", "fullscreen" | string | |
| immediate | Forces the window to allow tearing | bool | |
| keep_aspect_ratio | Forces aspect ratio when resizing with the mouse | bool | |
| max_size | Sets the maximum size for floating windows. See position and size above | table or string | |
| min_size | Sets the minimum size for floating windows. See position and size above | table or string | |
| nearest_neighbor | Forces nearest-neighbor filtering | bool | |
| no_anim | Disables animations for the window | bool | |
| no_auto_hdr | Disables AutoHDR for the window. This is useful to stop programs like foot triggering AutoHDR when they are fullscreened | bool | |
| no_blur | Disables blur for the window | bool | |
| no_dim | Disables window dimming for the window | bool | |
| no_focus | Disables focus to the window | bool | |
| no_follow_mouse | Prevents the window from being focused when the mouse moves over it when input.follow_mouse=1 is set | bool | |
| no_glow | Disables glow for the window | bool | |
| no_max_size | Removes max size limitations | bool | |
| no_screen_share | Hides the window and its popups from screen sharing by drawing black rectangles in their place | bool | |
| no_shadow | Disables shadows for the window | bool | |
| no_shortcuts_inhibit | Disallows the app from inhibiting your shortcuts | bool | |
| no_vrr | Disables VRR for the window. Only works when misc.vrr is set to 2 or 3 | bool | |
| no_wobble | Disables wobble for the window | bool | |
| no_xdg_drags | If true, will disable XDG-driven drags for the window (e.g., dragging a CSD top bar) | bool | |
| opacity | Additional opacity multiplier (e.g., "0.8" overall, "0.9 0.7" active/inactive, "1.0 0.8 0.9" active/inactive/fullscreen). Append " override" after each value to set absolute instead of multiplied | string | |
| opaque | Set decoration.active/inactive/fullscreen_opacity to 1 for this window | bool | |
| force_rgbx | Disables the window’s own transparency (not Hyprland’s given transparency, in contrast to the opaque rule) | bool | |
| persistent_size | For floating windows, internally store their size. When a new floating window opens with the same class and title, restore the saved size | bool | |
| render_unfocused | Forces the window to think it’s being rendered when it’s not visible | bool | |
| rounding | Forces X pixels of rounding, ignoring the default | int | |
| rounding_power | Overrides the rounding power for the window | float | |
| scroll_mouse | Forces the window to override input.scroll_factor | float | |
| scroll_touchpad | Forces the window to override input.touchpad.scroll_factor | float | |
| stay_focused | Forces focus on the window as long as it’s visible | bool | |
| sync_fullscreen | Whether the fullscreen mode should always be the same as the one sent to the window | bool | |
| tag | Applies a tag. Use prefix +/- to set/unset, or no prefix to toggle (e.g., "+myTag") | string | |
| tonemap | Tonemapping behavior: on (Default), off disables tonemapping, clamp clamps source luminance to target, limited uses a dynamic curve to tonemap only the top end out of bounds content | string | |
| xray | Sets blur xray mode for the window | bool |
All dynamic effects can be set with set_prop().
group window rule options
The group effect takes a string with space-separated options:
"barred"- Do not automatically group into the focused unlocked group."deny"- Do not allow the window to be toggled as or added to a group."invade"- Force open window in the locked group."lock"["always"] - Lock the group. Combine with"set"or"new"."new"- Shorthand for"barred set"."override"[other options] - Override othergrouprules."set"["always"] - Open window as a group."unset"- Clear allgrouprules.
Note
group with no options is a shorthand for group = "set".
By default, set and lock only affect new windows once.
The always qualifier makes them always effective.
border_color window rule
The border_color rule accepts a single color or a gradient:
-- Single color
border_color = "rgb(FF0000)"
-- Gradient
border_color = { colors = { "rgba(33ccffee)", "rgba(00ff99ee)" }, angle = 45 }The border_color rule can also be used in conjunction with the focus prop in order to independently set the active or inactive border color of a window.
For example:
-- Set Firefox's inactive border color to a gradient from magenta to cyan
hl.window_rule(
match = { class = "firefox", focus = false },
border_color = { colors = { "rgba(ffff00ee)", "rgba(00ffffee)" }, angle = 33 }
)Tip
Combine two rules, one with focus = true and another with focus = false, to set the active and inactive border colors of specific windows
(similarly to how general.col.active_border and general.col.inactive_border affect windows normally).
Tags
Window tags can be static or dynamic.
Dynamic tags have a suffix of *.
Check window tags with hyprctl clients.
To add a static tag, use hl.dsp.window.tag dispatcher.
To add a dynamic tag, use tag window rule.
The tag rule can only manipulate dynamic tags, and the hl.dsp.window.tag only works with static tags (dynamic tags are cleared when the dispatcher is called).
Examples
hyprctl dispatch 'hl.dsp.window.tag({ tag = "+code" })' # Add tag to current window.
hyprctl dispatch 'hl.dsp.window.tag({ tag = "-code" })' # Remove tag from current window.
hyprctl dispatch 'hl.dsp.window.tag({ tag = "code" })' # Toggle the tag of current window.
# Or target windows
hyprctl dispatch 'hl.dsp.window.tag({ tag = "+music", window = "class:Celluloid" })'-- Move kitty to 100 100 and add an anim style (named rule)
hl.window_rule({
name = "move-kitty",
match = { class = "kitty" },
move = {100, 100},
animation = "popin",
})
-- Disable blur for firefox
hl.window_rule({ match = { class = "firefox" }, no_blur = true })
-- Move kitty to the center of the cursor
hl.window_rule({
match = { class = "kitty" },
move = {"cursor_x-(window_w*0.5)", "cursor_y-(window_h*0.5)"},
})
-- Set border color to red if window is fullscreen
hl.window_rule({
match = { fullscreen = true },
border_color = "rgb(FF0000) rgb(880808)",
})
-- Set border color to yellow when title contains Hyprland
hl.window_rule({
match = { title = ".*Hyprland.*" },
border_color = "rgb(FFFF00)",
})
-- Set opacity to 1.0 active, 0.5 inactive and 0.8 fullscreen for kitty
hl.window_rule({
match = { class = "kitty" },
opacity = "1.0 override 0.5 override 0.8 override",
})
-- Set rounding to 10 for kitty
hl.window_rule({ match = { class = "kitty" }, rounding = 10 })
-- Fix pinentry losing focus
hl.window_rule({
match = { class = "(pinentry-)(.*)" },
stay_focused = true,
})
hl.window_rule({ match = { class = "footclient" }, tag = "+term" }) -- Add dynamic tag `term*`
hl.window_rule({ match = { class = "footclient" }, tag = "term" }) -- Toggle dynamic tag `term*`
hl.window_rule({ match = { tag = "cpp" }, tag = "+code" }) -- Add `code*` to windows tagged `cpp`
hl.window_rule({ match = { tag = "code" }, opacity = "0.8" }) -- Set opacity for tag `code` or `code*`
hl.window_rule({ match = { tag = "cpp" }, opacity = "0.7" }) -- `cpp`-tagged windows match both; last wins
hl.window_rule({ match = { tag = "term*" }, opacity = "0.6" }) -- Match `term*` only, not bare `term`
hl.window_rule({ match = { tag = "term" }, tag = "-code" }) -- Remove dynamic tag `code*` from `term`/`term*`
-- Or with a keybind
hl.bind("SUPER + CTRL + 2", hl.dsp.window.tag({ tag = "alpha_0.2" }))
hl.bind("SUPER + CTRL + 4", hl.dsp.window.tag({ tag = "alpha_0.4" }))
hl.window_rule({ match = { tag = "alpha_0.2" }, opacity = "0.2 override" })
hl.window_rule({ match = { tag = "alpha_0.4" }, opacity = "0.4 override" })Notes
Effects marked as dynamic are re-evaluated whenever the matching property of the window changes.
For instance, if a rule changes the border_color when a window is floating, the color reverts to default when it’s tiled again.
Effects are processed top to bottom, and the last match takes precedence.
Here, all non-fullscreen kitty windows have opacity 0.8, except when floating — those get 0.5.
All other floating windows get 0.5.
hl.window_rule({ match = { float = true }, opacity = "0.5 override 0.5 override" })
hl.window_rule({ match = { class = "kitty" }, opacity = "0.8 override 0.8 override" })Dynamically enabling / disabling / changing rules
Only named rules can be dynamically changed, enabled, or disabled.
hl.window_rule() returns a handle object:
local myRule = hl.window_rule({
name = "my-rule",
match = { class = "kitty" },
border_size = 5,
})
myRule:set_enabled(false) -- disable
myRule:set_enabled(true) -- re-enable
myRule:is_enabled() -- query status