Skip to content
Embed Neovim in your browser.
TypeScript Lua Vim script HTML JavaScript
Branch: master
Clone or download
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github/workflows Configure CI job that runs vimscript linter using GitHub Actions Oct 23, 2019
autoload Cleanup all vimscript lint warnings Oct 23, 2019
lua Force exit if :qall doesn't work Nov 2, 2019
plugin Add selenium tests Sep 3, 2019
src background.ts: Fix browserAction being reset on firenvim close Nov 14, 2019
static Remove svg files Oct 13, 2019
tests Add monaco support Nov 14, 2019
.appveyor.yml ci: make sure to use same node/npm versions on windows/osx/linux Oct 23, 2019
.gitignore Add package.lock Aug 8, 2019
.travis.yml ci: make sure to use same node/npm versions on windows/osx/linux Oct 23, 2019
.vintrc.yaml Add configuration for Vint vimscript linter Oct 23, 2019 remove redundant `What I expected:` line Oct 26, 2019 Add build instructions to, add Mar 8, 2019 Improve config description wording Nov 12, 2019 Turn native messenger into a neovim plugin Jul 17, 2019 tell users to revert the changes they made Oct 4, 2019
firenvim.gif Add firenvim.gif to readme Mar 19, 2019
package-lock.json build(deps): bump @types/jest from 24.0.22 to 24.0.23 Nov 12, 2019
package.json build(deps): bump @types/jest from 24.0.22 to 24.0.23 Nov 12, 2019
tsconfig.json Fix frames reappearing when typing text in elements modifies DOM Nov 5, 2019
tslint.json NeovimFrame.ts: take altGr into account Nov 11, 2019
webpack.config.js Remove svg files Oct 13, 2019

Firenvim Build Status Build status Total alerts Vint

Turn your browser into a Neovim client.

Firenvim demo

How to use

Just click on any textarea and it will be immediately replaced by an instance of Firenvim. When you want to set the content of the now hidden textarea to the content of the Neovim instance, just :w. If you want to close the Firenvim overlay and return to the textarea run :q. If you selected an element where you expected the Firenvim frame to appear and it didn't, try pressing <C-e>.


Before installing anything please read and make sure you're okay with everything mentioned. In the event you think of a way to compromise Firenvim, please send me an email (you can find my address in my commits).


  1. Make sure you are using Neovim 0.4.0 or later. This plugin will not work with vanilla VIM or Vimr.

  2. Check if the luabitop package is available by running :lua,1) in Neovim. If this throws an error, you will need to install it.

  3. Install Firenvim as a VIM plugin as you would any other, then run the built in post-install hook script.

    • vim-plug

      Plug 'glacambre/firenvim', { 'do': function('firenvim#install') }
    • dein

      call dein#add('glacambre/firenvim', { 'hook_post_update': function('firenvim#install') })
    • minpac

      call minpac#add('glacambre/firenvim', { 'do': function('firenvim#install') })
    • pathogen, vundle, others

      Install the plugin as you usually would, then run this shell command:

      $ nvim --headless "+call firenvim#install(0) | q"
  4. Finally install Firenvim in your browser from Mozilla's store or Google's.

From source


Installing from source requires NodeJS, npm, and Neovim >= 0.4.

Cross-browser steps

First, install Firenvim like a regular vim plugin (either by changing your runtime path manually or by using your favourite plugin manager).

Then, run the following commands:

git clone
cd firenvim
npm install
npm run build
npm run install_manifests

These commands should create three directories: target/chrome, target/firefox and target/xpi.

Firefox-specific steps

Go to about:addons, click on the cog icon and select install addon from file (note: this might require setting xpinstall.signatures.required to false in about:config).

Google Chrome/Chromium-specific steps

Go to chrome://extensions, enable "Developer mode", click on Load unpacked and select the target/chrome directory.

Other browsers

Other browsers aren't supported for now. Opera, Vivaldi and other Chromium-based browsers should however work just like in Chromium and have similar install steps. Brave and Edge might work, Safari doesn't (it doesn't support Webextensions).


Firenvim currently requires the following permissions for the following reasons:

Configuring Firenvim

Configuring the browser addon behavior

You can configure the keybinding to manually trigger Firenvim (<C-e> by default) in the shortcuts menu in about://addons on Firefox, or in chrome://extensions/shortcuts on Chrome.

The rest of Firenvim is configured by creating a variable named g:firenvim_config in your init.vim. This variable is a dictionary containing the key "localSettings". g:firenvim_config["localSettings"] is a dictionary the keys of which have to be a Javascript pattern matching a URL and the values of which are dictionaries containing settings that apply for all URLs matched by the Javascript pattern. When multiple patterns match a same URL, the pattern with the highest "priority" value is used.

Here's an example g:firenvim_config that matches the default configuration:

let g:firenvim_config = {
    \ 'localSettings': {
        \ '.*': {
            \ 'selector': 'textarea',
            \ 'priority': 0,
        \ }
    \ }
\ }

This means that for all URLs (".*"), textareas will be turned into Firenvim instances. Here's an example that will make Firenvim not take over any elements, except for Github's textareas:

let g:firenvim_config = {
    \ 'localSettings': {
        \ '.*': {
            \ 'selector': '',
            \ 'priority': 0,
        \ },
        \ 'github\.com': {
            \ 'selector': 'textarea',
            \ 'priority': 1,
        \ },
    \ }
\ }

Note that even with this config, manually triggering Firenvim will still work on every page.

Since Firenvim just uses the BufWrite event in order to detect when it needs to write neovim's buffers to the page, Firenvim can be made to automatically synchronize all changes like this:

au TextChanged * ++nested write
au TextChangedI * ++nested write

Depending on how large the edited buffer is, this could be a little slow. A better approach would then be to delay writes, like this:

let g:dont_write = v:false
function! My_Write(timer) abort
	let g:dont_write = v:false

function! Delay_My_Write() abort
	if g:dont_write
	let g:dont_write = v:true
	call timer_start(10000, 'My_Write')

au TextChanged * ++nested call Delay_My_Write()
au TextChangedI * ++nested call Delay_My_Write()

Configuring Neovim's behavior

You can detect when Firenvim connects to Neovim with the following code:

function! OnUIEnter(event)
    let l:ui = nvim_get_chan_info(a:event.chan)
    if has_key(l:ui, 'client') && has_key(l:ui.client, "name")
        if == "Firenvim"
            set laststatus=0
autocmd UIEnter * call OnUIEnter(deepcopy(v:event))

Similarly, you can detect when Firenvim disconnects from a Neovim instance with the UILeave autocommand.

If you want to use different settings depending on the textarea you're currently editing, you can use autocommands to do that too. All buffers are named like this: domainname_page_selector.txt (see the toFileName function). This means that you can for example set the file type to markdown for all GitHub buffers:

au BufEnter github.com_*.txt set filetype=markdown


The main issue with Firenvim is that some keybindings (e.g. <C-w>) are not overridable. I circumvent this issue by running a patched version of Firefox.

You might also like

  • Tridactyl, provides vim-like keybindings to use Firefox. Also lets you edit input fields and text areas in your favourite editor with its :editor command.
  • GhostText, lets you edit text areas in your editor with a single click. Requires installing a plugin in your editor too. Features live updates!
  • Textern, a Firefox addon that lets you edit text areas in your editor without requiring you to install a plugin in your editor.
  • withExEditor, same thing as Textern, except you can also edit/view a page's source with your editor.
You can’t perform that action at this time.