Skip to content

Window Rules

Syntax

hl.window_rule({
    name? = str,
    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)str
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 tagstr
titleWindows with title matching RegEx[RegEx]
workspaceWindows on matching workspace. Can be id, "name:string" or a workspace selectorworkspace 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"str
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 fullscreenstr
groupSets window group properties. See group options belowstr
maximizeMaximizes a windowbool
monitorSets the monitor on which a window should open (e.g., "1", "DP-1"). Can be suffixed with " silent"str
moveMoves a floating window to the given monitor-local coordinates (e.g., {100, 200}, {"(cursor_x-(window_w*0.5))", "(cursor_y-(window_h*0.5))"})str
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 (e.g., {800, 600}, {"(monitor_w*0.5)", "(monitor_h*0.5)"})str
suppress_eventIgnores specific events. Space-separated: "fullscreen", "maximize", "activate", "activatefocus", "fullscreenoutput", "x11configurerequest"str
tileTiles a windowbool
workspaceSets the workspace on which a window should open. Can also be "unset" or suffixed with " silent"str

Expressions

Expressions are used with move and size. They are space-separated (no spaces within each expression). All position variables are monitor-local.

  • 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

Example expressions:

move = {"window_w * 0.5", "(monitor_h / 2) + 17"}
size = {"monitor_w * 0.5", "monitor_h * 0.5"}

Dynamic effects

Dynamic effects are re-evaluated every time a property changes.

EffectDescriptionArgumentLimits
persistent_sizeFor floating windows, internally store their size. When a new floating window opens with the same class and title, restore the saved sizebool
no_max_sizeRemoves max size limitationsbool
stay_focusedForces focus on the window as long as it’s visiblebool
animationForces an animation onto a window with an optional style (e.g., "popin", "popin 80%")str
border_colorSets the window’s border to a color, gradient, or two gradients (active/inactive). E.g., "rgb(FF0000)", { colors = {"rgba(33ccffee)", "rgba(00ff99ee)"}, angle = 45 }gradient
idle_inhibitSets an idle inhibit rule. Modes: "none", "always", "focus", "fullscreen"str
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 multipliedstr
tagApplies a tag. Use prefix +/- to set/unset, or no prefix to toggle (e.g., "+myTag")str
max_sizeSets the maximum size for floating windows (e.g., {800, 600})vec2
min_sizeSets the minimum size for floating windows (e.g., {200, 150})vec2
border_sizeSets the border sizeint
roundingForces X pixels of rounding, ignoring the defaultint
rounding_powerOverrides the rounding power for the windowfloat
allows_inputForces an Xwayland window to receive input even if it requests not tobool
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
keep_aspect_ratioForces aspect ratio when resizing with the mousebool
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_shadowDisables shadows for the windowbool
no_glowDisables glow for the windowbool
no_shortcuts_inhibitDisallows the app from inhibiting your shortcutsbool
no_screen_shareHides the window and its popups from screen sharing by drawing black rectangles in their placebool
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
opaqueForces the window to be opaquebool
force_rgbxForces Hyprland to ignore the alpha channel entirelybool
sync_fullscreenWhether the fullscreen mode should always be the same as the one sent to the windowbool
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 contentstr
immediateForces the window to allow tearingbool
xraySets blur xray mode for the windowbool
render_unfocusedForces the window to think it’s being rendered when it’s not visiblebool
scroll_mouseForces the window to override input.scroll_factorfloat
scroll_touchpadForces the window to override input.touchpad.scroll_factorfloat
confine_pointerLocks the mouse cursor to the window. Mostly useful for keeping your mouse cursor locked to one monitor during gamingbool

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.

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