· 4 min read
EPaper: a web component library for e-paper displays
E-paper panels invalidate several assumptions that common component libraries are built on: refresh times are measured in hundreds of milliseconds, touch panels report no hover state, and the number of stable tones a panel can hold is small. A theme on top of an established library cannot take those assumptions back, which is why EPaper is its own web component library for electrophoretic displays: just over eighty custom elements with an e- prefix, no framework, no runtime dependencies, published on npm under the MIT licence.
Refresh behaviour and DOM updates
Animations and CSS transitions are disabled globally in the base stylesheet, since the refresh characteristics of e-paper panels would otherwise cause pronounced ghosting that persists across several subsequent refreshes. The same consideration applies to rendering strategy. Replacing a subtree causes the display controller to schedule a full-panel refresh, which takes roughly 200–800 ms and is accompanied by a visible flash, whereas changing a single attribute or text node results in a partial refresh in the range of 30–80 ms.
Components therefore render once when they are connected and afterwards apply targeted DOM mutations through a small set of typed helpers. Those helpers return early when the value is unchanged, so a component embedded in a reactive framework does not trigger a repaint when the framework re-asserts the same attribute on every render pass.
Interaction states without hover or opacity
Since e-paper touch surfaces do not support hovering, interaction states are conveyed by other means: focus is rendered as a 3px outline with a 2px offset, the pressed state inverts foreground and background, and selection switches to a flat fill. Disabled and error states use diagonal hatch patterns defined once as design tokens.
Opacity and grey tones are deliberately avoided for state encoding. Intermediate tones are dithered by the controller, and the dither pattern is not stable between refreshes, so a control styled with reduced opacity changes its texture on every repaint. Colour is not available for state encoding on monochrome panels at all.
Form participation and DOM model
All interactive controls — inputs, checkboxes, radio and checkbox groups, toggles, selects, cascaders, tree selects, number fields, date and time pickers, and upload — are form-associated custom elements based on ElementInternals. Given a name attribute they participate in FormData, form.reset() and constraint validation, so a form behaves correctly without additional event handlers or state management. That matters for kiosk deployments, where the application is often a single HTML file.
The components render into the light DOM rather than a shadow root. This keeps form participation straightforward, allows integrators to override styles with ordinary CSS selectors, and avoids the Shadow DOM defects found in the reduced browser builds that such devices frequently ship with. The trade-off is that the rendered markup and its .ink-* class names are part of the public API.
Geometry and typography
Line weights follow the physical characteristics of the panels. At 150–300 ppi and without sub-pixel anti-aliasing, 1px lines lose contrast, so the default border width is 2px and hairlines are reserved for inert dividers. Icons are drawn with a 2px stroke, square caps and mitred joins and without fills, because rounded endpoints and small filled areas produce visible refresh artefacts.
Touch targets default to 44px, which corresponds to roughly 3.7 mm of physical surface at 300 ppi — a practical minimum, given that capacitive layers over e-paper are less precise than those over OLED. Line height is 1.55 for interface text and 1.6 for longer prose, which is set in a serif face because reflective grayscale is read more slowly than a backlit display. On Kaleido panels the five available colours are exposed as flat tokens rather than gradients or alpha blends, and a diagnostic component renders each colour next to its dithered preview so the result on hardware can be assessed during design.
Distribution
The CSS ships as three layers — tokens, reset and component styles — both as readable source for bundlers and as a combined minified bundle of about 5 KB gzipped. The complete component set is roughly 42 KB gzipped; per-component subpath imports keep that down in practice. Type declarations, a Custom Elements Manifest and IDE metadata for VS Code and JetBrains are generated during the build. Documentation, examples and the Storybook are available at epaper-components.dev, the source is on GitHub.