Live preview for Neovim — edit HTML, CSS, and JavaScript, see changes instantly in your browser.
- Live Preview — see changes instantly in your browser as you edit
- Real-time Sync — HTML, CSS, and JavaScript changes are reflected immediately
- Cursor Tracking — highlights the element under your cursor in the browser
- CSS Selection — click browser elements to jump to corresponding CSS rules
- Error Display — shows HTML/CSS validation errors inline
- WebSocket Communication — fast, persistent connection between editor and browser
- Diff-based Updates — efficient DOM updates using minimal operations
- TypeScript Support — live preview for
.tsand.tsxfiles - WebSocket Reconnection — automatic reconnection with visual status indicator
- Custom Error Handlers — configurable HTML/CSS validation rules
- Mobile Preview — QR code generation for testing on mobile devices
- Debounced Updates — efficient bandwidth usage with 100ms debounce
render.nvim
┌──────────────────────────────────────────────────────────────────┐
│ │
│ ┌──────────┐ HTTP ┌──────────┐ WebSocket ┌──────────┐ │
│ │ Neovim │ ────────→ │ Node.js │ ──────────→ │ Browser │ │
│ │ Plugin │ │ Server │ │ Client │ │
│ └────┬─────┘ └────┬─────┘ └────▲─────┘ │
│ │ │ │ │
│ │ subprocess │ serve HTML + inject │ │
│ │ │ diff updates │ │
│ ▼ ▼ │ │
│ ┌──────────┐ ┌──────────┐ │ │
│ │ Python │ │ AST │ DOM patching │ │
│ │ Bridge │ │ Parser │ ───────────────────┘ │
│ └──────────┘ └──────────┘ │
│ htmlparser2 │
│ postcss │
└──────────────────────────────────────────────────────────────────┘
| Layer | Role | Technology |
|---|---|---|
| Neovim | Editor integration, autocmds, debounce | Vimscript / Lua |
| Python | Process bridge, HTTP client | Python 2.7+ / 3.x |
| Node.js | HTTP + WebSocket server, file serving | Node.js 12+ |
| Parser | HTML AST diffing, CSS validation | htmlparser2, postcss, csslint |
| Browser | Live DOM updates, element highlighting | Vanilla JS (zero deps) |
- Neovim or Vim with Python support
- Node.js (v12 or higher)
- Python 2.7+ or 3.x
{
'hishantik/render.nvim',
ft = { 'html', 'css', 'javascript', 'typescript', 'tsx' },
build = function()
local plugin_dir = vim.fn.stdpath('data') .. '/lazy/render.nvim'
vim.fn.system('npm install --prefix ' .. plugin_dir .. '/server')
end,
}Plug 'hishantik/render.nvim'After installation:
cd ~/.local/share/nvim/site/pack/render/start/render.nvim
npm install --prefix serveruse 'hishantik/render.nvim'After installation:
cd ~/.local/share/nvim/site/pack/packer/start/render.nvim
npm install --prefix servergit clone https://github.com/hishantik/render.nvim.git ~/.config/nvim/plugged/render.nvim
cd ~/.config/nvim/plugged/render.nvim/server
npm installpkg install neovim nodejs termux-open iproute2
mkdir -p ~/.config/nvim/plugged
git clone https://github.com/hishantik/render.nvim.git ~/.config/nvim/plugged/render.nvim
cd ~/.config/nvim/plugged/render.nvim/server
npm install --ignore-scripts
termux-openis required for opening URLs on Android.--ignore-scriptsskips native C++ compilation that fails without NDK.iproute2provides theipcommand for LAN IP detection.
On Termux, /tmp is read-only. Configure the log path:
vim.g.render_server_log = vim.fn.stdpath('data') .. '/render_server_logfile'| Command | Description |
|---|---|
:Render |
Start the server and open browser |
:RenderStop |
Stop the server |
:RenderReload |
Force reload the page |
:RenderEval {code} |
Execute JavaScript in browser |
:RenderMobile |
Open QR code page for mobile preview |
:RenderConfigure {type} {rules} |
Configure validation rules |
:RenderConfig |
Open config file (init.vim/init.lua) |
:e index.html
:Render
" Edit your files — changes appear instantly in the browser
:RenderStop.ts and .tsx files are automatically supported. Just open and :Render as usual.
Test on mobile devices connected to the same network:
-- In init.lua
vim.g.render_server_allow_remote_connections = 1:Render
:RenderMobile " Opens QR code page — scan with your phone| Option | Default | Description |
|---|---|---|
g:render_browser_command |
0 |
Browser launch command (0 = auto) |
g:render_auto_start_browser |
1 |
Auto-open browser on start |
g:render_auto_start_server |
1 |
Auto-start Node server |
g:render_eval_on_save |
1 |
Evaluate JS on save |
g:render_refresh_on_save |
0 |
Reload page on save |
g:render_server_port |
pid-based |
Server port number |
g:render_server_path |
http://127.0.0.1 |
Server URL |
g:render_server_log |
/tmp/render_server_logfile |
Server log path |
g:render_html_rules |
{} |
Custom HTML validation rules |
g:render_csslint_rules |
[] |
Custom CSSLint rules |
g:render_server_allow_remote_connections |
0 |
Allow mobile/network access |
vim.g.render_browser_command = 'google-chrome'
vim.g.render_auto_start_browser = 0
vim.g.render_refresh_on_save = 1
vim.g.render_server_allow_remote_connections = 1
vim.g.render_server_port = 8080
vim.g.render_html_rules = {
['tag-pair'] = true,
['doctype-first'] = false,
}
vim.g.render_csslint_rules = { 'compatible-vendor-prefixes' }let g:render_browser_command = 'google-chrome'
let g:render_auto_start_browser = 0
let g:render_refresh_on_save = 1
let g:render_server_allow_remote_connections = 1
let g:render_server_port = 8080
let g:render_html_rules = {
\ 'tag-pair': v:true,
\ 'doctype-first': v:false
\}
let g:render_csslint_rules = ['compatible-vendor-prefixes']Use :RenderConfig to quickly open your config file.
- Server Start — Python bridge launches Node.js server
- File Serving — HTML parsed into AST, client scripts injected
- Change Detection — Vim events trigger content sync (debounced 100ms)
- Diff Updates — server computes minimal DOM operations
- Broadcast — changes sent via WebSocket to browser
- Apply — client updates DOM with minimal operations
Automatic handling with exponential backoff:
- Connection lost → status indicator shows "reconnecting..."
- Exponential backoff: 1s, 2s, 4s, 8s... up to 30s max
- Connection restored → status indicator disappears
| Operation | Latency |
|---|---|
| Local round-trip | 5-20ms |
| Initial HTML parse | 50-200ms |
| Diff update | 1-5ms |
| Debounce delay | 100ms |
Hishantik
- GitHub: hishantik
- Repository: render.nvim
Contributions are welcome! Feel free to submit issues and pull requests.
Originally based on bracey.vim by Mason Clayton.