π boundary.nvim
October 23, 2025 Β· View on GitHub
See React/RSC 'use client' boundaries at the call site.
Inspired by the VS Code extension RSC Boundary Marker, brought to Neovim.
If this helps, please β star the repo!
πΈ Examples
default
custom marker text
custom hl color
β¨ Features
- Detects components that declare
'use client'. - Shows a right-aligned
'use client'marker as virtual text next to each JSX usage. - Auto-watches buffers to keep markers in sync (or use a manual refresh).
- Handles default / named / aliased imports and directory imports resolving to
index.
π Quick Start
With lazy.nvim:
{
"Kenzo-Wada/boundary.nvim",
branch = "release",
opts = {
auto = true, -- automatic refresh enabled by default
-- marker_text = "'use client'",
},
}
Manual refresh:
:BoundaryRefresh
π¦ Installation
Works with any plugin manager. Once on your runtimepath, just:
require("boundary").setup()
All options are optional; sensible defaults are provided.
βοΈ Configuration
require("boundary").setup({ ... }) accepts:
| Option | Type | Default | Description |
|---|---|---|---|
marker_text | string | 'use client' | Virtual text displayed next to each matching JSX usage. |
marker_hl_group | string | BoundaryMarker | Highlight group for the marker (links to Comment by default). |
hover_only | boolean | false | Only display markers when the cursor is on the matching line. |
directives | string[] | { "'use client'", '"use client"' } | Directive strings recognized in imported files. |
search_extensions | string[] | { ".tsx", ".ts", ".jsx", ".js" } | File extensions tried when resolving bare relative imports. |
filetypes | string[] | { "javascript", "javascriptreact", "typescript", "typescriptreact" } | Filetypes that trigger scanning. |
max_read_bytes | number | 4096 | Max bytes read from each import when scanning for directives. |
auto | boolean | true | Enable automatic refresh via autocommands. |
events | string[] | { "BufEnter", "BufWritePost", "TextChanged", "InsertLeave" } | Events used to refresh when auto is true. |
π Usage
- Import a local component in a supported React file (
.tsx,.jsx, β¦). - Ensure the componentβs file begins with a
'use client'(or"use client"). - Edit or save (with
auto = true) or run:BoundaryRefreshto populate markers.
// components/Button.tsx
"use client";
export default function Button() {
return <button>Click me</button>;
}
// app/page.tsx
import Button from "../components/Button";
export default function Page() {
return (
<div>
<Button /> 'use client' // boundary.nvim shows virtual text here
</div>
);
}
π‘ Auto-refresh events
Default events:
BufEnterβ when entering a bufferBufWritePostβ after savingTextChanged/InsertLeaveβ during edits / leaving insert mode
Tune this list to balance responsiveness and cost.
π§° Commands
:BoundaryRefreshβ Re-scan the current buffer.
π€ Contributing
Issues and PRs are welcome!
We label good first issue to help newcomers get started.
π License
MIT