All versions since 0.22.0
0.22.0
The Lit DevTools now run in any server. createLitDevtools() serves the
panel from your app’s own origin, without Vite or a second port, and docks it
in a drawer along the bottom of the page. An Elysia example puts it next to
server rendering on Bun, and a forms example shows form-associated elements
with :state(). The panel takes its colours, type and code font from the Lit
Design System, and agents can read the docs as Markdown. Nothing needs action
to upgrade.
Added
- The Lit DevTools in any server.
createLitDevtools()from@oddsquad/vite-plugin-lit/devframegives a server without Vite (Elysia, Hono,Bun.serve, a SvelteKit or Next.js route) one request handler for the panel, its page script and its RPC on the app’s own origin, with nolit-devtools devprocess or second port. - The panel docks in the page. With
createLitDevtools(), a Lit button in the corner opens the panel in a resizable drawer along the bottom of the page, and picking an element opens it there instead of in another tab. It reopens as you left it; passdock: falseto keep it a tab. - An Elysia example, without Vite. A guestbook that Elysia renders on Bun
with
@lit-labs/ssr, streams, hydrates and keeps live over a WebSocket, with a form that works before it hydrates. It shows the hydration traps to avoid, attaches the standalone Lit DevTools, and builds into a single executable. - A forms example. A text field, a switch and a star rating extend one
FormControlbase class and work in a plain<form>: they submit withFormData, block submit while invalid, reset, and follow a disabled fieldset. Each shows what it is doing as:state()custom states for CSS to style on. - Every docs page has a Markdown copy. Append
index.mdto a page’s address, follow itsrel="alternate"link, or sendAccept: text/markdownto get the page as Markdown, with Link headers pointing to llms.txt and the sitemap. - An agent skill for the plugin. Agents that read Agent Skills Discovery
find it at
/.well-known/agent-skills/on the docs site: setup, CSS delivery, hot-patch failures and the DevTools MCP server in one file. - A setup prompt for coding agents. The Installation page has a prompt to copy into your agent; it installs the plugin, adds it to the Vite config and registers the types, then lists what it changed.
- Browser agents can search and read the docs through WebMCP. In a
browser with WebMCP, the docs offer
search_docs,read_docs_pageandopen_docs_pagetools.
Changed
- The panel takes the Lit Design System’s theme. Its colours, focus ring, motion and type scale come from the same tokens as the docs, in both colour schemes. Corners stay square; pills, status dots and the Timeline’s layer chips are round.
- The panel sets code in Lilex. Values, source locations, timings and the Timeline’s lanes use the Lilex monospace instead of the system one.
- The Updates count no longer looks like an error. The number on the Updates tab is blue instead of red; the orange count on Components still flags Lit warnings.
- A lighter split between the tree and the details. The divider in the Components view is a hairline that lights up blue under the pointer, and is just as easy to drag.
- The docs moved to lit-devtools.oddsquad.dev. Links in the DevTools panel, the README and the extension listing point there, and the old oddcelot.github.io/vite-plugin-lit/ addresses redirect.
Fixed
- A re-created child keeps its own listeners and lookups. When a parent
edit makes Lit re-create a child,
#privatearrow-function listeners and fields the child sets inconnectedCallback, such as a form it looks up, stay the new element’s instead of being overwritten by the old one’s. - Dark outlines and nulls are legible. In the dark scheme, unchecked
switches, inputs and outlined buttons have a visible outline, and
nullvalues in the Properties view no longer fade into the background. - The
./buildand./astro/*exports have types on JSR. JSR no longer warns that these entry points have no type declarations, and installing the package from JSR types them like the others.
0.23.0
The Components panel now shows what a component keeps to itself: its
#private fields, readable and editable under the dev server, and the custom
states, form value and validity of a form-associated element. The tree no
longer has a Live switch; it stays live, holds still under the pointer and
paces itself on busy pages. The panel’s rows, colours and fields got easier
to read and hit, and the docs run the examples live beside the panel. Nothing
needs action to upgrade.
Added
- The Components panel shows and edits a component’s
#privatefields. Under the dev server, a Private section after State lists each native#privatefield as#namewith its live value. A string, number or boolean has the same edit button as a property, kept as an override you can switch off, pin across reloads or remove, and the component re-renders with it. Agents read them throughlit_component-detailsand set them throughlit_set-prop. They come from thehmr.privateFieldsrewrite, so turning that off hides them. - The Components details show custom states and form values. An element
that calls
attachInternals()gets an Internals section with the states:state()matches, the value it last passed tosetFormValue(), and its validity and validation message, kept live as they change. Agents read the same throughlit_component-details. - Try the examples live in the docs. The Demos page opens flame, Web Awesome, Fernhouse, CSS, Tailwind, Forms and the tutorial’s app running in your browser with the DevTools panel under them, with nothing to boot and a zoom control; StackBlitz is one switch away for editing their files.
Changed
- The live component tree keeps up with busy pages without slowing them. A page that changes constantly still gets a fresh tree every so often, rebuilds space themselves out by how long the last one took, and none run while the Timeline is recording.
- The Components toolbar sets Pick apart from the switches. Pick is a crosshair beside the tag filter, and Flash and Anatomy, which stay on until you turn them off, sit together as one group at the right.
- Tree and list rows are easier to hit. Rows in the component tree and the timeline list are 24px tall, the minimum target size WCAG asks for.
- Element references and functions no longer share a colour. Tags and element refs are teal, functions stay blue, in both colour schemes.
Fixed
- A link to a component opens its details even before the page is ready.
Opening the panel on
#tab=components&component=Nbefore the page connected, or before its components defined, no longer shows “This element is no longer in the page” for an element that is there. - Settings’ About shows the page’s Lit even when opened first. A panel opened on the Settings tab before the page connected said “lit: not detected” until the tab was reopened; it now lists the page’s Lit packages as soon as the page connects.
- Disabled fields no longer pass for empty ones. A disabled select or input is dimmed, filled and dash-outlined with a not-allowed cursor, and the tags of a multi-select read as live rather than greyed out.
- The Lit tab’s footer buttons work in a narrow panel. A long notice no longer covers its own “Don’t show again” or “Not now”: the text is cut short instead, and shows whole when you hover it.
Removed
- The Components tab’s Live toggle is gone; the tree is always live. It stays still while the pointer is over it, so the row under the pointer does not move, and catches up when the pointer leaves. A tree paused in an earlier version comes back live.
0.24.0 Latest
Your components now describe themselves: the plugin writes a Custom Elements
Manifest from your sources, in the build, the dev server or from
lit-devtools manifest, and the details pane reads more of what a component
declares, dispatches and inherits. A language server brings the same
knowledge to your editor, and @oddsquad/lit-devtools installs the plugin,
the server and its Oxlint rules as one package. Nothing needs action to
upgrade.
Added
- Generate a Custom Elements Manifest from your components. Set
manifest: trueandvite buildemitscustom-elements.jsonbeside the bundle, the dev server serves it live, andwritekeeps a copy in the project for editors and Storybook, with no separate analyzer to set up. lit-devtools manifestwrites a Custom Elements Manifest from the command line. It reads every script undersrcand writescustom-elements.json, ready for aprepublishOnlyscript or CI. It uses your Vite config’s aliases, and in a project without one resolves imports the way Node and TypeScript do,tsconfig.jsonpaths included.- A language server for Lit components.
@oddsquad/lit-language-servercompletes your components’ tags, attributes, properties and events in templates, shows their docs on hover, types event handlers and reports one that doesn’t fit its event, in Zed or any LSP editor. Configure it withlitPlugin({languageServer}). - Install everything as
@oddsquad/lit-devtools. One package brings the plugin (@oddsquad/lit-devtools/vite,/astro), the language server and the Oxlint rules (/oxlint); the separate packages stay for a project that wants one part. - Components inherit docs from the library elements they extend. A component built on, say, Web Awesome’s badge now lists the badge’s properties, slots and events in the details pane, read from Web Awesome’s own Custom Elements Manifest.
- Components show the events they dispatch, even without
@fires. An event your class sends withthis.dispatchEvent(new CustomEvent('pick'))now appears under Events in the details pane, typedCustomEvent. - The manifest says what each event carries. An event dispatched as
new CustomEvent('add-to-cart', {detail: {id: this.productId}})is listed asCustomEvent<{id: string}>, also when a@firestag documents it without a type. - Component docs read
@attr,@prop,@defaultand@tag. JSDoc written for the Custom Elements Manifest analyzer now shows in the details pane: attributes and properties the code doesn’t declare, defaults it doesn’t initialize, and the tag of a class registered elsewhere. - Components show the defaults their constructor sets. A
this.variant = 'neutral'in the constructor now shows as the default ofvariantin the details pane, even when the property comes from a library base class such as Web Awesome’s. - Vanilla custom elements show their observed attributes. An element
that lists
static observedAttributes = ['mode']now showsmodeunder Attributes in the details pane, described by an@attrtag if it has one.