Skip to Content
WidgetOverview

These pages document @evanion/widget 0.1.3, the version on npm.

@evanion/widget

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.

For a high-level look at the system, visit the rendering overview.

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 (like span: 2 for 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:

GoalTool
Describe a page as JSON dataAnyWidgetItem, a type for items that can be written by a CMS
Define supported typesA registry from defineWidgets, or a simple list of type names
Reject bad payloads before renderingvalidateItems(items, known), which reports all problems without throwing
Enforce required props in the CMSA required map for validateItems to ensure essential props are present
Framework-agnostic checksvalidateItems has no dependencies and runs in any JS environment
Consistent error reportingERROR_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 type exists. It cannot check if the props match a component’s TypeScript definition (though @evanion/react-widget can).
  • No Automatic Execution: The library doesn’t run validateItems automatically; 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.

Last updated on