@evanion/widget
@evanion/widget 0.1.0 and its patch releases up to 0.1.3, the version on npm. Values on this page were produced by running the source at f9b1d93, a later commit than the 0.1.0 tag, and are not re-executed.
Stop “Silent Failures” in your CMS-driven pages with a framework-agnostic widget validation engine.
When a content management system (CMS) saves a page, it typically stores the content as a list of “items.” Each item specifies a type (which component should be used) and props (the data for that component).
The danger is a Silent Failure: if a CMS saves an item with a type that your frontend doesn’t recognize, the renderer will often simply skip that item, and if a required prop is missing, it draws the widget without it. In production, this leaves a mysterious gap in your page where a widget should have been, and since no error is thrown, you might not notice it until a user reports it.
@evanion/widget is the core engine that identifies these “missing” or “broken” widgets before they ever hit the browser. It allows you to catch content errors during the save process, in a webhook, or as a blocking step in your CI pipeline.
The Model: Page as an Item Array
In this system, a widget is a single structural block of a page—such as a game listing, a hero banner, or a featured shelf. A widget item is the data representation of that block.
A renderer (such as @evanion/react-widget or @evanion/astro-widget) is the framework-specific package that actually turns these data items into UI components.
Consider this listing page for the Baize board game shop. It contains a wide listing for Brass: Birmingham and a shelf of other games. We can use validateItems to check that every item in this array names a known type and carries its props:
import { } from '@evanion/widget';
import type { } from '@evanion/widget';
const : [] = [
{
: 'brass-birmingham',
: 'listing',
: { : 'Brass: Birmingham', : 4 },
: { : 2 },
},
{
: 'tonight',
: 'shelf',
: { : 'On the table tonight' },
: [
{ : 'wingspan', : 'listing', : { : 'Wingspan' } },
],
},
];
const = (, ['listing', 'shelf']);
; // -> []If problems is empty, every item is valid. If it’s not, the library tells you exactly which item is causing the issue, allowing you to alert the content editor immediately.
Anatomy of a Widget Item
Every item consists of a few key fields that standardize how your CMS talks to your frontend:
id: A unique string used for React keys and DOM attributes.type: The name of the component used to render the widget.props: The actual data passed to the component.meta: Optional placement data (likespan: 2for a grid). This is handled by the item chrome (chrome.item, the element that surrounds each widget) rather than the widget itself.children: An optional array of nested items, allowing you to create complex layouts like shelves containing listings.
The Widget Vocabulary
To help you build your renderer, we use these terms:
- Known Types: The list of widget types that your renderer actually has components for.
- Registry: A map that links each known type to its corresponding component.
- Problem: An error report generated by
validateItems, containing the index and type of the faulty item.
Core Capabilities
@evanion/widget provides the logic for validating your CMS payloads without requiring a frontend framework:
| Goal | Tool |
|---|---|
| Describe a page as JSON data | AnyWidgetItem, a type for items that can be written by a CMS |
| Define supported types | A registry from defineWidgets, or a simple list of type names |
| Reject bad payloads before rendering | validateItems(items, known), which reports all problems without throwing |
| Enforce required props in the CMS | A required map for validateItems to ensure essential props are present |
| Framework-agnostic checks | validateItems has no dependencies and runs in any JS environment |
| Consistent error reporting | ERROR_MESSAGES and warnOnce to keep warnings consistent across your app |
Design Boundaries
To keep the core lightweight and portable, it is important to distinguish the core from the renderer:
- No UI Rendering: The core does not draw anything on the screen; that is the job of the renderer.
- No Compile-time Prop Checks: The core only knows if a
typeexists. It cannot check if thepropsmatch a component’s TypeScript definition (though@evanion/react-widgetcan). - No Automatic Execution: The library doesn’t run
validateItemsautomatically; you must call it in your own code (e.g., in a webhook or build script). - No Data Fetching: The core only validates the data it is given; it doesn’t know where the data comes from.
Set up the Widget Core
The core’s model is simple: an array of items, a list of supported types, and a validation call. Getting started shows you how to install the package and use validateItems as a quality gate for your saved pages.