{"id":13891327,"url":"https://github.com/ULB-Darmstadt/shacl-form","last_synced_at":"2025-07-17T04:31:39.867Z","repository":{"id":65202535,"uuid":"587204629","full_name":"ULB-Darmstadt/shacl-form","owner":"ULB-Darmstadt","description":"HTML5 web component for editing/viewing RDF data that conform to SHACL shapes","archived":false,"fork":false,"pushed_at":"2024-07-16T07:02:49.000Z","size":773,"stargazers_count":20,"open_issues_count":1,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-07-19T17:18:06.306Z","etag":null,"topics":["editor","rdf","shacl","validation","viewer"],"latest_commit_sha":null,"homepage":"https://ulb-darmstadt.github.io/shacl-form/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ULB-Darmstadt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-10T07:49:43.000Z","updated_at":"2024-07-24T09:46:57.969Z","dependencies_parsed_at":"2024-07-08T08:26:55.824Z","dependency_job_id":"91aa3bd0-234c-41d4-93b7-e9de853249b6","html_url":"https://github.com/ULB-Darmstadt/shacl-form","commit_stats":null,"previous_names":[],"tags_count":37,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ULB-Darmstadt%2Fshacl-form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ULB-Darmstadt%2Fshacl-form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ULB-Darmstadt%2Fshacl-form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ULB-Darmstadt%2Fshacl-form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ULB-Darmstadt","download_url":"https://codeload.github.com/ULB-Darmstadt/shacl-form/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226171768,"owners_count":17584911,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["editor","rdf","shacl","validation","viewer"],"created_at":"2024-08-06T16:01:35.999Z","updated_at":"2025-07-17T04:31:39.852Z","avatar_url":"https://github.com/ULB-Darmstadt.png","language":"TypeScript","funding_links":[],"categories":["Declarative UIs","TypeScript"],"sub_categories":[],"readme":"# SHACL Form Generator\n\n```console\nnpm i @ulb-darmstadt/shacl-form\n```\n\nHTML5 web component for editing/viewing [RDF](https://www.w3.org/RDF/) data that conform to [SHACL shapes](https://www.w3.org/TR/shacl/).\n\n## [See demo here](https://ulb-darmstadt.github.io/shacl-form/)\n\n### Basic usage\n\n```html\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003c!-- load web component --\u003e\n    \u003cscript src=\"https://cdn.jsdelivr.net/npm/@ulb-darmstadt/shacl-form/dist/form-default.js\" type=\"module\"\u003e\u003c/script\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003c!--\n      SHACL shapes can be defined on the attribute 'data-shapes'\n      or can be loaded by setting attribute 'data-shapes-url'\n    --\u003e\n    \u003cshacl-form data-shapes=\"\n      @prefix sh:   \u003chttp://www.w3.org/ns/shacl#\u003e .\n      @prefix rdfs: \u003chttp://www.w3.org/2000/01/rdf-schema#\u003e .\n      @prefix ex:   \u003chttp://example.org#\u003e .\n\n      ex:ExampleShape\n        a sh:NodeShape, rdfs:Class ;\n        sh:property [\n          sh:name 'my value' ;\n          sh:path ex:exampleValue ;\n          sh:maxCount 3 ;\n        ] .\n    \"\u003e\u003c/shacl-form\u003e\n\n    \u003cscript\u003e\n      const form = document.querySelector(\"shacl-form\")\n      form.addEventListener('change', event =\u003e {\n        // check if form data validates according to the SHACL shapes\n        if (event.detail?.valid) {\n          // get data graph as RDF triples and\n          // log them to the browser console\n          const triples = form.serialize() \n          console.log('entered form data', triples)\n          // store the data somewhere, e.g. in a triple store\n        }\n      })\n    \u003c/script\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n### Element attributes\n\nAttribute | Description\n---|---\ndata-shapes | SHACL shape definitions (e.g. a turtle string) to generate the form from\ndata-shapes-url | When `data-shapes` is not set, the SHACL shapes are loaded from this URL\ndata-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\ndata-values | RDF triples (e.g. a turtle string) to use as existing data graph to fill the form\ndata-values-url | When `data-values` is not set, the data graph triples are loaded from this URL\ndata-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\ndata-values-namespace | RDF namespace to use when generating new RDF subjects. Default is empty, so that subjects will be blank nodes.\ndata-values-graph | If set, serializing the form will create a named graph with the given IRI.\ndata-language | Language to use if shapes contain langStrings, e.g. in `sh:name` or `rdfs:label`. Default is [`navigator.language`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/language) with fallback to [`navigator.languages`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/languages)\ndata-loading | Text to display while the web component is initializing. Default: `\"Loading...\"`\ndata\u0026#x2011;ignore\u0026#x2011;owl\u0026#x2011;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\ndata-view | When set, turns the web component into a viewer that displays the given data graph without editing functionality\ndata-collapse | When set, `sh:group`s 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\"`\ndata-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\ndata-generate-node-shape-reference | When generating the RDF data graph, \u0026lt;shacl-form\u0026gt; can create a triple that references the root `sh:NodeShape` of the data. Suggested values for this attribute are `http://www.w3.org/1999/02/22-rdf-syntax-ns#type` or `http://purl.org/dc/terms/conformsTo`. Default is empty, so that no such triple is created\ndata-show-node-ids | When this attribute is set, shacl node shapes will have their subject id shown in the form\n\n### Element functions\n\n\u003ca id=\"toRDF\"\u003e\u003c/a\u003e\n```typescript\ntoRDF(graph?: Store): Store\n```\nAdds the form values as RDF triples to the given graph. If no graph object is provided, creates a new [N3 Store](https://github.com/rdfjs/N3.js#storing).\n\n```typescript\nserialize(format?: string, graph?: Store): string\n```\nSerializes 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. \u003ca name=\"formats\"\u003e\u003c/a\u003eSupported formats:  `text/turtle` (default), `application/ld+json`, `application/n-triples`, `application/n-quads`, `application/trig`.\n\n```typescript\nvalidate(ignoreEmptyValues: boolean): Promise\u003cboolean\u003e\n```\nValidates 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.\n\n```typescript\nregisterPlugin(plugin: Plugin)\n```\nRegister a [plugin](./src/plugin.ts) to customize editing/viewing certain property values. Plugins handle specific RDF predicates or `xsd:datatype`s or both. Examples: [Leaflet](./src/plugins/leaflet.ts), [Mapbox](./src/plugins/mapbox.ts), [FixedList](./src/plugins/fixed-list.ts)\n\n```typescript\nsetTheme(theme: Theme)\n```\nSet a design theme to use for rendering. See section [Theming](#Theming).\n\n```typescript\nsetClassInstanceProvider((className: string) =\u003e Promise\u003cstring\u003e)\n```\nSets a callback function that is invoked when a SHACL property has an `sh:class` definition to retrieve class instances. See [below](#classInstanceProvider) for more information.\n\n```typescript\nsetSharedShapesGraph(graph: Store)\n```\nSet an externally managed shapes graph to use. This improves performance When using multiple instances of `shacl-form` on the same page. Note that the shape triples need to be stored in the graph with ID `shapes` to be recognized.\n\n## Features\n\n### Validation\n\nIn edit mode, `\u003cshacl-form\u003e` validates the constructed data graph using the library [shacl-engine](https://github.com/rdf-ext/shacl-engine) and displays validation results as icons next to the respective form fields.\n\n### Data graph binding\n\n`\u003cshacl-form\u003e` 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.\n\n### Viewer mode\n\n`\u003cshacl-form\u003e` 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](https://ulb-darmstadt.github.io/shacl-form/#viewer-mode) for an example.\n\n### Providing additional data to the shapes graph\n\nApart from setting the element attributes `data-shapes` or `data-shapes-url`, there are two ways of adding RDF data to the shapes graph:\n1. While parsing the triples of the shapes graph, any encountered `owl:imports` predicate that has a valid HTTP URL value will be tried to fetch with the HTTP Accept header set to all of the [supported](#formats) MIME types. A successful response will be parsed and added to the shapes graph. The [example shapes graph](https://ulb-darmstadt.github.io/shacl-form/#example) contains the following triples:\n    ```\n    example:Attribution\n      owl:imports \u003chttps://w3id.org/nfdi4ing/metadata4ing/\u003e ;\n      sh:property [\n        sh:name      \"Role\" ;\n        sh:path      dcat:hadRole ;\n        sh:class     prov:Role ;\n      ] .\n    ```\n    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.\n\n2. \u003ca id=\"classInstanceProvider\"\u003e\u003c/a\u003eThe `\u003cshacl-form\u003e` element has a function `setClassInstanceProvider((className: string) =\u003e Promise\u003cstring\u003e)` that registers a callback function which is invoked when a SHACL property has\nan `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.\n  \n    Class hierarchies can be built using `rdfs:subClassOf`. Instance hierarchies can be modeled e.g. like:\n    ```\n    ex:parent a ex:Class .\n    ex:child rdfs:subClassOf ex:parent; a ex:parent .\n    ex:grandchild rdfs:subClassOf ex:child; a ex:child .\n    ```\n    \n    In [this example](https://ulb-darmstadt.github.io/shacl-form/#example), the code:\n  \n    ```typescript\n    form.setClassInstanceProvider((clazz) =\u003e { \n      if (clazz === 'http://example.org/Material') {\n        return `\n          \u003chttp://example.org/steel\u003e   a \u003chttp://example.org/Material\u003e; \u003chttp://www.w3.org/2000/01/rdf-schema#label\u003e \"Steel\".\n          \u003chttp://example.org/wood\u003e    a \u003chttp://example.org/Material\u003e; \u003chttp://www.w3.org/2000/01/rdf-schema#label\u003e \"Wood\".\n          \u003chttp://example.org/alloy\u003e   a \u003chttp://example.org/Material\u003e; \u003chttp://www.w3.org/2000/01/rdf-schema#label\u003e \"Alloy\".\n          \u003chttp://example.org/plaster\u003e a \u003chttp://example.org/Material\u003e; \u003chttp://www.w3.org/2000/01/rdf-schema#label\u003e \"Plaster\".\n        `\n      }}\n    )\n    ```\n    returns instances of the class `http://example.org/Material` that are then used to populate the \"Artwork material\" dropdown in the form.\n\n    A more realistic use case of this feature is calling some API endpoint to fetch class instance definitions from existing ontologies.\n\n### SHACL \"or\" and \"xone\" constraint\n\n`\u003cshacl-form\u003e` supports using [sh:or](https://www.w3.org/TR/shacl/#OrConstraintComponent) and [sh:xone](https://www.w3.org/TR/shacl/#XoneConstraintComponent) to let users select between different options on nodes or properties.\nThe [example shapes graph](https://ulb-darmstadt.github.io/shacl-form/#example) has the following triples:\n```\nexample:Attribution\n  a sh:NodeShape ;\n  sh:property [\n    sh:maxCount  1 ;\n    sh:minCount  1 ;\n    sh:path prov:agent ;\n    sh:or (\n      [ sh:node example:Person ; rdfs:label \"Person\" ]\n      [ sh:node example:Organisation ; rdfs:label \"Organisation\" ]\n    )\n  ] .\n```\nWhen adding a new attribution, `\u003cshacl-form\u003e` 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.\n\nWhen binding an existing data graph to the form, the constraint is tried to be resolved depending on the respective data value:\n- For RDF literals, an `sh:or` option with a matching `sh:datatype` is chosen\n- 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.\n\n### Linking existing data\n\nIn case a node shape has a `sh:targetClass` and any graph, i.e.\n- the shapes graph\n- the data graph\n- any graph loaded by `owl:imports`\n- triples provided by [classInstanceProvider](#classInstanceProvider)\n\ncontains instances of that class, those can be linked in the respective SHACL property. In effect, the generated data graph will just contain a reference to the instance, but not the triples that the instance consists of.\n\n### SHACL shape inheritance\n\nSHACL defines two ways of inheriting shapes: [sh:and](https://www.w3.org/TR/shacl/#AndConstraintComponent)\nand [sh:node](https://www.w3.org/TR/shacl/#NodeConstraintComponent). `\u003cshacl-form\u003e` supports both. In [this example](https://ulb-darmstadt.github.io/shacl-form/#example), node shape `example:ArchitectureModelDataset` extends `example:Dataset` by defining the following RDF triple:\n\n```\nexample:ArchitectureModelDataset sh:node example:Dataset .\n```\n\nProperties of inherited shapes are displayed first.\n\n### Plugins\n\nPlugins 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](https://ulb-darmstadt.github.io/shacl-form/#example) contains the following code:\n```typescript\nimport { LeafletPlugin } from '@ulb-darmstadt/shacl-form/plugins/leaflet.js'\nconst form = document.getElementById(\"shacl-form\")\nform.registerPlugin(new LeafletPlugin({ datatype: 'http://www.opengis.net/ont/geosparql#wktLiteral' }))\n```\nIn 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](https://leafletjs.com/) to edit or view geometry in format [well known text](http://giswiki.org/wiki/Well_Known_Text) on a map.\nCustom plugins can be built by extending class [Plugin](https://github.com/ULB-Darmstadt/shacl-form/blob/main/src/plugin.ts#L40).\n\n### Property grouping and collapsing\n\nProperties can be grouped using [sh:group](https://www.w3.org/TR/shacl/#group) in the shapes graph. [This example](https://ulb-darmstadt.github.io/shacl-form/#example) defines a group \"Physical properties\" and assigns certain properties to it.\n\nWhen the element attribute `data-collapse` is set, `\u003cshacl-form\u003e` 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\"`.\n\nApart from grouped properties, all properties having an `sh:node` predicate and `sh:maxCount` != 1 are collapsed.\n\n### Use with Solid Pods\n\n`\u003cshacl-form\u003e` can easily be integrated with [Solid Pods](https://solidproject.org/about). The output of `toRDF()` being a RDF/JS N3 Store, as explained [above](#toRDF), it can be presented to `solid-client`s `fromRdfJsDataset()` function, which converts the RDF graph into a Solid Dataset. The following example, based on Inrupt's basic [Solid Pod example](https://docs.inrupt.com/developer-tools/javascript/client-libraries/tutorial/getting-started/) shows how to merge data from a `\u003cshacl-form\u003e` with a Solid data resource at `readingListDataResourceURI`:\n \n```js\n  // Authentication is assumed, resulting in a fetch able to read and write into the Pod\n  try {\n    // Get data out of the shacl-form\n    const form = document.querySelector('shacl-form')\n\n    // Extract the RDF graph from the form\n    const shaclFormGraphStore = await form.toRDF()\n\n    // Convert RDF store into a Solid dataset\n    const shaclFormDataset = await fromRdfJsDataset(shaclFormGraphStore)\n\n    // First get the current dataset\n    myReadingList = await getSolidDataset(readingListDataResourceURI, { fetch: fetch })\n\n    // get all things from the shaclFormDataset\n    const shaclFormThings = getThingAll(shaclFormDataset)\n\n    // add the things from ShaclForm to the existing set\n    shaclFormThings.forEach((thing) =\u003e (myReadingList = setThing(myReadingList, thing)))\n\n    // save the new dataset\n    let savedReadingList = await saveSolidDatasetAt(readingListDataResourceURI, myReadingList, {\n      fetch: fetch\n    })\n\n    // Other handling here\n\n  } catch (err) {\n    console.error(`Storing SHACL data from Form failed with error ${err}!`)\n  }\n```\n\n### Theming\n\n`\u003cshacl-form\u003e` comes in 3 different bundles, each providing a specific theme. See the [demo page](https://ulb-darmstadt.github.io/shacl-form/#theming) for an example.\n\nTheme | Import statement\n--- | ---\n[Default](./src/themes/default.ts) (slightly customized default browser styles) | `import '@ulb-darmstadt/shacl-form/form-default.js'`\n[Bootstrap](./src/themes/bootstrap.ts) [alpha status] | `import '@ulb-darmstadt/shacl-form/form-bootstrap.js'`\n[Material Design](./src/themes/material.ts) [alpha status] | `import '@ulb-darmstadt/shacl-form/form-material.js'`\n\nCustom themes can be employed by extending class [Theme](./src/theme.ts), then calling function `setTheme()` on the `\u003cshacl-form\u003e` element.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FULB-Darmstadt%2Fshacl-form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FULB-Darmstadt%2Fshacl-form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FULB-Darmstadt%2Fshacl-form/lists"}