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

xsd-ui

v1.8.4

Published

Independent Angular UI component library workspace

Downloads

546

Readme

xsd-ui

npm version license Angular TypeScript

Dynamic Angular form library for ISO 20022 workflows.

xsd-ui renders schema-driven forms from XSD-to-JSON metadata, supports recursive complex structures, validates according to schema constraints, and exports data as clean output JSON.

Why xsd-ui

  • Schema-driven rendering for nested ISO 20022 structures
  • Reactive Forms architecture with recursive field generation
  • Built-in validation from schema rules (length, pattern, numeric constraints, enum)
  • Repeatable groups, choice structures, currency amounts, and one-click UETR generation
  • XML and JSON patching APIs (setXmlForm, setJsonForm)
  • Output shaping with optional empty-field omission
  • Precise validity reporting via getInvalidFields() (field path + reason)
  • Fully themeable through CSS custom properties — no build tooling required
  • Event-based API access (onFormReadyEvent) without ViewChild
  • Standalone Angular components, ready for library consumption

Installation

npm install xsd-ui

Peer dependencies:

  • @angular/common ^21.2.10
  • @angular/core ^21.2.10
  • @angular/forms ^21.2.10
  • @angular/animations ^21.2.10
  • rxjs ^7.8.1

Quick Start

Register license once (recommended):

import {
  configureXsdUiLicense,
  XsdLicensePayload,
  XsdLicenseValidationResult,
  XsdLicenseValidator,
} from 'xsd-ui';

const validateLicenseOnServer: XsdLicenseValidator = async (
  licenseKey: string,
  payload: XsdLicensePayload,
): Promise<XsdLicenseValidationResult> => {
  const response = await fetch('/api/licenses/validate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ licenseKey, payload }),
  });

  if (!response.ok) {
    return { valid: false, reason: 'License API unavailable.' };
  }

  return response.json() as Promise<XsdLicenseValidationResult>;
};

configureXsdUiLicense({
  licenseKey: '<YOUR_LICENSE_KEY>',
  licenseValidator: validateLicenseOnServer,
  requireServerValidation: true,
  offlineFallbackOnServerError: true,
});

Use component:

import { Component } from '@angular/core';
import {
  XsdFormComponent,
  XsdLicenseValidationResult,
  XsdFormPublicApi,
  XsdFormSchema,
} from 'xsd-ui';

@Component({
  selector: 'app-payment-form',
  standalone: true,
  imports: [XsdFormComponent],
  template: `
    <xsd-form
      [schema]="schema"
      (onFormReadyEvent)="onFormReady($event)"
      (licenseValidationChange)="onLicenseValidationChange($event)"
      (change)="onFormChange()"
    />

    <button type="button" (click)="submit()">Submit</button>
  `,
})
export class PaymentFormComponent {
  schema!: XsdFormSchema;
  formApi: XsdFormPublicApi | null = null;

  onFormReady(api: XsdFormPublicApi): void {
    this.formApi = api;
  }

  onFormChange(): void {
    // Live updates, autosave, previews, etc.
  }

  onLicenseValidationChange(result: XsdLicenseValidationResult): void {
    if (!result.valid) {
      console.error(result.reason);
    }
  }

  submit(): void {
    if (!this.formApi) return;
    if (!this.formApi.isValid()) return;

    const payload = this.formApi.getForm(true);
    console.log(payload);
  }
}

Core Components

  • XsdFormComponent (xsd-form): root orchestration component
  • XsdFieldComponent (xsd-field): recursive field renderer

Edit form layout

The editable form uses the same visual system as the read-only view — fonts, type scale and palette — without changing the document structure: every section renders in schema order.

  • One hierarchy device. A section is a heading plus a left rail; there are no nested cards. Only repeated items get a card. The innermost section holding focus gets an accented rail.
  • Optional empty sections collapse in place to a single muted heading line (› Proxy, › Interest 0 [+ Add]). Click to expand; they expand automatically when setJsonForm / setXmlForm fills them.
  • Choices live in the heading. Identification [Other ▾] — the option selector sits beside the section name and the chosen option's fields render directly beneath it.
  • Add on a repeat scrolls to the new item, highlights it briefly and focuses its first input.
  • Booleans get a true / false select; an amount's Ccy attribute is a labelled tag beside it.
  • Accessible by construction: real <button> toggles with aria-expanded and names, no interactive element nested in another, aria-required / aria-invalid / aria-describedby on inputs, unique ids per rendered field.

Inputs

| Input | Type | Required | Description | |---|---|---|---| | schema | XsdFormSchema | Yes | Root schema including namespace and schemaElement. | | licenseKey | string | No | Optional override for global registered key. | | licenseValidator | XsdLicenseValidator | No | Optional override for global server validator. | | requireServerValidation | boolean | No | Optional override for global server-validation enforcement. | | offlineFallbackOnServerError | boolean | No | Optional override to allow offline fallback when server validation errors out. | | translations | TranslationConfig | No | Label and error message overrides. | | readonly | boolean | No | Renders a read-only document view instead of the editable form. See Read-only view. | | showValidationInView | boolean | No | In read-only mode, marks fields that fail schema validation with ⚠. | | readonlyOptions | XsdReadonlyOptions | No | Read-only view tuning: collapse, formatValues, headingDepth, tierThresholds. Defaults: verbatim values, full hierarchy. | | readonlyTitle | string | No | Read-only header title. Defaults to the business element's label (e.g. "Bank To Customer Account Report V08"). | | readonlyMeta | string | No | Line under the read-only title. Defaults to the message id from the namespace (e.g. camt.052.001.08); '' hides it. |

Outputs

| Output | Payload | Description | |---|---|---| | onFormReadyEvent | XsdFormPublicApi | Emits when form API is ready (and on schema rebuild). | | licenseValidationChange | XsdLicenseValidationResult | Emits license validation state and failure reason. | | change | void | Emits on value changes and programmatic updates. |

Licensing Best Practice

For browser libraries, client-side checks alone are not tamper-proof. Recommended production setup:

  1. Register licensing once at app startup with configureXsdUiLicense(...).
  2. Keep signed offline key verification enabled (licenseKey + RSA signature).
  3. Add backend entitlement validation using licenseValidator.
  4. Set requireServerValidation to true in production.
  5. Keep offlineFallbackOnServerError enabled if you want graceful offline operation.
  6. Return short-lived entitlements from your backend and rotate/revoke there.

Note: When implementing licenseValidator, return { valid: false } for explicit entitlement rejection (revoked, over-limit, wrong tenant), and throw errors for network/server failures. This lets xsd-ui distinguish deny vs fallback conditions.

This hybrid approach is the strongest practical model for Angular UI components.

Public API

Exposed through onFormReadyEvent.

| Method | Description | |---|---| | isValid(): boolean | Returns schema-aware validity (optional empty branches are handled). | | getInvalidFields(): XsdInvalidField[] | Returns every failing field as { path, reason } — ideal for surfacing which fields are invalid after a patch. | | getForm(omitEmpty?: boolean) | Returns output JSON in root-keyed structure. | | setJsonForm(json) | Patches form using either full root-keyed JSON or inner object. | | setXmlForm(xml) | Parses and patches ISO 20022 XML payloads. | | getNamespace() | Returns schema namespace. | | clearForm() | Resets form values. | | disableForm() | Disables all controls. | | enableForm() | Enables all controls. | | setReadonly(readonly) | Switches between the editable form and the read-only document view. |

Read-only view

When you only need to show a message — e.g. an incoming XML you received rather than one the user is composing — a disabled form is hard to read: every input, empty optional group and placeholder is still rendered. Set readonly instead and xsd-form renders a compact, document-style view:

<xsd-form [schema]="schema" [readonly]="true" [showValidationInView]="true" />
onFormReady(api: XsdFormPublicApi): void {
  api.setXmlForm(incomingXml);   // patch as usual
  api.setReadonly(true);         // or bind [readonly] in the template
}

The view is produced by a projection pass (projectView(), exported and framework-free) that walks schema and instance together and emits a small tree before anything renders. A camt.052 schema has ~2 300 leaves; a typical message carries ~30 values — the projection keeps only those.

Defaults are faithful: every value is shown exactly as written in the message (no date reformatting, no digit grouping, no timezone conversion — the original text of date-times is kept even though the edit form stores a browser-local copy), and every container keeps its own heading and rail so it is always clear which section a value belongs to.

What always happens (schema-driven, no per-message templates):

| | Rule | Example | |---|---|---| | Prune | Empty leaves and containers are dropped; repeats keep present items; a choice shows only its filled branch; Ccy folds into the amount | <Amt Ccy="EUR">704873.77</Amt> → 704873.77 EUR | | Style | External code sets (…Cd, ≤ 4 chars) and enumerations render as chips; CRDT/DBIT as a badge; identifiers and amounts are monospaced | ITAV, CRDT | | Amounts | A currency amount stays one labelled row, with the Ccy attribute shown as a named tag beside the value — mirroring <Amt Ccy="EUR">704873.77</Amt> | Amount → 704873.77 [Ccy EUR] | | Cards | Repeats become numbered cards; every value inside keeps its own labelled row | 1 → Type › Code ITAV, Amount, Credit Debit Indicator, Date | | Index | Documents with more than 150 values get a sticky section index | |

Optional compaction via readonlyOptions ([readonlyOptions]="{ collapse: true, formatValues: true }"):

| Option | Effect | Example | |---|---|---| | collapse | A container with exactly one surviving child merges into it; code-only groups become one chip row; a repeated item's code and amount move into its card title with CRDT/DBIT merged into the amount; repeats are hoisted to top-level headings; very small documents drop headings | Acct/Id/Othr/Id → Account · Other · Identification, BkTxCd → PMNT / RCDT / XBCT, card 1 ITAV 704 873.77 EUR CRDT | | headingDepth | Containers deeper than this become a muted label prefix instead of a heading | Report Pagination · Page Number | | formatValues | Thin-space digit grouping, ≥ 2 decimals on amounts, 24 Nov 2020 dates, 11:00:00 UTC+01:00 date-times, Yes/No booleans | 704 873.77 EUR | | tierThresholds | Row counts at which the layout switches tier (default [20, 150]) | |

With showValidationInView, fields that fail schema constraints get a ⚠ marker with the reason (missing required fields are shown as —), plus a summary banner — handy for reviewing messages that were not produced by this form.

Project a summary band of your own (e.g. account / available balance / as-of) with the xsdViewSummary slot:

<xsd-form [schema]="schema" [readonly]="true">
  <div xsdViewSummary class="my-summary">…</div>
</xsd-form>

The underlying form model stays alive, so getForm(), getInvalidFields(), setJsonForm() and setXmlForm() keep working and switching back to edit mode is lossless. readonly is independent of disableForm() (which changes control state, not presentation).

Theming: the view shares the --xsd-ui-* palette and adds --xsd-ui-ink, --xsd-ui-font and --xsd-ui-mono. It prefers IBM Plex Sans/Mono when the host app loads them and falls back to system fonts otherwise.

Theming

xsd-ui ships with a clean, accessible default theme built on a five-color palette, where each color carries a consistent meaning:

| Role | Default | Used for | |---|---|---| | Structure | #006ba6 | Field labels, choice selectors, Add, select carets | | Interaction | #0496ff | Focus rings, input hover, active-section rail, new-item highlight | | Highlight | #ffbc42 | Accent highlights | | Required / Error | #d81159 | Required marker, invalid inputs, error messages, Remove | | Ink | #15171b (--xsd-ui-ink) | Text, headings, rails and lines (mixed to tints) |

Fonts: --xsd-ui-font / --xsd-ui-mono (default IBM Plex Sans/Mono when the host loads them, system fonts otherwise) apply to both the edit form and the read-only view.

Re-brand the entire form by overriding the public --xsd-ui-* custom properties from any ancestor (typically :root in your global stylesheet) — no recompilation needed:

:root {
  --xsd-ui-ocean:     #1e3a8a;  /* structure   */
  --xsd-ui-blue:      #2563eb;  /* interaction */
  --xsd-ui-gold:      #f59e0b;  /* highlight   */
  --xsd-ui-raspberry: #dc2626;  /* required / error */
  --xsd-ui-berry:     #7c3aed;  /* repeatable sets  */
}

Optional darker hover shades — --xsd-ui-ocean-dark, --xsd-ui-blue-dark, --xsd-ui-raspberry-dark — can be overridden the same way; otherwise sensible defaults are derived from the base colors.

Schema Model Overview

xsd-ui expects an XsdFormSchema shape similar to:

interface XsdFormSchema {
  namespace: string;
  schemaElement: SchemaElement | SchemaElement[];
}

Each SchemaElement contains metadata such as:

  • name, id, xpath
  • dataType
  • cardinality: minOccurs, maxOccurs
  • validation constraints: minLength, maxLength, pattern, minInclusive, maxInclusive, etc.
  • structure: elements (children)

Validations Supported

  • Required checks from minOccurs
  • String length (minLength, maxLength)
  • Regex pattern
  • Numeric boundaries (minInclusive, maxInclusive, minExclusive, maxExclusive)
  • fractionDigits, totalDigits
  • Enumerations (values)
  • Choice structures and unbounded arrays

XML / JSON Patching

JSON patch

formApi.setJsonForm({
  FIToFICstmrCdtTrf: {
    GrpHdr: {
      MsgId: 'MSG-001',
      CreDtTm: '2026-04-25T12:41:52.673+08:00',
      NbOfTxs: '1'
    }
  }
});

XML patch

formApi.setXmlForm(`
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08">
  <FIToFICstmrCdtTrf>
    <GrpHdr>
      <MsgId>XML-PATCH-001</MsgId>
      <NbOfTxs>1</NbOfTxs>
    </GrpHdr>
  </FIToFICstmrCdtTrf>
</Document>
`);

License

This package is distributed under a commercial license. Contact the publisher for licensing terms and usage rights.