{"id":20804347,"url":"https://github.com/joshbrew/DOMElement","last_synced_at":"2025-05-11T17:31:38.856Z","repository":{"id":49847545,"uuid":"426376663","full_name":"joshbrew/DOMElement","owner":"joshbrew","description":"Custom extended HTMLElement for easy webcomponent rendering","archived":false,"fork":false,"pushed_at":"2022-07-29T02:47:02.000Z","size":157,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-05T16:00:55.353Z","etag":null,"topics":["javascript","npm-package","webcomponent","webcomponents"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/joshbrew.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}},"created_at":"2021-11-09T20:27:59.000Z","updated_at":"2022-03-29T21:51:56.000Z","dependencies_parsed_at":"2022-09-08T00:40:50.191Z","dependency_job_id":null,"html_url":"https://github.com/joshbrew/DOMElement","commit_stats":null,"previous_names":["brainsatplay/domfragment","brainsatplay/domelement"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshbrew%2FDOMElement","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshbrew%2FDOMElement/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshbrew%2FDOMElement/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshbrew%2FDOMElement/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joshbrew","download_url":"https://codeload.github.com/joshbrew/DOMElement/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253604798,"owners_count":21934902,"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":["javascript","npm-package","webcomponent","webcomponents"],"created_at":"2024-11-17T19:08:52.826Z","updated_at":"2025-05-11T17:31:38.532Z","avatar_url":"https://github.com/joshbrew.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## DOMElement.js\n//By Joshua Brewster (AGPL v3.0)\n\n![fragelement-status](https://img.shields.io/npm/v/fragelement.svg) \n![fragelement-downloads](https://img.shields.io/npm/dt/fragelement.svg)\n![fragelem-size](https://img.shields.io/github/size/brainsatplay/DOMElement/DOMElement.js)\n![fragelem-l](https://img.shields.io/npm/l/fragelement)\n\n`npm i fragelement`\n\n[fragelement-based webcomponent app example](https://github.com/moothyknight/esbuild_base_webcomponents)\n\nThis is a simple wrapper for the native web components with template fragments in javascript.\n\n### DOMElement \nThis class extends the HTMLElement class and implements a template fragment rendering method:\n\n\nExtend it like:\n```js\nclass CustomElement extends DOMElement { \n  props={defaultprop:1}:\n  useShadow=false; //shadow DOM root? Allows scoped stylesheets, uses 'open' mode so it's further programmable from script.\n  styles=undefined //you can include a stylesheet template string here to trigger the shadow dom for scoped style sheets automatically, prepended to the template or inserted into head if its in the template. Triggers an html updated if already rendered.\n\n  //The template can be an imported html file when building in node.js for a better experience\n  template=(self,props)=\u003e{return `\u003cdiv\u003eNew Element: ${JSON.stringify(props)}\u003c/div\u003e`} \n         \n  oncreate=undefined, //(self,props)=\u003e{} when the node is created e.g. setting up buttons (props) =\u003e {}\n  ondelete=undefined, //(self,props)=\u003e{} when the node is deleted, e.g. cleaning up events (props) =\u003e {}\n  onresize=undefined, //(self,props =\u003e {} run on window.onresize event \n  onchanged=undefined, //if props change, e.g. re-render? (self,props) =\u003e {}. Using past tense to not conflict with built in onchange event in most elements\n  renderonchanged=false //(self,props) =\u003e {}  //true or a function fired after rerendering, will auto trigger rerenders when props changed\n  \n}\n\nCustomElement.addElement('custom-element'); //adds the custom class to the window's built-in customElementRegistry before instantiating the new element\n//if you don't provide a tag, the element will be registered as the classname plus a dash like 'customelement-'\n```\n \nwhere all that needs to be set is the template variable.\n\nThen this *should* work in html:\n\n```html\n\u003ccustomelement- props='{\"a\":\"1\",\"b\":\"2\",\"c\":\"3\"}'\u003e\u003ccustomelement- /\u003e \n```\nCan define props, onresize, onchanged, oncreate, ondelete, and even template just like other stock html functions. The prop onrenderchange if included will trigger the render function, and you can supply a function to fire after the fact.\n\n```js\nlet elm = document.querySelector('customelement-');\n\nelm.addEventListener('resized',(e) =\u003e {\n  console.log(e.target.props);\n});\n\nelm.addEventListener('changed',(e) =\u003e {\n  console.log(e.target.props);\n  //e.g. elm.render() //re-render the element\n});\n\nelm.addEventListener('deleted',(e) =\u003e {\n  console.log(e.target.props);\n});\n\nelm.addEventListener('rendered',(e) =\u003e {\n  console.log(e.target.props);\n});\n\n```\n\nCustom elements have to have a '-' in the names for whatever reason, they are auto added on the end of the class name if none specified in addElement\n\n\n### Styles:\n\nSet the `styles` property on the element to a template string of your style sheet contents and it will be prepended with the shadow root. You can set it on attributes on page init or in js and it will work. Otherwise if you want a shadow DOM root to use scoped stylesheets, set `elm.useShadow = true`.\n\n### Even more fun:\n\n```html\n\n\u003cbody\u003e\n    \u003cscript\u003e\n        function foo(x=123){ console.log(x); return 1; }\n    \u003c/script\u003e\n\n\n    \u003ccustomelement- \n      props='{\"a\":\"1\"}' \n      teststr=\"abc\" \n      testvalue=\"123\" \n      eval_foo=\"foo(456)\" \n      eval_boo=\"(inp)=\u003e{console.log('this is probably a dumb feature', inp); return 2; }\"\u003e\n    \u003c/customelement-\u003e\n\n    \u003cscript\u003e\n        let elem = document.getElementsByTagName('customelement-')[0];\n        console.log(Array.from(elem.attributes));\n        console.log(elem.boo('but hello world'));\n        console.log(elem.props);\n        console.log(elem.testvalue);\n    \u003c/script\u003e\n\u003c/body\u003e\n```\n\n### All methods in DOMElement:\n\n```js\n\nlet elm = new DOMElement()\n\ndocument.body.appendChild(elm) //add to body\n\nelm\n\n   .addElement(tag=this.tag, cls=this, extend=undefined) //static method to add this class to the dom, or some other class, input a tag or by default it uses the class name with a '-' on the end\n   \n   .render(props=this.props) //render the element with the props\n   \n   .delete() //delete the element and call the ondelete callback\n   \n   .state\n   \n          .setState(updateObj={}) //set state and trigger subscriptions for key:value pairs\n          \n          .subscribeTrigger(key,onchanged=(res)=\u003e{}) //subscribe a function when a key:value pair is updated by setState. returns an int\n          \n          .unsubscribeTrigger(key,sub) //unsubscribe using the int returned by subscribeTrigger\n          \n          .subscribeTriggerOnce(key,onchanged=(res)=\u003e{}) //subscribe a function to run once when a key:value pair is changed by setState({})\n          \n          .data //data object in state\n          \n   //internal functions\n   \n   .attributeChangedCallback(name, old, val) //when an observed attribute is updated run this function. Arbitrary attributes can be defined in the html tag, \n   //if 'eval_' is attached you can even add custom functions that are available on the element. E.g. elm.custom() (e.g. eval_custom='console.log('hello world')').\n   //Any arbitrary attributes can be get/set at any time as well, they will set the same key:value pair on props for conditional rendering purposes in the template.\n   \n   .connectedCallback() //runs when the element is connected to the DOM. \n          \n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshbrew%2FDOMElement","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoshbrew%2FDOMElement","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshbrew%2FDOMElement/lists"}