# Add "superpin" or "sticky" to hyprland as super + grave (floating and tiled windows move with workspaces)

> Source: <https://gist.github.com/majamin/d779fb1c1845e5ec3723f9c29d1df5e4>
> Published: 2026-05-24 00:15:32+00:00

superpin.lua

      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      
Learn more about bidirectional Unicode characters

 
    Show hidden characters

local superpin_windows = {}

---add or remove window from superpin list

---@param target_win HL.Window

local function toggle_superpin(target_win)

  if superpin_windows[target_win.address] then

    superpin_windows[target_win.address] = nil

    hl.notification.create({ text = "superpin off: " .. target_win.title, timeout = 2000 })

  else

    superpin_windows[target_win.address] = {

      win = target_win,

      at   = target_win.at,

      size = target_win.size,

    }

    hl.notification.create({ text = "superpin on: " .. target_win.title, timeout = 2000 })

  end

end

-- watch for workspace changes to ensure superpin windows follow

hl.on("workspace.active", function(ws)

  for _, stored in pairs(superpin_windows) do

    hl.dispatch(hl.dsp.window.move({ workspace = ws.id, window = stored.win }))

  end

end)

-- clean up

hl.on("window.close", function(win)

  superpin_windows[win.address] = nil

end)

-- toggle superpin

hl.bind("SUPER + grave", function()

  local win = hl.get_active_window() --[[@as HL.Window]]

  toggle_superpin(win)

end)

-- helps restore original position and size

hl.on("window.update_rules", function(win)

  if win.floating then

    local stored = superpin_windows[win.address]

    if stored and stored.at and stored.size then

      hl.dispatch(hl.dsp.window.move({ x = stored.at.x, y = stored.at.y, window = win }))

      hl.dispatch(hl.dsp.window.resize({ x = stored.size.x, y = stored.size.y, window = win }))

    end

  end

end)
