@shapething/shacl-renderer
v2.0.0
Published
A SHACL toolkit.
Readme
@shapething/shacl-renderer
A SHACL toolkit for React. Give it a SHACL shapes graph and an RDF data graph and it renders a user interface for them:
- edit – a form for creating or updating a resource,
- view – a read-only presentation of a resource,
- facet – faceted search/filtering over the instances in a graph.
Validation runs live as you edit. The package implements the
SHACL 1.2 Core specification and the proposed SHACL-UI
(shui:, http://www.w3.org/ns/shacl-ui/) extension: widget selection through declarative
scoring, value-node labels via property roles, language resolution, and federated search.
Part of ShapeThing.
Install
npm install @shapething/shacl-renderer react react-domreact and react-dom (^19) are peer dependencies.
Usage
import { ShaclRenderer, type SubmitResult } from "@shapething/shacl-renderer";
import "@shapething/shacl-renderer/style.css";
import { DataFactory } from "rdf-data-factory";
const factory = new DataFactory();
export function PersonForm() {
return (
<ShaclRenderer
// Either graph can be a URL, a string of RDF (Turtle, JSON-LD, ...), an RdfStore or quads.
shapesGraph={new URL("https://example.org/shapes.ttl")}
dataGraph={new URL("https://example.org/people/alice.ttl")}
focusNode={factory.namedNode("https://example.org/people/alice")}
nodeShapes={[factory.namedNode("https://example.org/shapes#PersonShape")]}
mode="edit" // "edit" | "view" | "facet"
onSubmit={(result: SubmitResult) => {
// result.dataGraph is a snapshot of the edited data;
// result.additions / result.deletions are the quads that changed.
console.log(result.additions, result.deletions);
}}
/>
);
}ShaclRenderer accepts any subset of the Environment fields. Fields you leave out fall back to
their defaults. When nodeShapes is omitted, it is resolved from the shapes that target the
focusNode. The package also exports the types you need to configure it, write a custom widget,
or write your own preprocessor: Environment, RawEnvironment, SubmitResult, Preprocessor,
WidgetProps, WidgetComponent, WidgetMeta, Widgets, PropertyUIElement, and the values
defaultPreprocessors, defaultWidgets, defaultEnvironment and minimalEnvironment.
Stylesheet
The components render into the light DOM and ship their styles as one stylesheet. Import it once, wherever your application loads global CSS:
import "@shapething/shacl-renderer/style.css";Web component
For pages that don't use React themselves, a <shacl-renderer> custom element is also
available. You still need to load the stylesheet and install react/react-dom, because the
element uses them internally.
<link rel="stylesheet" href="/node_modules/@shapething/shacl-renderer/dist/style.css" />
<script type="module">
import "@shapething/shacl-renderer/webcomponent";
</script>
<shacl-renderer
shapes="/shapes.ttl"
data="/alice.ttl"
focus-node="https://example.org/people/alice"
node-shapes="https://example.org/shapes#PersonShape"
mode="edit"
></shacl-renderer>Attributes cover the string and boolean settings. Anything else (pre-parsed stores, custom
widgets, preprocessors, locale loaders) goes through the element's environment JavaScript
property. Submitting dispatches a shacl-submit CustomEvent whose detail is the
SubmitResult.
Tools
The ./tools entry point holds SHACL-driven code generation and conversion utilities. They live
in a separate entry so the renderer bundle doesn't pull in their dependencies:
import { generate, jsToRdf, rdfToJs, shaclToType } from "@shapething/shacl-renderer/tools";generate: generates fake data that conforms to a shape (uses@faker-js/faker).jsToRdf/rdfToJs: convert between plain JavaScript objects and RDF, guided by a shape.shaclToType: generates TypeScript type declarations from node shapes.
Astro content loader
The Node-only ./astro entry point builds on these tools: an Astro content
loader with one entry per shape target (keyed by its IRI, read with rdfToJs), which can also
write a zod schema for the collection (generated from shaclToType, needs ts-to-zod installed):
// src/content.config.ts
import { astroLoader } from "@shapething/shacl-renderer/astro";
import { defineCollection } from "astro:content";
import { PersonSchema } from "./person";
const people = defineCollection({
// Paths are globs relative to the Astro project root.
loader: astroLoader({
shapes: "./src/rdf/person-shape.ttl",
data: "./src/rdf/people/*.ttl",
languages: ["en"],
schemaFile: "./src/person.ts",
}),
schema: PersonSchema,
});Funding
This project is funded through NGI0 Commons Fund, a fund established by NLnet with financial support from the European Commission's Next Generation Internet program. Learn more at the NLnet project page.
