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

@input/pen-dom

v0.2.11

Published

DOM field-editor engine and helpers for Pen

Readme

@input/pen-dom

Shared DOM field-editor engine for Pen renderers. @input/pen-react and @input/pen-vue mount FieldEditorImpl inside their document shells. Vanilla hosts call mountEditor, which is that same composition without a framework.

This package does not assemble a schema or install a preset. Editor-field chrome (PEN_EDITOR_CHROME_STYLESHEET) is adopted by mountEditor by default; pass { chrome: false } to skip. It is the DOM engine, not a product editor.

Install

This package has no peer dependencies. Hosts that want a mounted editor still need @input/pen-core and a preset or schema.

pnpm add @input/pen @input/pen-dom yjs

yjs is a peer of @input/pen-yjs, which @input/pen-core depends on.

engines.node is >=22.

Usage

import { createEditor } from "@input/pen";
import { mountEditor } from "@input/pen-dom";

const editor = createEditor();

const root = document.querySelector("#app");
if (!(root instanceof HTMLElement)) {
  throw new Error("Missing #app");
}

mountEditor(editor, root);

That snippet is the vanilla mount path. FieldEditorImpl.setRootElement alone binds a focus sink and never builds the document tree — the page stays blank while it typechecks. React and Vue hosts should keep using those packages; they already construct FieldEditorImpl and the same document shell.

mountEditor adopts editor-field chrome by default so an empty field fills its block, placeholders paint, and :focus-visible uses --pen-focus-ring. Pass { chrome: false } for the HOST6 unstyled path: clicks still land and the first keystroke works with no CSS.

The root export also includes urlPolicy, urlPolicyExtension, DomScheduler, and keyboard helpers such as bindEditorDocumentKeyDown and handleEditorDocumentKeyDown. Extra subpaths exist on the exports map (./field-editor, ./constants/selectAll, and the listed ./utils/* keys). Prefer the root export unless you already depend on a subpath.

Capabilities

The normative per-surface matrix is packages/docs/CAPABILITY-MATRIX.md in the Pen repository. This package is the vanilla surface, and it is also where most capabilities are implemented for the framework bindings — so its column is mostly bring-your-own-ui: the behavior is here, and mountEditor renders no chrome for it.

supported from mountEditor alone: single-block fields, expanded fields, document mutation, paste, editor-field chrome (PEN_EDITOR_CHROME_STYLESHEET), and the review-surface styling contract (adopt PEN_REVIEW_STYLESHEET). Everything else — table chrome, AI review affordances, overlays, multiplayer presence, search UI — exports its state and utilities and leaves the rendering to you.

Options

mountEditor(editor, root, options?) returns { fieldEditor, root, destroy }. Options:

| Option | Default | Effect | | ------------------ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | readonly | false | Declines typing and pointer activation; sets data-readonly (match with [data-readonly], not ="true") and aria-readonly="true". Does not stop editor.apply. pen.ariaReadOnly the facet only sets aria-readonly. | | interactionModel | "content-first" | Passed through resolveSelectAllBehavior | | focusPolicy | unset | Host focus policy passed to FieldEditorImpl | | chrome | true | Adopt PEN_EDITOR_CHROME_STYLESHEET. Pass false for the unstyled HOST6 path. |

FieldEditorImpl accepts a second argument:

| Option | Default | Effect | | ------------------- | ------------------ | ------------------------------------------------ | | selectAllBehavior | "document-first" | "block-first" selects the active block first | | focusPolicy | unset | Host focus policy passed to the focus controller |

DEFAULT_SELECT_ALL_BEHAVIOR is "document-first". resolveSelectAllBehavior(interactionModel) returns "block-first" only when interactionModel is "block-first".

Documentation

The docs site (the @input/pen-docs package) covers this area on the Getting started page (#/getting-started).

The public signatures of record are in api-report.md next to this package's source in the Pen repository. The docs site does not host a generated browsable reference.

License

MIT © Input B.V. See LICENSE.md.