Joy DOM

@joy-dom/spec

TypeScript types and JSON Schema for the Joy DOM document format.

@joy-dom/spec is the source of truth for what Joy DOM documents may contain. It exports a Zod schema, the inferred TypeScript types, and a published JSON Schema file. Renderers and tooling consume these.

For the behavioral spec (selectors, resolution order, breakpoints), see Specification. This page covers the programmatic surface.

Install

bun add @joy-dom/spec

Top-level exports

SpecSchema

A Zod schema for the full document. Use it to validate any object claiming to be a Joy DOM document.

const  = .();
if (.) {
  const : Spec = .;
} else {
  .(.);
}

Two calling forms:

  • SpecSchema.parse(value) - throws a ZodError on failure.
  • SpecSchema.safeParse(value) - returns { success, data | error }.

Spec

TypeScript type inferred from SpecSchema. Shape:

type Spec = {
  version: 1;
  style: Record<string, Style>;
  breakpoints: Breakpoint[];
  layout: Node;
};

Node

A discriminated union covering the supported node types.

type Node = TextNode | ImageNode | BlockNode | CustomNode;

type TextNode = {
  type: "p" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
  props?: NodeProperties;
  children?: PrimitiveValue[];
};

type ImageNode = {
  type: "img";
  props: NodeProperties & { src: string; alt?: string };
};

type BlockNode = {
  type: "div";
  props?: NodeProperties;
  children?: (Node | PrimitiveValue)[];
};

type CustomNode<Props = unknown> = {
  type: `${string}-${string}`; // kebab-case
  props?: NodeProperties & Props;
  children?: (Node | PrimitiveValue)[];
};

type PrimitiveValue = string | number | null;

NodeProperties

The common subset of fields every node may carry:

type NodeProperties = {
  id?: string;
  className?: string[];
  style?: Style;
};

Style

A record of supported style properties. The shape matches §5 Properties; see that section for value tables and inheritance.

Breakpoint

type Breakpoint = {
  conditions: MediaQuery[];
  nodes: Record<string, Partial<NodeProperties>>;
  style: Record<string, Style>;
};

MediaQuery

A discriminated union over condition types:

type MediaQuery =
  | { type: "type"; value: "print" }
  | {
      type: "feature";
      name: "width";
      value: number;
      operator?: ">" | "<" | ">=" | "<=";
      unit: "px";
    }
  | { type: "feature"; name: "orientation"; value: "landscape" | "portrait" }
  | { op: "and" | "or"; conditions: MediaQuery[] }
  | { op: "not"; condition: MediaQuery };

See §6.2 Conditions for the human-readable description.

Helpers

isCustomElementName(value)

Returns true if value is a string matching the WHATWG custom-element-name rules (§3.6). Use this when accepting arbitrary type strings from external input.

import {  } from "@joy-dom/spec";

("contact-button"); // true
("Button"); // false (not lowercase, no hyphen)
("annotation-xml"); // false (reserved)

JSON Schema

The package ships a JSON Schema for the full document at dist/schema.json. Use it from non-JS tools - editors with JSON Schema support, OpenAPI pipelines, validation CLIs.

# Build the JSON Schema artifact
bun --filter @joy-dom/spec build:schema

Other Zod schemas

For when you need to validate a fragment rather than the whole document:

ExportValidates
StyleSchemaA single Style record (e.g. an inline style).
NodeSchemaA single Node (any variant).
ChildNodeSchemaA Node or a PrimitiveValue.
BreakpointSchemaA single breakpoint object.
MediaQuerySchemaA single media query.
LengthSchemaA Length<unit> object.
NodePropertiesSchemaJust the common node props (id, className, …).

Why Zod?

Zod gives one definition that produces both a runtime validator and a TypeScript type. The exported types you import from @joy-dom/spec are the validator output, so they cannot drift from what the schema accepts.

Where next

On this page