Use the Lit language server
The Lit language server makes your editor understand your components: it
completes their tags, attributes, properties and events in html templates,
shows their docs on hover, types your event handlers, and reports a handler
that doesn’t fit its event. It reads your sources as you type, so a
component’s docs are current before you save, and it works in a project
without Vite. Language server lists everything
it does.
Set it up in VS Code
Section titled “Set it up in VS Code”-
Build the extension in a checkout of the repository:
Terminal window pnpm installcd packages/vscodepnpm run build && pnpm run packageThis writes
lit-devtools-<platform>.vsixfor your machine, with the server bundled in. -
In VS Code, run Extensions: Install from VSIX… from the command palette and pick that file.
-
Open a project and hover a component’s tag in an
htmltemplate.
The extension runs the project’s own @oddsquad/lit-language-server when the
project installs it, directly or through @oddsquad/lit-devtools, so the
version matches the project, and the bundled copy otherwise. To run a different build, point the lit.server.path setting at
its dist/bin.mjs. Lit: Restart Language Server picks the server again,
and the Lit Language Server output channel says which one started.
The type hints on event handlers are inlay hints, which VS Code shows unless
editor.inlayHints.enabled is off.
Set it up in Zed
Section titled “Set it up in Zed”-
Build the server in a checkout of the repository:
Terminal window pnpm installcd packages/lit-language-server && pnpm run build -
In Zed, run zed: install dev extension from the command palette and pick
packages/zed. Zed compiles it, which needs Rust from rustup. -
Point Zed at the server you built, in its settings:
~/.config/zed/settings.json {"lsp": {"lit-language-server": {"binary": {"path": "/path/to/lit-devtools/packages/lit-language-server/dist/bin.mjs"}}}}Inside the repository itself the extension finds the server without this.
-
Open a project and hover a component’s tag in an
htmltemplate.
Once the package is published, a project that installs it as a dev dependency is found without the setting, and the extension otherwise installs the latest release itself.
The type hints on event handlers are inlay hints, which Zed shows when
"inlay_hints": {"enabled": true} is set.
Configure it
Section titled “Configure it”The server needs no settings. To change what it reads or how loud a problem
is, set languageServer in your Vite config:
import {defineConfig} from 'vite';import {litPlugin} from '@oddsquad/lit-devtools/vite';
export default defineConfig({ plugins: [ litPlugin({ languageServer: { diagnostics: {css: 'off', 'event-type': 'warning'}, }, }), ],});In a project without Vite, put the same settings in a
lit-devtools.config.ts (or .mts, .js, .mjs, .json) next to its
package.json:
export default { languageServer: { scan: ['src', 'lib'], cssTemplateTags: ['css', 'styles'], },};When a package has both, the Vite config’s languageServer wins as a whole,
and the config file gets a warning saying it’s ignored: the two are never
merged key by key. A .ts config file needs Node 22.18 or later; a .js or
.json one works on any. The
settings reference lists every key.
Check it in CI with Oxlint
Section titled “Check it in CI with Oxlint”The same problems can fail a lint run. Install @oddsquad/lit-devtools next
to Oxlint and extend its Oxlint plugin’s recommended config, which turns each
rule on at the severity the editor gives it:
npm install -D oxlint @oddsquad/lit-devtoolsimport {defineConfig} from 'oxlint';import litDevtools from '@oddsquad/lit-devtools/oxlint';
export default defineConfig({ extends: [litDevtools.configs.recommended], rules: {'lit-devtools/css': 'off'},});Rules set next to extends win, as lit-devtools/css does here. With
Vite+, the same object goes under lint in vite.config.ts. A project that
wants only the rules installs @oddsquad/oxlint-plugin-lit and imports from
it instead. In an .oxlintrc.json, list the plugin and its rules yourself:
{ "jsPlugins": ["@oddsquad/lit-devtools/oxlint"], "rules": {"lit-devtools/event-type": "error", "lit-devtools/css": "warn"}}- Oxlint’s config decides each rule’s severity; the
diagnosticssetting is for the editor only. The other settings, such asscan, apply to both. - Silence one spot with Oxlint’s own comment,
// oxlint-disable-next-line lit-devtools/event-type. - Oxlint reads JavaScript and TypeScript files, so problems in HTML, Astro and MDX pages still show only in the editor.
- The first file waits while the plugin reads the workspace, once per run.
Use it in a monorepo
Section titled “Use it in a monorepo”Open the monorepo at its root. The server finds the workspace from a
pnpm-workspace.yaml or a workspaces field in package.json, and reads
every package in it:
- Each package is read with its own settings and its own Vite config, so its aliases apply.
- A component can extend a base class from another workspace package; its inherited attributes and properties show up.
- A tag from a published library completes only in the packages that depend on that library.
When nothing shows up
Section titled “When nothing shows up”- Check that the server started: in VS Code, the Lit Language Server output channel; in Zed, dev: open language server logs.
- After rebuilding the server, restart it: Lit: Restart Language Server in VS Code, editor: restart language server in Zed.
- Check the settings file for a warning on its first line: a mistake there is reported, not thrown.
- With another Custom Elements Manifest server installed, such as the Web Components Language Server, hovers appear twice; disable one.