I really love the i3 window manager, my only compliant was about the standard workspace handling.


By default you can use at most 10 workspaces binding each of them to a number, optionally you can give them a name.

With a basic configuration you have something like:

1:web  2:mail ...

Pressing Mod+1 you go to web and pressing Mod+Shift+1 you move a container to it.


Luckily i3 is very customizable, through its configuration file, the i3-msg command and various external programs, in this case we are going to use the mighty dmenu.


The i3-msg command permits to do useful stuffs like:

i3-msg workspace my_workspace

to change workspace, and the self-explanatory:

i3-msg move container to workspace my_workspace

[Note: if we pass a not existing workspace a new one will be created]

We also need:

i3-msg -t get_workspaces

that prints information about workspaces in json form.


You probably know it as something magical called by the dmenu_run script, the one that permits you to run any program just pressing Mod+d.

dmenu itself does something really simple:

  • take a list of options (new-line separated) from the standard input
  • display them allowing the user to chose one
  • print the user choice on standard output

[Note: if we digit something that is not a given option it will be printed as it is]

(So dmenu_run is something like: print all the commands in user $PATH | dmenu | exec stuff from sdtin)

Put pieces together

So, what we want is define two bindings, one does:

list workspaces | dmenu | go to that workspace

and the other:

list workspaces | dmenu | move container to that workspace

Layer of abstraction

To avoid a messy configuration files Always, in life, you need to hide complexity, it can be done for example creating some bash scripts to wrap commands.

I keep mine in a bin folder in my home (many of them are generated by a python script, the same that generates the i3 configuration files, but I’m not writing about that), and I added ~/bin to $PATH.

dmenu takes a lot of arguments, about position, font, color, prompt and so on…

Let’s create a menu command that takes only the prompt character:

dmenu -b -p "$1" -fn Monaco-9 \
-nb "#000000" -nf "#999999" \
-sb "#000000" -sf "#4984bb"


Now we need a lsws command to list workspaces, i3-msg -t get_workspaces prints a json with many informations, like screen, focus and position, but we want just names.

My roommate suggested me tu use jq, but I have already here a cryptic implementation in the good old “pure” bash:

i3-msg -t get_workspaces | tr ',' '\n' | grep "name" | cut -d '"' -f 4

Finally, write the conf

Now you can put this lines in your config file:

bindsym $mod+space       exec i3-msg workspace $(lsws | menu "→")
bindsym $mod+Shift+space exec i3-msg move container to workspace \
$(lsws | menu "|→")

reload and press:

  • Mod+space to go to an existing workspace or create a new one
  • Mod+shift+space to move a container (eventually creating a new workspace)


I wrote this configuration one night, in less than half hour, just before starting to sleep and without being sure of what I was doing.

I needed some some days to be used to the different workflow, especially the longer fingers movements to switch focus (from coding to mail, than to music and than back to coding).

Before I was used to keep Mod pressed and than hit random numbers, until the apparition of the right workspace, now I have to slow down and think of which keys compose the name of the place where I want to go.