{"id":15462968,"url":"https://github.com/epa-wg/custom-element","last_synced_at":"2025-04-15T05:55:21.404Z","repository":{"id":63979980,"uuid":"569134208","full_name":"EPA-WG/custom-element","owner":"EPA-WG","description":"Declarative Custom Element ","archived":false,"fork":false,"pushed_at":"2025-02-08T06:49:04.000Z","size":937,"stargazers_count":26,"open_issues_count":44,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-15T05:55:13.330Z","etag":null,"topics":["html","webcomponents","xml","xslt"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EPA-WG.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}},"created_at":"2022-11-22T06:41:17.000Z","updated_at":"2025-04-08T13:04:22.000Z","dependencies_parsed_at":"2024-02-07T05:44:38.830Z","dependency_job_id":"bdd6fc40-4e93-4633-88c5-aa0107853f2f","html_url":"https://github.com/EPA-WG/custom-element","commit_stats":{"total_commits":59,"total_committers":1,"mean_commits":59.0,"dds":0.0,"last_synced_commit":"6ae43a7667ec3de966355c9edee371a7952672e4"},"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EPA-WG%2Fcustom-element","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EPA-WG%2Fcustom-element/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EPA-WG%2Fcustom-element/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EPA-WG%2Fcustom-element/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EPA-WG","download_url":"https://codeload.github.com/EPA-WG/custom-element/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249016320,"owners_count":21198832,"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":["html","webcomponents","xml","xslt"],"created_at":"2024-10-02T00:06:25.212Z","updated_at":"2025-04-15T05:55:21.386Z","avatar_url":"https://github.com/EPA-WG.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# custom-element\n`Declarative Custom Element` (DCE) is a part of pure `Declarative Web Application` stack. A proof of concept as a part of\n[WCCG in Declarative custom elements](https://github.com/w3c/webcomponents-cg/issues/32#issuecomment-1321037301) and [Declarative Web Application](https://github.com/EPA-WG/dwa#readme)\ndiscussion. **NO-JS** The functionality of DCE and its data access does not require programming using JavaScript.\n\nIt allows to define custom HTML tag with template filled from slots, attributes and data `slice` as of now from\n[local-storage][local-storage-demo],  [http-request][http-request-demo], [location][location-demo].\nUI is re-rendered on each data slice change triggered by initialization or DOM event.\n\n[![git][github-image] GitHub][git-url]\n| Live demo: [custom-element][demo-url]\n| Try in [Sandbox][sandbox-url]\n| [tests project][git-test-url]\n| [Chrome devtools pugin][plugin-url]\n\n[![NPM version][npm-image]][npm-url]\n[![coverage][coverage-image]][coverage-url]\n[![Published on webcomponents.org][webcomponents-img]][webcomponents-url]\n\n\n\n\u003cdetails\u003e\n\u003csummary\u003e What is DCE? \u003c/summary\u003e\nDCE provides the next level of abstraction in HTML - native composition. With native implementation which is\nstreaming parser, streaming transformation, multithreading. native assumes the C/Rust compiled code.\nThere is no place for JavaScript except of polyfill and ability to extend DCE, which otherwise has to be native.\n\nThe composition assumes the fully functional template and ability to call the template with parameters( custom tag + attributes) .\n\nAs the next to HTML abstraction layer - **composition**, it provides:\n* ability to use dependencies as from withing the page as from external file/lib via src attribute and # in URL\n* ability to treat external content via content-type like html, SVG, images, video with own template rendering\n* provide styles and embedded DCE declarations in own and named(lib) scope, sharing the scoped registry.\n\nAfter composition the layer of **functional component** provides\n* data layer with access to attributes/payload(+slots), dataset, data bound slice\n* means in template to use the data selector for condition/enumeration/text injection into attributes and DOM\n* Set of native primitives to support browser APIs declaratively: location,storage, http request which bonded to slice and as result to reactive UI.\n* support the data change trigger over events\n\nWhile DCE is no-JS concept, DCE provides the basic declarative constructs to build most of simple apps. Assuming the extending via custom elements and JS.  The evolution goal is to adopt most demanded APIs/construct natively into DCE stack over time.\n\nDCE is compatible with closed/open/named root. Enabling as site-scoped styling and registry as encapsulated anonymous scopes in shadow root.\n\nThis project is a POC( Proof of Concept ) targeting to become a base for native DCE implementation polyfill.\n\u003c/details\u003e\n\n# use\n\nUse the [bootstrap project](https://github.com/EPA-WG/custom-element-bootstrap) with all pre-configured or\n## install\nuse via CDN\n```html\n\u003cscript type=\"module\" src=\"https://unpkg.com/@epa-wg/custom-element@0.0/custom-element.js\"\u003e\u003c/script\u003e\n```\nNPM, yarn\n```shell\nnpm i -P @epa-wg/custom-element\nyarn add @epa-wg/custom-element\n```\n\n## Enable IDE support\n[IDE.md](ide/IDE.md)\n\n\n\n## [Live demo 🔗][demo-url]\n\n### Interactivity via data `slice` triggered by events\n```html\n\u003ccustom-element\u003e\n      \u003cinput slice=\"typed\"\u003e //slice/typed : {//slice/typed}\n\u003c/custom-element\u003e\n\n\u003ccustom-element\u003e\n    \u003ctemplate\u003e\n        \u003cbutton slice=\"clickcount\"\n                slice-event=\"click\"\n                slice-value=\"//clickcount + 1\" \u003e + \u003c/button\u003e\n        \u003cinput slice=\"clickcount\" type=\"number\" value=\"{//clickcount ?? 0}\"\u003e\n        Click count: { //clickcount }\n    \u003c/template\u003e\n\u003c/custom-element\u003e\n```\nMore on `slice` concept in [slice and events demo page][slice-demo-url]\n\n### Templating power\ncomes from XSLT and XPath. Which is natively implemented in all current browsers, globally tested and well documented.\n```html\n\n\u003ccustom-element tag=\"pokemon-tile\" hidden\u003e\n    \u003ch3\u003e{title}\u003c/h3\u003e \u003c!-- title is an attribute in instance\n                                                 mapped into /*/attributes/title --\u003e\n    \u003cif test=\"//smile\"\u003e                 \u003c!-- data-smile DCE instance attribute,\n                                                 mapped into /*/dataset/smile\n                                                 used in condition --\u003e\n                                            \u003c!-- data-smile DCE instance attribute, used as HTML --\u003e\n        \u003cdiv\u003eSmile as: {//smile} \u003c/div\u003e\n    \u003c/if\u003e\n    \u003c!-- image would not be visible in sandbox, see live demo --\u003e\n    \u003cimg src=\"https://unpkg.com/pokeapi-sprites@2.0.2/sprites/pokemon/other/dream-world/{pokemon-id}.svg\"\n         alt=\"{title} image\"/\u003e\n                                            \u003c!-- image-src and title are DCE instance attributes,\n                                                 mapped into /*/attributes/\n                                                 used within output attribute via curly brackets --\u003e\n\n                                            \u003c!-- `slot name=xxx` replaced with elements with `slot=xxx` attribute --\u003e\n    \u003cp\u003e\u003cslot name=\"description\"\u003e\u003ci\u003edescription is not available\u003c/i\u003e\u003c/slot\u003e\u003c/p\u003e\n\u003c/custom-element\u003e\n\n\u003cpokemon-tile title=\"bulbasaur\" data-smile=\"👼\" pokemon-id=\"1\" \u003e\n    \u003cp slot=\"description\"\u003eBulbasaur is a cute Pokémon born with a large seed firmly affixed to its back;\n        the seed grows in size as the Pokémon  does.\u003c/p\u003e\n\u003c/pokemon-tile\u003e\n\n\u003cpokemon-tile title=\"ninetales\" pokemon-id=\"38\" \u003e\u003c/pokemon-tile\u003e\n```\ngenerates HTML\n```html\n\u003cpokemon-tile title=\"bulbasaur\" data-smile=\"👼\"\n              image-src=\"https://unpkg.com/pokeapi-sprites@2.0.2/sprites/pokemon/other/dream-world/1.svg\"\n    \u003e\n    \u003ch3\u003ebulbasaur\u003c/h3\u003e\n    \u003cdiv\u003eSmile as: 👼\u003c/div\u003e\n    \u003cimg src=\"https://unpkg.com/pokeapi-sprites@2.0.2/sprites/pokemon/other/dream-world/1.svg\" alt=\"bulbasaur\"\u003e\n    \u003cp\u003eBulbasaur is a cute Pokémon born with a large seed firmly affixed to its back;\n                the seed grows in size as the Pokémon  does.\u003c/p\u003e\n\u003c/pokemon-tile\u003e\n\u003cpokemon-tile title=\"ninetales\"\n              image-src=\"https://unpkg.com/pokeapi-sprites@2.0.2/sprites/pokemon/other/dream-world/38.svg\"\n    \u003e\n    \u003ch3\u003eninetales\u003c/h3\u003e\n    \u003cimg src=\"https://unpkg.com/pokeapi-sprites@2.0.2/sprites/pokemon/other/dream-world/38.svg\" alt=\"ninetales\"\u003e\n    \u003cp\u003e\u003c/p\u003e\n\u003c/pokemon-tile\u003e\n```\n\n[![responsive hex grid demo][hex-grid-image] responsive hex-grid demo][hex-grid-url]\n, look into sources for samples of CSS encapsulation and external template use.\n\n\n# Implementation notes\n## Life cycle\n### `custom-element` declaration\n* constructor injects payload into XSL template\n* creates a class for custom element extending HTMLElement\n* registers element by `tag` attribute\n\nNOTE: attempt to register custom element with already registered tag name would fail due to w3c standard limitations.\nThe scoped custom element registry is still a proposal.\n\n### omitting `tag` leads to template instantiation\nWhether template is inline or given by `src` attribute, the `custom-element` would be instantiated inline if no `tag`\nattribute is given.\n\n### custom element instance\nconstructor creates XML with\n* root matching the tag\n* payload\n  * dom nodes with `slot` attribute stay inside\n* attributes\n* ?dataset\n\nDOM content is replaced with results of instance XML transformation by declaration XSLT.\n\n# `tag` attribute\nallows to define the Custom Element tag registered by `window.customElements.define()`.\n\nIf omitted, the tag is auto-generated and the content is rendered inline.\n```html\n\u003ccustom-element\u003e my tag is {tag} \u003c/custom-element\u003e\n```\nSee [demo](https://unpkg.com/@epa-wg/custom-element@0.0/demo/external-template.html) for `tag` attribute use.\n\n# `src` attribute\nallows to refer either external template or template within external library by `#id` hash in URL.\n\nSee [demo](https://unpkg.com/@epa-wg/custom-element@0.0/demo/external-template.html) with various samples.\n\n## types of template\n* HTML with DCE syntax ( slots, data slices, xslt operators, etc. )\n* SVG image, MathML, etc.\n* XSLT template. The `datadom` is the XML payload for transformation. In order to be embedded into external document,\nthis document has to have XML syntax like XHTML. Attempt of including XSLT within HTML file would break the template\nintegrity by parser.\n\n\n## `#id` Local reference\nallows to refer the template withing same document\n\n## `url`\nallows to use the external document as template\n\n## `url#id`\nallows to refer the template withing external document\n\n\n# template syntax\n[Scoped CSS][css-demo-url] live demo\n## styles encapsulation\nDCE can have the own styles which would be scoped to the instances.\nIn order to prevent the style leaking, it has to be defined withing `template` tag:\n```html\n\u003ccustom-element\u003e\n  \u003ctemplate\u003e\n    \u003cstyle\u003e\n        color: green;\n        button{ color: blue; }\n    \u003c/style\u003e\n    \u003clabel\u003e green \u003cbutton\u003eblue\u003c/button\u003e \u003c/label\u003e\n  \u003c/template\u003e\n\u003c/custom-element\u003e\n```\n\u003cfieldset\u003e\n  \u003clabel style=\"color: green\"\u003e green \u003cbutton style=\"color: blue\"\u003eblue\u003c/button\u003e \u003c/label\u003e\n\u003c/fieldset\u003e\n\n### override style for instance\nIn same way as in DCE itself:\n```html\n        \u003ccustom-element tag=\"dce-2\"\u003e\n            \u003ctemplate\u003e\u003c!-- template needed to avoid styles leaking into global HTML --\u003e\n                \u003cstyle\u003e\n                    button{ border: 0.2rem dashed blue; }\n                \u003c/style\u003e\n                \u003cbutton\u003e\u003cslot\u003eBlue borders\u003c/slot\u003e\u003c/button\u003e\n            \u003c/template\u003e\n        \u003c/custom-element\u003e\n        \u003cdce-2\u003edashed blue\u003c/dce-2\u003e\n        \u003cdce-2\u003e\n            \u003ctemplate\u003e \u003c!-- template needed to avoid styles leaking into global HTML --\u003e\n                \u003cstyle\u003ebutton{border-color:red;}\u003c/style\u003e\n                Red border\n            \u003c/template\u003e\n        \u003c/dce-2\u003e\n```\n## Attributes\nTo be served by IDE and to track the attributes changes, they have to be declared via `attribute`:\n```html\n    \u003ccustom-element tag=\"dce-with-attrs\" hidden\u003e\n        \u003cattribute name=\"p1\" \u003edefault_P1                \u003c/attribute\u003e\n        \u003cattribute name=\"p2\" select=\"'always_p2'\"       \u003e\u003c/attribute\u003e\n        \u003cattribute name=\"p3\" select=\"//p3 ?? 'def_P3' \" \u003e\u003c/attribute\u003e\n        p1: {$p1} \u003cbr/\u003e p2: {$p2} \u003cbr/\u003e p3: {$p3}\n    \u003c/custom-element\u003e\n    \u003cdce-with-attrs p1=\"123\" p3=\"qwe\"\u003e\u003c/dce-with-attrs\u003e\n```\n\nThe curly braces `{}` in attributes implemented as [attribute value template](https://www.w3.org/TR/xslt20/#attribute-value-templates)\n\nThe names in curly braces are matching the instance attributes. I.e. in XML node `/my-component/attributes/`.\n\nTo access payload XPath could start with `/*/payload/`. I.e. `{/*/payload//label}` refers to all `label` tags in payload.\n\n## Slots\n`\u003cslot name=\"xxx\"\u003e` is replaced by payload top elements with `slot` attribute matching the name,\ni.e.  slot `xxx` is matching `\u003ci slot=\"xxx\"\u003e...\u003c/i\u003e` in payload.\n```html\n\u003ccustom-element tag=\"with-description\" \u003e\n    \u003cslot name=\"description\"\u003edescription is not available\u003c/slot\u003e\n    \u003c!-- same as\n        \u003cvalue-of select='/*/payload/*[@slot=\"description\"]'/\u003e\n    --\u003e\n\u003c/custom-element\u003e\n\u003cwith-description\u003e\n    \u003cp slot=\"description\"\u003eBulbasaur is a cute Pokémon ...\u003c/p\u003e\n\u003c/with-description\u003e\n```\n\n## loops, variables\nLoop implemented via [for-each](https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/for-each)\n\n[Variables in XSLT](https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/variable)\n\n## [XPath](https://developer.mozilla.org/en-US/docs/Web/XSLT/Transforming_XML_with_XSLT/The_Netscape_XSLT_XPath_Reference)\nis available in `{}` in attributes, in `for-each`, `if`, `value-of`, and other XSL tags.\n\nXPath is a selector language to navigate over custom element instance data, attributes, and payload.\n\n## XSLT 1.0\nThe in-browser native implementation as of now supports [XSLT 1.0](https://www.w3.org/TR/xslt-10/).\nFile the [change request](https://github.com/EPA-WG/custom-element/issues) for support of another XSLT version or\ntemplate engine.\n\n# troubleshooting\n## HTML parser is not compatible with templates\nOn many tags like `table`, or link `a` the attempt to use XSLT operations could lead to DOM order mismatch to given\nin template. In such cases the `xhtml:` prefix in front of troubled tag would solve the parsing.\n\n```html\n\u003ccustom-element tag=\"dce-2\" hidden\u003e\n  \u003clocal-storage key=\"basket\" slice=\"basket\" live type=\"json\"\u003e\u003c/local-storage\u003e\n  \u003cxhtml:table xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"  \u003e\n    \u003cxhtml:tbody\u003e\n      \u003cfor-each select=\"//basket/@*\"\u003e\n        \u003cxhtml:tr\u003e\n          \u003cxhtml:th\u003e {name()} \u003c/xhtml:th\u003e\n          \u003cxhtml:td\u003e {.}      \u003c/xhtml:td\u003e\n        \u003c/xhtml:tr\u003e\n      \u003c/for-each\u003e\n    \u003c/xhtml:tbody\u003e\n    \u003cxhtml:tfoot\u003e\n      \u003cxhtml:tr\u003e\n        \u003cxhtml:td\u003e\u003cslot\u003e🤔\u003c/slot\u003e\u003c/xhtml:td\u003e\n        \u003cxhtml:th\u003e {sum(//slice/basket/@*)} \u003c/xhtml:th\u003e\n      \u003c/xhtml:tr\u003e\n    \u003c/xhtml:tfoot\u003e\n  \u003c/xhtml:table\u003e\n\u003c/custom-element\u003e\n```\nSee [demo source](demo/local-storage.html) for detailed sample.\n\n## Chrome devtools plugin\n[@epa-wg/custom-element plugin][plugin-url] gives the view into\n\n* `current` selected in DOM inspector node\n* Parent `customElement`\n* Declarative Custom Element `dce` for custom element ^^\n\n* `datadom` for easier inspection\n* `xml` as a string\n* `xslt` as a string\n\n## template debugging\n`xml` and `xslt` can be saved to file via for \"_copy string contents_\" into clipboard.\n\nThe XSLT debugger from your favorite IDE can set the breakpoints withing those files and\nrun transformation under debugger.\n\n\n## `{}` does not give a value\n* try to add as attribute you could observe and put the value of node name or text to identify the current location in data\nwithin template\n```xml\n\u003cb title=\"{name(*)} : {text()}\"\u003exml tag name: \u003cvalue-of select='name()'/\u003e\u003c/b\u003e\n```\n\n[git-url]:        https://github.com/EPA-WG/custom-element\n[git-test-url]:   https://github.com/EPA-WG/custom-element-dist\n[demo-url]:       https://unpkg.com/@epa-wg/custom-element@0.0/index.html\n[css-demo-url]:   https://unpkg.com/@epa-wg/custom-element@0.0/demo/scoped-css.html\n[slice-demo-url]:   https://unpkg.com/@epa-wg/custom-element@0.0/demo/data-slices.html\n[hex-grid-url]:   https://unpkg.com/@epa-wg/custom-element@0.0/demo/hex-grid.html\n[hex-grid-image]: https://unpkg.com/@epa-wg/custom-element@0.0.32/demo/hex-grid-transform.png\n[local-storage-demo]: https://unpkg.com/@epa-wg/custom-element@0.0/demo/local-storage.html\n[http-request-demo]:  https://unpkg.com/@epa-wg/custom-element@0.0/demo/http-request.html\n[location-demo]:  https://unpkg.com/@epa-wg/custom-element@0.0/demo/location.html\n[github-image]:   https://cdnjs.cloudflare.com/ajax/libs/octicons/8.5.0/svg/mark-github.svg\n[npm-image]:      https://img.shields.io/npm/v/@epa-wg/custom-element.svg\n[npm-url]:        https://npmjs.org/package/@epa-wg/custom-element\n[coverage-image]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.32/coverage/src/custom-element/coverage.svg\n[coverage-url]:   https://unpkg.com/@epa-wg/custom-element-dist@0.0.32/coverage/src/custom-element/index.html\n[storybook-url]:  https://unpkg.com/@epa-wg/custom-element-dist@0.0.32/storybook-static/index.html?path=/story/welcome--introduction\n[sandbox-url]:    https://stackblitz.com/github/EPA-WG/custom-element?file=index.html\n[webcomponents-url]: https://www.webcomponents.org/element/@epa-wg/custom-element\n[webcomponents-img]: https://img.shields.io/badge/webcomponents.org-published-blue.svg\n[plugin-url]:     https://chrome.google.com/webstore/detail/epa-wgcustom-element/hiofgpmmkdembdogjpagmbbbmefefhbl\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fepa-wg%2Fcustom-element","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fepa-wg%2Fcustom-element","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fepa-wg%2Fcustom-element/lists"}