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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@ulb-darmstadt/shacl-form

v2.0.0

Published

SHACL form generator

Readme

SHACL Form Generator

npm i @ulb-darmstadt/shacl-form

HTML5 web component for editing/viewing RDF data that conform to SHACL shapes.

See demo here

Basic usage

<html>
  <head>
    <!-- load bundled web component (or when developing your own app, just do "npm i @ulb-darmstadt/shacl-form")  -->
    <script src="https://cdn.jsdelivr.net/npm/@ulb-darmstadt/shacl-form/dist/bundle.js" type="module"></script>
  </head>
  <body>
    <!--
      SHACL shapes can be defined on the attribute 'data-shapes'
      or can be loaded by setting attribute 'data-shapes-url'
    -->
    <shacl-form data-shapes="
      @prefix sh:   <http://www.w3.org/ns/shacl#> .
      @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
      @prefix ex:   <http://example.org#> .

      ex:ExampleShape
        a sh:NodeShape, rdfs:Class ;
        sh:property [
          sh:name 'my value' ;
          sh:path ex:exampleValue ;
          sh:maxCount 3 ;
        ] .
    "></shacl-form>

    <script>
      const form = document.querySelector("shacl-form")
      form.addEventListener('change', event => {
        // check if form data validates according to the SHACL shapes
        if (event.detail?.valid) {
          // get data graph as RDF triples and
          // log them to the browser console
          const triples = form.serialize() 
          console.log('entered form data', triples)
          // store the data somewhere, e.g. in a triple store
        }
      })
    </script>
  </body>
</html>

Element attributes

Attribute | Description ---|--- data-shapes | SHACL shape definitions (e.g. a turtle string) to generate the form from data-shapes-url | When data-shapes is not set, the SHACL shapes are loaded from this URL data-shape-subject | Optional subject (id) of the SHACL node shape to use as root for the form. If not set, the first found node shape will be used data-values | RDF triples (e.g. a turtle string) to use as existing data graph to fill the form data-values-url | When data-values is not set, the data graph triples are loaded from this URL data-values-subject | The subject (id) of the generated data. If this is not set, a blank node with a new UUID is created. If data-values or data-values-url is set, this id is also used to find the root node in the data graph to fill the form data-values-namespace | RDF namespace to use when generating new RDF subjects. Default is empty, so that subjects will be blank nodes. data-values-graph | If set, serializing the form will create a named graph with the given IRI. data-language | Language to use if shapes contain langStrings, e.g. in sh:name or rdfs:label. Default is navigator.language with fallback to navigator.languages data-loading | Text to display while the web component is initializing. Default: "Loading..." data‑ignore‑owl‑imports | By default, owl:imports URLs are fetched and the resulting RDF triples are added to the shapes graph. Setting this attribute to any value disables this feature data-view | When set, turns the web component into a viewer that displays the given data graph without editing functionality data-collapse | When set, sh:groups and properties with sh:node and sh:maxCount != 1 are displayed in a collapsible accordion-like widget to reduce visual complexity of the form. The collapsible element is initially shown closed, except when this attribute's value is "open" data-submit-button | [Ignored when data-view attribute is set] Whether to add a submit button to the form. The value of this attribute is used as the button label. submit events get emitted only when the form data validates data-generate-node-shape-reference | When generating the RDF data graph, <shacl-form> by default creates a triple that references the root sh:NodeShape of the data. Default value of this attribute is http://purl.org/dc/terms/conformsTo. Set this to the empty string to disable generating such a triple. data-show-node-ids | When this attribute is set, shacl node shapes will have their subject id shown in the form data-proxy | URL of a proxy to use when fetching resources (e.g. owl:imports). This can help loading resources from the web that are not CORS enabled. The URL of the resource to fetch will be appended to the value of this attribute. Example value for this attribute: http://you-proxy.org/?url=. data-dense | Boolean inidcating to render a compact form with small paddings and margins. Default: true data-hierarchy-colors | If set, a colored vertical bar is displayed on the right side of the form for each nested hierarchy level with the intention of easing orientation in complex nested forms. The value of this attribute can be a list of comma seperated CSS color definitions. If no value is given, a default color palette is used.

Element functions

toRDF(graph?: Store): Store

Adds the form values as RDF triples to the given graph. If no graph object is provided, creates a new N3 Store.

serialize(format?: string, graph?: Store): string

Serializes the given RDF graph to the given format. If no graph object is provided, this function calls toRDF() (see above) to construct the form data graph in one of the supported output formats (default is text/turtle).

validate(ignoreEmptyValues: boolean): Promise<boolean>

Validates the form data against the SHACL shapes graph and displays validation results as icons next to the respective input fields. If ignoreEmptyValues is true, empty form fields will not be marked as invalid. This function is also internally called on change and submit events.

registerPlugin(plugin: Plugin)

Register a plugin to customize editing/viewing certain property values. Plugins handle specific RDF predicates or xsd:datatypes or both. Example: Leaflet

setTheme(theme: Theme)

Set a design theme to use for rendering. See section Theming.

setClassInstanceProvider((className: string) => Promise<string>)

Sets a callback function that is invoked when a SHACL property has an sh:class definition to retrieve class instances. See below for more information.

Features

Validation

In edit mode, <shacl-form> validates the constructed data graph using the library shacl-engine and displays validation results as icons next to the respective form fields.

Data graph binding

<shacl-form> requires only a shapes graph as input via the attribute data-shapes (or data-shapes-url) to generate an empty form and create new RDF data from the form input fields. Using the attributes data-values (or data-values-url) and data-values-subject, you can also bind an existing data graph to the form. The given data graph is then used to fill the form input fields.

Viewer mode

<shacl-form> not only is an RDF data editor, but can also be used as a viewer by setting attribute data-view and binding both, a shapes and a data graph. See the demo for an example.

Providing additional data to the shapes graph

Apart from setting the element attributes data-shapes or data-shapes-url, there are two ways of adding RDF data to the shapes graph:

  1. While parsing the triples of the shapes graph, any encountered owl:imports predicate that has a valid HTTP URL is fetched with the HTTP Accept header set to all of the supported MIME types. A successful response is parsed and added to a named graph. This graph is scoped (i.e. available) only to the node where the owl:import statement is defined on and all its sub nodes.

    The example shapes graph contains the following triples:

    example:Attribution
      sh:property [
        owl:imports <https://w3id.org/nfdi4ing/metadata4ing/> ;
        sh:name      "Role" ;
        sh:path      dcat:hadRole ;
        sh:class     prov:Role ;
      ] .

    In this case, the URL references an ontology which among other things defines instances of class prov:Role that are then used to populate the "Role" dropdown in the form. The imported ontology is available only for rendering and validating this specific property.

  2. The <shacl-form> element has a function setClassInstanceProvider((className: string) => Promise<string>) that registers a callback function which is invoked when a SHACL property has an sh:class predicate. The expected return value is a (promise of a) string (e.g. in format text/turtle) that contains RDF class instance definitions of the given class.

    In this example, the code:

    form.setClassInstanceProvider((clazz) => { 
      if (clazz === 'http://example.org/Material') {
        return `
          <http://example.org/steel>   a <http://example.org/Material>; <http://www.w3.org/2000/01/rdf-schema#label> "Steel".
          <http://example.org/wood>    a <http://example.org/Material>; <http://www.w3.org/2000/01/rdf-schema#label> "Wood".
          <http://example.org/alloy>   a <http://example.org/Material>; <http://www.w3.org/2000/01/rdf-schema#label> "Alloy".
          <http://example.org/plaster> a <http://example.org/Material>; <http://www.w3.org/2000/01/rdf-schema#label> "Plaster".
        `
      }}
    )

    returns instances of the class http://example.org/Material that are then used to populate the "Artwork material" dropdown in the form.

    A more realistic use case of this feature is calling some API endpoint to fetch class instance definitions from existing ontologies.

Use of SHACL sh:class

In case a property shape has a sh:class, all available graphs are scanned for instances of the given class to let the user choose from. rdfs:subClassOf is also considered when building the list of class instances.

shacl-form also supports class instance hierarchies modelled with skos:broader and/or skos:narrower. This is illustrated by the "Subject classification" property in the example.

SHACL constraints sh:or and sh:xone

<shacl-form> supports using sh:or and sh:xone to let users select between different options on nodes or properties. The example shapes graph has the following triples:

example:Attribution
  a sh:NodeShape ;
  sh:property [
    sh:maxCount  1 ;
    sh:minCount  1 ;
    sh:path prov:agent ;
    sh:or (
      [ sh:node example:Person ; rdfs:label "Person" ]
      [ sh:node example:Organisation ; rdfs:label "Organisation" ]
    )
  ] .

When adding a new attribution, <shacl-form> renders a dropdown to let the user select between the two options Person/Organisation. After selecting one of the options, the dropdown is replaced by the input fields of the selected node shape.

When binding an existing data graph to the form, the constraint is tried to be resolved depending on the respective data value:

  • For RDF literals, an sh:or option with a matching sh:datatype is chosen
  • For blank nodes or named nodes, the rdf:type of the value is tried to be matched with a node shape having a corresponding sh:targetClass or with a property shape having a corresponding sh:class. If there is no rdf:type but a sh:nodeKind of sh:IRI, the id of the the node is used as the value.

Linking existing data

In case a node shape has a sh:targetClass and any graph, i.e.

contains instances of that class, those can be linked in the respective SHACL property. The generated data graph will then just contain a reference to the instance, but not the triples that the instance consists of.

SHACL shape inheritance

SHACL defines two ways of inheriting shapes: sh:and and sh:node. <shacl-form> supports both. In this example, node shape example:ArchitectureModelDataset extends example:Dataset by defining the following RDF triple:

example:ArchitectureModelDataset sh:node example:Dataset .

Properties of inherited shapes are displayed first.

Plugins

Plugins can modify rendering of the form and add functionality to edit and view certain RDF datatypes or predicates (or a combination of both). As an example, the JavaScript of this page contains the following code:

import { LeafletPlugin } from '@ulb-darmstadt/shacl-form/plugins/leaflet.js'
const form = document.getElementById("shacl-form")
form.registerPlugin(new LeafletPlugin({ datatype: 'http://www.opengis.net/ont/geosparql#wktLiteral' }))

In effect, whenever a SHACL property has an sh:datatype of http://www.opengis.net/ont/geosparql#wktLiteral, the plugin is called to create the editor and/or viewer HTML elements. This specific plugin uses Leaflet to edit or view geometry in format well known text on a map. Custom plugins can be built by extending class Plugin.

Property grouping and collapsing

Properties can be grouped using sh:group in the shapes graph. This example defines a group "Physical properties" and assigns certain properties to it.

When the element attribute data-collapse is set, <shacl-form> creates an accordion-like widget that toggles the visibility of grouped properties in order to reduce the visual complexity of the form. If the grouped properties should initially be shown, set data-collapse="open".

Apart from grouped properties, all properties having an sh:node predicate and sh:maxCount != 1 are collapsed.

Supported RDF formats

Input formats

Output formats

  • text/turtle, application/n-triples, application/n-quads, application/trig using N3 writer
  • application/ld+json using jsonld

Use with Solid Pods

<shacl-form> can easily be integrated with Solid Pods. The output of toRDF() being a RDF/JS N3 Store, as explained above, it can be presented to solid-clients fromRdfJsDataset() function, which converts the RDF graph into a Solid Dataset. The following example, based on Inrupt's basic Solid Pod example shows how to merge data from a <shacl-form> with a Solid data resource at readingListDataResourceURI:

  // Authentication is assumed, resulting in a fetch able to read and write into the Pod
  try {
    // Get data out of the shacl-form
    const form = document.querySelector('shacl-form')

    // Extract the RDF graph from the form
    const shaclFormGraphStore = await form.toRDF()

    // Convert RDF store into a Solid dataset
    const shaclFormDataset = await fromRdfJsDataset(shaclFormGraphStore)

    // First get the current dataset
    myReadingList = await getSolidDataset(readingListDataResourceURI, { fetch: fetch })

    // get all things from the shaclFormDataset
    const shaclFormThings = getThingAll(shaclFormDataset)

    // add the things from ShaclForm to the existing set
    shaclFormThings.forEach((thing) => (myReadingList = setThing(myReadingList, thing)))

    // save the new dataset
    let savedReadingList = await saveSolidDatasetAt(readingListDataResourceURI, myReadingList, {
      fetch: fetch
    })

    // Other handling here

  } catch (err) {
    console.error(`Storing SHACL data from Form failed with error ${err}!`)
  }

Theming

<shacl-form> has a built-in abstraction layer for theming, i.e. the look and feel of the form elements. If you would like to employ a different theme like e.g. bootstrap or material design, then extend class Theme and call function setTheme() on the <shacl-form> element.