You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The ability to register a keybind with multiple actions that happen in sequence.
Every syntax I can think of complicates parsing binding actions which by this point can contain just about anything. So, instead, I thought of something different. Here is some proposed syntax:
The chain key would cause the parsed action to be appended to the most recently bound action. Therefore, starting with ignore is a good way to ensure that you're starting a new chain and to establish the key. You could just as easily start with toggle_fullscreen here. The chain will inherit the flags of the most recently bound action (performable, all, global, etc.).
Note that chaining will NOT work with unbind. Unbind explicitly removes a binding so chaining cannot attach to it.
This adds a bit of verbosity but enables a bunch of good use cases for us:
Doesn't complicate parsing actions, there's no ambiguity, quotations, escapes, etc. needed to support this.
chain makes it pretty clear something special is going on. I thought about using a sigil like | or |> or something but that makes it pretty special. chain is pretty clear, I think.
Compatible with CLIs without ugly quoting, --keybind=ctrl+shift+f=unbind --keybind=chain=foo --keybind=chain=bar
Easy to make it a configuration error to specify any flags on chains
I know its not ideal and the syntax is a bit odd at first glance, but I think its the best option we've got given the constraints.
This initial proposed issue would send all keybinds to the same target surface that triggered it. Importantly, this omits some use cases, such as creating a new window, sending text to it, and then pressing enter. I think that requires some more thought on how we can fit that in and Im happy to see a new discussion about that.
Reacted by Daniel Wennberg, Shinebayar G and Emmanuel Lebeaupin
The chaining must happen with the named table to apply the chain to. If no named table is given, it assumes the default table. This is a bit of an implementation detail but simplifies our implementation a lot (allows us to attach chains to binding sets internally). I think we can work around this limitation in the future since I suspect it'll be a bit of a footgun.
For anyone finding this and being confused about how chain works with tables, what is documented here is no longer true – it has been changed in #10039, and you no longer need the chain prefix.
Activity
mitchellh commentedon Dec 18, 2025
This initial proposed issue would send all keybinds to the same target surface that triggered it. Importantly, this omits some use cases, such as creating a new window, sending text to it, and then pressing enter. I think that requires some more thought on how we can fit that in and Im happy to see a new discussion about that.
mitchellh commentedon Dec 22, 2025
Adding more details to this for key sequences:
In this scenario,
chainapplies to the most recent binding, including sequences. So this would chainctrl+a>b>cto create a new window and a new tab.And for tables:
The chaining must happen with the named table to apply the chain to. If no named table is given, it assumes the default table. This is a bit of an implementation detail but simplifies our implementation a lot (allows us to attach chains to binding sets internally). I think we can work around this limitation in the future since I suspect it'll be a bit of a footgun.
Chained Keybinds (ghostty-org#10015)
rc/ghostty: add commented-out remote tab keybind for Ghostty 1.3
ghostty, fish: work around chained keybind cross-surface limitation
ghostty, fish: work around chained keybind cross-surface limitation
ghostty, fish: route mosh-tab keybind through tmux run-shell
ghostty: add cmd+shift+t mosh tab via boo + skhd
kirelagin commentedon Apr 18, 2026
For anyone finding this and being confused about how
chainworks with tables, what is documented here is no longer true – it has been changed in #10039, and you no longer need the chain prefix.