Skip to content

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:

PropDescriptionType
classWindows with class matching RegEx[RegEx]
contentWindows with specified content type (none, photo, video, game)string
focusCurrently focused windowbool
fullscreenFullscreen (covering or non-covering) windowsbool
fullscreen_state_clientWindows with matching fullscreenstate. 0 - none, 1 - maximize, 2 - fullscreen, 3 - maximize and fullscreenint
fullscreen_state_internalWindows with matching fullscreenstate. 0 - none, 1 - maximize, 2 - fullscreen, 3 - maximize and fullscreenint
floatFloating windowsbool
groupGrouped windowsbool
initial_classWindows with initialClass matching RegEx[RegEx]
initial_titleWindows with initialTitle matching RegEx[RegEx]
modalModal windows (e.g., “Are you sure” popups)bool
pinPins the window (i.e. show it on all workspaces). Important: pinning is ignored for non-floating windowsbool
tagWindows with matching tagstring
titleWindows with title matching RegEx[RegEx]
workspaceWindows on matching workspaceworkspace selector
xdg_tagMatch a window by its xdgTag[RegEx]
xwaylandXwayland windowsbool

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.

EffectDescriptionType
centerIf the window is floating, will center it on the monitorbool
contentSets content type: "none", "photo", "video", or "game"string
floatFloats a windowbool
fullscreenFullscreens a windowbool
fullscreen_stateSets the fullscreen mode for the internal client (e.g., "1 2"). Values: 0 none, 1 maximize, 2 fullscreen, 3 maximize and fullscreenstring
groupSets window group properties. See group options belowstring
maximizeMaximizes a windowbool
monitorSets the monitor on which a window should open (e.g., "1", "DP-1"). Can be suffixed with " silent"string
moveMoves a floating window to the given monitor-local coordinates. See position and size belowtable or string
no_close_forMakes the window uncloseable with killactive for a given number of ms on openint
no_initial_focusDisables the initial focus to the windowbool
pinPins 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 = truebool
pseudoPseudotiles a windowbool
scrolling_widthSet column width for window when starting on a workspace with the scrolling layoutfloat
sizeResizes a floating window. See position and size belowtable or string
suppress_eventIgnores specific events. Space-separated: "fullscreen", "maximize", "activate", "activatefocus", "fullscreenoutput", "x11configurerequest"string
tileTiles a windowbool
workspaceSets 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_w and monitor_h for monitor size
  • window_x and window_y for window position
  • window_w and window_h for window size
  • cursor_x and cursor_y for 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.

EffectDescriptionArgumentLimits
allows_inputForces an Xwayland window to receive input even if it requests not tobool
animationForces an animation onto a window with an optional style (e.g., "popin", "popin 80%")string
border_colorSets the window’s border to a color or gradient. See border_color belowgradient
border_sizeSets the border sizeint
confine_pointerLocks the mouse cursor to the window. Mostly useful for keeping your mouse cursor locked to one monitor during gamingbool
dim_aroundDims everything around the window. Meant for floating windowsbool
decorateWhether to draw window decorations. (default: true)bool
focus_on_activateWhether Hyprland should focus an app that requests to be focusedbool
idle_inhibitSets an idle inhibit rule. Modes: "none", "always", "focus", "fullscreen"string
immediateForces the window to allow tearingbool
keep_aspect_ratioForces aspect ratio when resizing with the mousebool
max_sizeSets the maximum size for floating windows. See position and size abovetable or string
min_sizeSets the minimum size for floating windows. See position and size abovetable or string
nearest_neighborForces nearest-neighbor filteringbool
no_animDisables animations for the windowbool
no_auto_hdrDisables AutoHDR for the window. This is useful to stop programs like foot triggering AutoHDR when they are fullscreenedbool
no_blurDisables blur for the windowbool
no_dimDisables window dimming for the windowbool
no_focusDisables focus to the windowbool
no_follow_mousePrevents the window from being focused when the mouse moves over it when input.follow_mouse=1 is setbool
no_glowDisables glow for the windowbool
no_max_sizeRemoves max size limitationsbool
no_screen_shareHides the window and its popups from screen sharing by drawing black rectangles in their placebool
no_shadowDisables shadows for the windowbool
no_shortcuts_inhibitDisallows the app from inhibiting your shortcutsbool
no_vrrDisables VRR for the window. Only works when misc.vrr is set to 2 or 3bool
no_wobbleDisables wobble for the windowbool
no_xdg_dragsIf true, will disable XDG-driven drags for the window (e.g., dragging a CSD top bar)bool
opacityAdditional 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 multipliedstring
opaqueSet decoration.active/inactive/fullscreen_opacity to 1 for this windowbool
force_rgbxDisables the window’s own transparency (not Hyprland’s given transparency, in contrast to the opaque rule)bool
persistent_sizeFor floating windows, internally store their size. When a new floating window opens with the same class and title, restore the saved sizebool
render_unfocusedForces the window to think it’s being rendered when it’s not visiblebool
roundingForces X pixels of rounding, ignoring the defaultint
rounding_powerOverrides the rounding power for the windowfloat
scroll_mouseForces the window to override input.scroll_factorfloat
scroll_touchpadForces the window to override input.touchpad.scroll_factorfloat
stay_focusedForces focus on the window as long as it’s visiblebool
sync_fullscreenWhether the fullscreen mode should always be the same as the one sent to the windowbool
tagApplies a tag. Use prefix +/- to set/unset, or no prefix to toggle (e.g., "+myTag")string
tonemapTonemapping 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 contentstring
xraySets blur xray mode for the windowbool

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 other group rules.
  • "set" ["always"] - Open window as a group.
  • "unset" - Clear all group rules.

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
Last updated on