Sidebar explorer
Replace Lite’s built-in explorer when you want to organize files by project, tags, or your own rules. Start with a small file list: show the current directory’s files and open them in the main area.
This Lite-only capability requires plugin API 3.1.0. Prepare a test Space with a few files. The example deliberately lists files without implementing an expandable directory tree.
1. Declare the sidebar entry
Section titled “1. Declare the sidebar entry”Create plugin.json and src/tree.ts. Use this manifest:
{ "apiVersion": 1, "id": "example.file-list", "name": "File List", "version": "0.1.0", "requires": { "pluginApi": "3.1.0" }, "workspace": { "files": { "read": true } }, "views": [ { "id": "tree", "title": "File List", "kind": "page", "entry": "./src/tree.ts" } ], "placements": [ { "location": "sidebar/explorer", "view": "tree" } ]}sidebar/explorer makes the plugin an available sidebar browser. workspace.files.read allows file listings across the Space. It is still a page View, but unlike a normal navigation page it receives explorer state.
2. List files and handle clicks
Section titled “2. List files and handle clicks”Write this in src/tree.ts:
import type { Mount } from "@eidos.space/plugin-sdk"
const mount: Mount = async (ctx, root) => { const { explorer, fs, ui } = ctx.capabilities if (!explorer || !fs || !ui.openFile) throw new Error("Explorer unavailable") const openFile = ui.openFile const list = document.createElement("div") const status = document.createElement("p") status.setAttribute("role", "status") root.append(list, status) let revision = 0
const refresh = async () => { const current = ++revision try { const state = explorer.read() const files = await fs.list(state.rootDirectory ?? "", { recursive: false, includeDirectories: false, }) if (ctx.signal.aborted || current !== revision) return const buttons = files.map((file) => { const button = document.createElement("button") button.textContent = file.name button.style.display = "block" button.setAttribute( "aria-current", String(file.path === state.activePath) ) button.onclick = () => { void openFile(file.path).catch((error) => { status.textContent = String(error) }) } return button }) list.replaceChildren(...buttons) status.textContent = files.length ? "" : "No files in this folder." } catch (error) { if (!ctx.signal.aborted && current === revision) status.textContent = String(error) } }
ctx.subscriptions.add(explorer.watch(() => void refresh())) ctx.subscriptions.add(await fs.watch("", () => void refresh())) await refresh()}export default mountexplorer.read() provides the current directory and open file. When rootDirectory is null, the empty path means the Space root. fs.list reads one directory level; ui.openFile opens a selected file in the main area.
The two subscriptions serve different purposes: explorer.watch responds to browsing state, and fs.watch responds to filesystem changes. The former has no initial callback, so the example explicitly calls refresh().
The revision counter discards late results after rapid navigation. Failed refreshes preserve the current list and display an error.
3. Enable it in Lite and check the result
Section titled “3. Enable it in Lite and check the result”- Load
plugin.jsonin Plugin Manager and enable it for the Space. - Select File List under Plugins → Choose file explorer.
- Check that the sidebar lists files. Click one to open its configured View.
- Add or remove a test file in the Space and check that the list refreshes.
- Switch back to the built-in explorer in Plugin Manager.
Lite saves the selection per Space. If the plugin fails, Lite restores the built-in heading and tree with a retry action.
Extend the list into a tree
Section titled “Extend the list into a tree”Set includeDirectories to true to include directories, even empty ones. On expansion, call fs.list(path, { recursive: false, includeDirectories: true }) for that directory and keep expansion state in the plugin. Directory clicks should expand or navigate; only file clicks should call ui.openFile.
Read explorer.read().sort for the selected sort order; modifiedAtMs supports time sorting. This example does not implement sorting, directory navigation, or selection styling. Add those for a complete browser.
The plugin owns the entire explorer area, including its heading, search, sort controls, and file toolbar. Lite retains window navigation and application controls. Global Space text search temporarily overlays the sidebar without unmounting it. Explorer state does not grant file access; the host checks permissions separately.
See Explorer and Filesystem for interface details.