npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mdocui/web-components

v0.8.1

Published

Custom element renderer for mdocUI — works in any framework, or none

Downloads

291

Readme

@mdocui/web-components

Custom element renderer for mdocUI. Renders streamed LLM output as real DOM, in any framework or none.

Part of the mdocui monorepo.

Install

npm install @mdocui/web-components

Quick Start

Importing the package registers <mdoc-ui>.

<script type="module">
  import '@mdocui/web-components'

  const el = document.querySelector('mdoc-ui')

  // stream it
  for await (const chunk of response) el.push(chunk)
  el.done()

  // or set it all at once
  el.markup = 'Revenue grew **12%**\n\n{% chart type="bar" labels=["Q1","Q2"] values=[10,14] /%}'
</script>

<mdoc-ui></mdoc-ui>

No framework, no peer dependencies. The only runtime dependency is @mdocui/core.

API

| Member | Description | |---|---| | push(chunk) | Feed the next chunk of a streaming response | | done() | Close the stream and flush | | reset() | Clear and start again | | markup = string | Replace the content in one go | | getNodes() | The parsed AST | | isStreaming | Whether a stream is open | | classNames | Map of component name to CSS class | | components | Map of component name to your own renderer | | registry | A ComponentRegistry; defaults to the built-ins |

Events

Both bubble.

el.addEventListener('mdocui:action', (e) => {
  e.detail // { type: 'button_click', action: 'go', label: 'Go', ... }
})

el.addEventListener('mdocui:error', (e) => {
  e.detail // { componentName, error, props }
})

A component that throws is reported here and skipped; the rest of the message still renders.

Registering under another name

import { defineMdocUI } from '@mdocui/web-components'
defineMdocUI('my-mdoc')

defineMdocUI is safe to call twice and does nothing where there is no DOM, so importing this package during a server render will not throw.

Light DOM

Components render into the element itself, not a shadow root, so page CSS reaches them:

[data-mdocui-card] { border-radius: 12px; }

Or pass classes per component, which also drops the default inline styles:

el.classNames = { card: 'my-card', button: 'my-button' }

Streaming

Only the tail of the document is re-rendered as chunks arrive. A component becomes a node once its closing tag lands, so anything interactive is final by the time it reaches the DOM — focus and typed input are never thrown away mid-stream.

The same input produces the same DOM regardless of how it is chunked.

Accessibility

The same guarantees as @mdocui/react: ids unique per instance, controls disabled while streaming, the full ARIA tab pattern with Home/End and a roving tab stop, charts announcing their data rather than their type, and submitted forms leaving the tab order via inert.

Prose is built from text nodes and never assigned as HTML, and link hrefs pass through sanitizeHref, so javascript: and data: URLs render as plain text.

License

MIT