{"id":19313600,"url":"https://github.com/qkrdmstlr3/shell-html","last_synced_at":"2025-08-19T04:45:09.783Z","repository":{"id":57358239,"uuid":"382615272","full_name":"qkrdmstlr3/shell-html","owner":"qkrdmstlr3","description":"simple library for component-based front-end development using scss","archived":false,"fork":false,"pushed_at":"2021-07-10T15:26:30.000Z","size":229,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-09T15:57:04.610Z","etag":null,"topics":["component","custom-element","html-templa","shadowdom","shell-html","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/qkrdmstlr3.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-07-03T12:53:45.000Z","updated_at":"2022-06-19T23:20:51.000Z","dependencies_parsed_at":"2022-09-06T21:41:15.882Z","dependency_job_id":null,"html_url":"https://github.com/qkrdmstlr3/shell-html","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/qkrdmstlr3/shell-html","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qkrdmstlr3%2Fshell-html","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qkrdmstlr3%2Fshell-html/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qkrdmstlr3%2Fshell-html/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qkrdmstlr3%2Fshell-html/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/qkrdmstlr3","download_url":"https://codeload.github.com/qkrdmstlr3/shell-html/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qkrdmstlr3%2Fshell-html/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271103053,"owners_count":24699639,"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","status":"online","status_checked_at":"2025-08-19T02:00:09.176Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["component","custom-element","html-templa","shadowdom","shell-html","typescript"],"created_at":"2024-11-10T00:40:23.004Z","updated_at":"2025-08-19T04:45:09.729Z","avatar_url":"https://github.com/qkrdmstlr3.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# shell-html\n\n![version](https://img.shields.io/npm/v/shell-html)\n![dependencies](https://img.shields.io/badge/dependencies-none-success)\n![typescript](https://img.shields.io/badge/typescript-4.3.5-blue?logo=typescript)\n\n\u003e simple library for component-based front-end development using scss\n\nshell-html is a simple library implemented with about 300 lines using vanillaTS. It enables component-based development using web-component and shadowDOM. You can styling using with **SCSS**\n\n### Install\n\n```\nnpm install shell-html\n```\n\n## Examples\n\nproviding an **[example project](https://github.com/qkrdmstlr3/shell-html/tree/main/example/todo)** to show you how it works.\n\n## Docs\n\nexplained based on TypeScript. If you want to use Javascript, you can remove type declaration\n\n\u003ca href=\"#create\"\u003ecreate component\u003c/a\u003e\n\n\u003ca href=\"#use\"\u003ehow to render component\u003c/a\u003e\n\n\u003ca href=\"#methods\"\u003eshell-html methods\u003c/a\u003e\n\n\u003ca href=\"#localstate\"\u003emanage component local state\u003c/a\u003e\n\n\u003ca href=\"#globalstate\"\u003emanage component global state\u003c/a\u003e\n\n---\n\n### \u003cdiv id=\"create\"\u003eCreate Component\u003c/div\u003e\n\nTo create component, you need to import **ShellHTML** and **createComponent**.\nCreate a new class that extends shellhtml. You can render html tags inside render function returning below. To render component, you have to use createComponent. First argument is component name and second is Class.\n\n🟥 **Note** that the component name must contain `-`\n\n```typescript\n// firstComponent.ts\nimport { ShellHTML, createComponent } from \"shell-html\";\n\nclass FirstComponent extends ShellHTML {\n  render() {\n    return {\n      html: `\u003cdiv class=\"className\"\u003e\u003c/div\u003e`,\n    };\n  }\n}\n\ncreateComponent(\"first-component\", FirstComponent);\n```\n\n\u003cbr/\u003e\n\nIf you want to add a stylesheet to a component or register for an event, you can do something like this:\n\n```typescript\n// firstComponent.ts\nimport { ShellHTML, createComponent, EventType } from \"shell-html\";\nimport styleSheet from \"./style.scss\";\n\nclass FirstComponent extends ShellHTML {\n  clickHandler() {\n    console.log(\"clicked!\");\n  }\n\n  render() {\n    return {\n      html: `\u003cdiv class=\"className\"\u003e\u003c/div\u003e`,\n      css: styleSheet,\n      eventFuncs: [\n        {\n          className: \"className\",\n          func: this.clickHandler,\n          type: EventType.click,\n        },\n      ],\n    };\n  }\n}\n\ncreateComponent(\"first-component\", FirstComponent);\n```\n\n🟥 There are caveats when using stylesheet. The shell-html component is protected using **shadowDOM**. This means that direct access to the component from outside is not possible. Therefore, it is not affected by css declared outside the component. This makes it possible to use duplicate ids for different components, and saves you from worrying about naming classes so that they do not overlap.\n\nUsing with scss, you can remove duplicate style\n\n---\n\n### \u003cdiv id=\"use\"\u003eHow to render Component\u003c/div\u003e\n\nLook at how to render the created component to DOM. Rendering can be done in two ways. First, render the entry component to html (for example Layout). second is rendering a component from a component\n\nFirst way is very simple. you need `index.html` for rendering. and create one tag with id.\n\n```html\n\u003cbody\u003e\n  \u003cdiv id=\"root\"\u003e\u003c/div\u003e\n\u003c/body\u003e\n```\n\nDoesn't it seem like a form you've seen a lot somewhere? right. These tags are mainly used when developing SPA in react. To put a component under the #id tag, you must declare below code as follows in the entry file.\n\nThe render function allows the component of the first argument to be rendered to the tag of the second argument.\n\n```typescript\n// index.ts (entry file)\nimport { render } from \"shell-html\";\n\nrender(\"first-component\", document.getElementById(\"root\"));\n```\n\n\u003cbr/\u003e\n\nLet's look at the code first to explain the second method.\n\n```typescript\n// secondComponent.ts\nimport { ShellHTML, createComponent } from \"shell-html\";\n\nclass LayoutComponent extends ShellHTML {\n  render() {\n    return {\n      html: `\n        \u003cdiv\u003e\n          \u003cfirst-component id=\"first\"\u003e\u003c/first-component\u003e\n          \u003csecond-component id=\"second\"\u003e\u003c/second-component\u003e\n        \u003c/div\u003e\n        `,\n    };\n  }\n}\n\ncreateComponent(\"layout-component\", LayoutComponent);\n```\n\nDon't you feel it how to use it? Just use the declared tag!\n\n🟥 Note that you have to specify the id. Because shell-html uses an existing component instead of creating a new component by comparing the ID, you must give it an ID. The id value must not be duplicated within one component\n\n---\n\n### \u003cdiv id=\"methods\"\u003eshell-html methods\u003c/div\u003e\n\nshell-html is custom-element based. So shell-html supports two functions in custom-element.\n\nIt were **connectedCallback** and **disconnectedCallback**. connectedCallback function called when component is attatched to DOM. You can enroll something in this function. disconnectedCallback function called when component is removed from DOM. You can release something in this function.\n\n🟥If you enroll something but not release that, it can lead to memory leaks\n\n```typescript\nimport { ShellHTML, createComponent, EventType } from \"shell-html\";\nimport styleSheet from \"./style.scss\";\n\nclass FirstComponent extends ShellHTML {\n  connectedCallback() {\n    // executed when component attatch to DOM\n  }\n\n  disconnectedCallback() {\n    // executed when component remove from DOM\n  }\n\n  render() {\n    return {\n      ...\n    };\n  }\n}\n\ncreateComponent(\"first-component\", FirstComponent);\n```\n\nshell-html also provide getElementsById and querySelector like below code:\n\n```typescript\nimport { ShellHTML, createComponent, EventType } from \"shell-html\";\nimport styleSheet from \"./style.scss\";\n\nclass FirstComponent extends ShellHTML {\n  clickHandler() {\n    const element1 = this.getElementById(\"id\")\n    const element2 = this.querySelector(\"tag\")\n  }\n\n  render() {\n    return {\n      ...\n    };\n  }\n}\n\ncreateComponent(\"first-component\", FirstComponent);\n```\n\n---\n\n### \u003cdiv id=\"localstate\"\u003emanage component local state\u003c/div\u003e\n\nshell-html supports **state** inside components. you can init initial value by passing an argument to the super function of the constructor. State is accessible via `this.state`. And you can change the state through `this.setState` function. When the state changes, the component is re-rendered. (\nstate guarantees immutability)\n\n```typescript\n// firstComponent.ts\nimport { ShellHTML, createComponent, EventType } from \"shell-html\";\nimport styleSheet from \"./style.scss\";\n\nclass FirstComponent extends ShellHTML {\n  constructor() {\n    // init initial state\n    super(\"hello\");\n  }\n\n  clickHandler() {\n    // change state\n    this.setState(\"world\");\n  }\n\n  render() {\n    // use state\n    const value = this.state;\n\n    return {\n      html: `\u003cdiv class=\"className\"\u003e${value}\u003c/div\u003e`,\n      css: styleSheet,\n      eventFuncs: [\n        {\n          className: \"className\",\n          func: this.clickHandler,\n          type: EventType.click,\n        },\n      ],\n    };\n  }\n}\n\ncreateComponent(\"first-component\", FirstComponent);\n```\n\n---\n\n### \u003cdiv id=\"globalstate\"\u003emanage component global state\u003c/div\u003e\n\nshell-html's component has a big disadvantage which is it cannot send and receive props like react. So it supports its own global state management.\n\nTo use global state you have to declare global state to entry file. You need to pass an object to the state function. The key value of an object must be unique and is an identifier that distinguishes the global state. init value is an initialization value\n\n```typescript\n// index.ts(entry file)\nimport { state } from \"shell-html\";\n\nstate({\n  key: \"state\",\n  init: { name: \"hello\" },\n});\n```\n\nThe shell html provides two functions for handling global state. The useglobalstate function is a function to get the global state value. If you pass the key value of the global state you want to get, the state is returned. setglobalstate changes the value of the global state. Additionally, you only need to pass the value to be changed as the second argument.\n\n```typescript\n// firstComponent.ts\nimport {\n  ShellHTML,\n  createComponent,\n  EventType,\n  useGlobalState,\n  getGlobalState,\n} from \"shell-html\";\nimport styleSheet from \"./style.scss\";\n\nclass FirstComponent extends ShellHTML {\n  clickHandler() {\n    // change state\n    setGlobalState(\"state\", { name: \"world\" });\n  }\n\n  render() {\n    // use state\n    const value = useGlobalState(\"state\");\n\n    return {\n      html: `\u003cdiv class=\"className\"\u003e${value}\u003c/div\u003e`,\n      css: styleSheet,\n      eventFuncs: [\n        {\n          className: \"className\",\n          func: this.clickHandler,\n          type: EventType.click,\n        },\n      ],\n    };\n  }\n}\n\ncreateComponent(\"first-component\", FirstComponent);\n```\n\nHowever, in order for the component to be re-rendered when the globalstate is changed, one additional operation must be performed. You can start and disable global state monitoring through enrollObserving and releaseObserving. Just need to pass the key name\n\n🟥 If you use enrollObserving function, you have to use releaseObserving too. If you don't, memory leaks occur.\n\n```typescript\nimport {\n  ShellHTML,\n  createComponent,\n  EventType,\n  useGlobalState,\n  getGlobalState,\n} from \"shell-html\";\nimport styleSheet from \"./style.scss\";\n\nclass FirstComponent extends ShellHTML {\n  connectedCallback() {\n    // enroll\n    this.enrollObserving(\"state\");\n  }\n\n  disconnectedCallback() {\n    // release\n    this.releaseObserving(\"state\");\n  }\n\n  clickHandler() {\n    setGlobalState(\"state\", { name: \"world\" });\n  }\n\n  render() {\n    const value = useGlobalState(\"state\");\n\n    return {\n      html: `\u003cdiv class=\"className\"\u003e${value}\u003c/div\u003e`,\n      css: styleSheet,\n      eventFuncs: [\n        {\n          className: \"className\",\n          func: this.clickHandler,\n          type: EventType.click,\n        },\n      ],\n    };\n  }\n}\n\ncreateComponent(\"first-component\", FirstComponent);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqkrdmstlr3%2Fshell-html","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqkrdmstlr3%2Fshell-html","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqkrdmstlr3%2Fshell-html/lists"}