So I was typing my email address for the hundredth time this week. Actually, I'm not even exaggerating. Forms, git configs, .env files, slack messages — everywhere I go, same email, same phone number, same "Thank you so much" reply. And every time I type it fully. Like a fool.
That is when I thought — wait, I already have Kanata running. Why am I installing anything else?
First, What Is Text Expansion?
Text expansion is basically this: you type a short trigger like tysm and the tool replaces it with Thank you so much automatically. You save keystrokes, you save time, you stop making typos in your own email address (yes, that happens).
It sounds simple. And it is. But the tool you use for it matters a lot.
What Are the Alternatives?
Before I explain the Kanata approach, let me be fair and list the tools people normally use:
Espanso (Cross-platform, open source)
Probably the most popular one in the Linux community. You write YAML config files, define triggers and replacements. Works on Linux, Mac, Windows. It is actually very good. But it is another daemon running in the background, another service to manage, another thing that can break after a system update.
AutoKey (Linux only)
Python-based automation tool. You can do text expansion plus scripting. Good if you need complex logic. But the UI is a bit old, and honestly the setup is more than what most people need just to expand a few phrases.
AutoHotkey (Windows only)
The OG for Windows users. Very powerful, scripting language and all. But obviously not useful if you are on Linux.
TextExpander (Mac/Windows, paid)
Commercial product. Paid subscription. Team features. If you are in a company that already uses it, fine. But for a personal setup? Paying monthly for typing shortcuts feels wrong.
Raycast (Mac only)
Mac launcher app that includes snippets. Very polished. But again, Mac only, and it is doing many things at once — launcher, clipboard, snippets, everything.
KDE/GNOME built-ins
Some desktop environments have basic autocorrect or replacement features. Very limited. Not something you can rely on for a proper workflow.
xdotool / ydotool scripts
You can write shell scripts that type text for you. This works but it is very manual. You need to wire it to some hotkey somehow. Not a proper text expansion system.
So Why Kanata?
Here is my honest answer: because it is already running.
I use Kanata every single day for keyboard remapping — home row mods, vim navigation layer, mouse control, everything. Kanata is the first thing that starts with my session and the last thing I think about when something feels off with my keys.
And Kanata has defseq — sequence mode. Which is exactly what text expansion needs. You type a sequence of keys, and Kanata fires a macro action. That macro can type out any text you want.
No new installation. No new service. No new config format to learn. Everything stays in one place.
Also — and this matters — Kanata runs at the kernel input level. It is intercepting keystrokes before they reach the application. This means it is fast. Not "fast enough" — actually fast. There is no perceptible delay. Tools like Espanso work at a higher level and sometimes you can feel the tiny lag when a substitution happens, especially in terminals. With Kanata, it feels like you actually typed it.
How It Works
Kanata has three pieces you need for this:
1. defvirtualkeys — the action
This defines what happens when the sequence triggers. You give it a name and an action.
(defvirtualkeys tysm (macro bspc S-t h a n k spc y o u spc s o spc m u c h))The bspc at the start deletes the trigger character that was typed to activate sequence mode. The rest is just typing the expanded text letter by letter.
2. defseq — the trigger
This tells Kanata which key sequence should fire the virtual key.
(defseq tysm (t y s m d scln))So when I type t y s m followed by my leader combo (d + ;), it fires tysm.
3. A leader key
You need a way to "enter" sequence mode. In my config I use S-scln (that is Shift+;, the : key) as the leader. So the full flow is: press :, type your short code, and the expansion fires.
The Template Pattern (How I Actually Do It)
Doing all three steps manually for every expansion gets repetitive fast. So I use a deftemplate to wrap it:
(deftemplate seq (name keys action)
(defvirtualkeys $name $action)
(defseq $name ($keys d scln))
(defseq $name ($keys S-scln))
)Now adding a new expansion is one line:
(t! seq tysm (t y s m) (macro bspc S-t h a n k spc y o u spc s o spc m u c h))Clean. Readable. No duplication.
Real Examples From My Config
Here is what I actually have set up:
Identification shortcuts — typing my name, email, phone:
(t! seq id-nn (n n) (macro bspc S-s o h a n))
(t! seq id-ns (n s) (macro bspc S-s o h a n spc S-e m o n))
(t! seq id-emo (e m o) (macro bspc s o h a n e m o n (unicode @) o u t l o o k . c o m))So :nn types Sohan, :ns types Sohan Emon, :emo types my Outlook email. My phone number is also there — I never mistype it anymore.
Emoji shortcuts — because typing emoji is pain:
(t! seq em-smile (m s) (macro bspc (unicode 😄)))
(t! seq em-cry (m c) (macro bspc (unicode 😂)))
(t! seq em-heart (m h) (macro bspc (unicode ❤))):ms gives 😄, :mc gives 😂. Works everywhere because Kanata injects it as a real keypress.
Typography — proper em dash:
(t! seq ty-dash (- -) (macro bspc (unicode —)))Type -- and get —. Small thing but makes documents look much better.
What Kanata Cannot Do (Being Honest)
Kanata text expansion has some real limitations:
- No dynamic content — you cannot do something like
:dateexpanding to today's date unless you generate the config file programmatically - Multi-line is tricky — expanding into a block of text with newlines and indentation works but the config becomes messy
- No clipboard integration — tools like Espanso can pull from clipboard or ask for input. Kanata macros are static
- No GUI — Espanso has a GUI search for snippets. With Kanata you need to remember your shortcuts or read the config
So if you need dynamic snippets, forms, or a searchable snippet library, Espanso is genuinely the better tool. No shame in that.
But for static, frequently-typed strings — names, emails, phone numbers, common phrases, emoji — Kanata is perfect and you are adding zero overhead to your system.
Setting It Up From Scratch
If you already use Kanata and want to add text expansion, here is the minimal setup:
Step 1 — Create a composer.kbd file with the template and your sequences:
(deftemplate seq (name keys action)
(defvirtualkeys $name $action)
(defseq $name ($keys S-scln))
)
;; your snippets
(t! seq my-email (e m) (macro bspc y o u (unicode @) e x a m p l e . c o m))Step 2 — Include it in your main kanata.kbd:
(include composer.kbd)Step 3 — Make sure sequence mode is enabled. Add to your defcfg:
(defcfg
sequence-timeout 1000
sequence-input-mode visible-backspaced
)visible-backspaced means you see the keys you type during the sequence, then they get deleted and replaced. Feels very natural.
Step 4 — Validate and reload:
kanata --check --cfg ~/.config/kanata/kanata.kbd
systemctl --user restart kanata.serviceThat is it. Start typing.
Final Thoughts
I have tried Espanso. It works, it is good software. But every tool you add is one more thing to maintain, one more thing that can stop working after an update, one more config file in a different format.
Kanata is already there. It is already fast. It already owns your keyboard. Giving it text expansion duties too just makes sense.
My email address has not been mistyped in months. My emoji game is faster than anyone I know. And I did not install a single new thing to get there.
If you are already a Kanata user, this is genuinely a no-brainer. Give it a try.
