{"id":21754655,"url":"https://github.com/aegisjsproject/core","last_synced_at":"2026-01-16T10:01:03.308Z","repository":{"id":219198787,"uuid":"748326116","full_name":"AegisJSProject/core","owner":"AegisJSProject","description":"A fast, secure, modern, light-weight, and simple  JS library for creating web components and more!","archived":false,"fork":false,"pushed_at":"2026-01-12T18:23:18.000Z","size":1006,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-01-12T23:58:06.080Z","etag":null,"topics":["aegis","component-library","constructable-stylesheets","css","custom-elements","dom","html","html-templates","sanitizer-api","security","web-components"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@aegisjsproject/core","language":"JavaScript","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/AegisJSProject.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"shgysk8zer0","liberapay":"shgysk8zer0"}},"created_at":"2024-01-25T18:39:09.000Z","updated_at":"2026-01-12T18:14:59.000Z","dependencies_parsed_at":"2026-01-08T19:04:22.929Z","dependency_job_id":null,"html_url":"https://github.com/AegisJSProject/core","commit_stats":null,"previous_names":["shgysk8zer0/aegis","aegisjsproject/core"],"tags_count":50,"template":false,"template_full_name":"shgysk8zer0/npm-template","purl":"pkg:github/AegisJSProject/core","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AegisJSProject%2Fcore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AegisJSProject%2Fcore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AegisJSProject%2Fcore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AegisJSProject%2Fcore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AegisJSProject","download_url":"https://codeload.github.com/AegisJSProject/core/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AegisJSProject%2Fcore/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28478049,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T06:30:42.265Z","status":"ssl_error","status_checked_at":"2026-01-16T06:30:16.248Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["aegis","component-library","constructable-stylesheets","css","custom-elements","dom","html","html-templates","sanitizer-api","security","web-components"],"created_at":"2024-11-26T09:14:40.272Z","updated_at":"2026-01-16T10:01:02.826Z","avatar_url":"https://github.com/AegisJSProject.png","language":"JavaScript","funding_links":["https://github.com/sponsors/shgysk8zer0","https://liberapay.com/shgysk8zer0","https://liberapay.com/shgysk8zer0/donate"],"categories":[],"sub_categories":[],"readme":"# `@aegisjsproject/core`\n\nA fast, secure, modern, light-weight, and simple JS library for creating web components and more! \n\n[![CodeQL](https://github.com/AegisJSProject/core/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/AegisJSProject/core/actions/workflows/codeql-analysis.yml)\n![Node CI](https://github.com/AegisJSProject/core/workflows/Node%20CI/badge.svg)\n![Lint Code Base](https://github.com/AegisJSProject/core/workflows/Lint%20Code%20Base/badge.svg)\n\n[![GitHub license](https://img.shields.io/github/license/AegisJSProject/core.svg)](https://github.com/AegisJSProject/core/blob/master/LICENSE)\n[![GitHub last commit](https://img.shields.io/github/last-commit/AegisJSProject/core.svg)](https://github.com/AegisJSProject/core/commits/master)\n[![GitHub release](https://img.shields.io/github/release/AegisJSProject/core?logo=github)](https://github.com/AegisJSProject/core/releases)\n[![GitHub Sponsors](https://img.shields.io/github/sponsors/shgysk8zer0?logo=github)](https://github.com/sponsors/shgysk8zer0)\n\n[![npm](https://img.shields.io/npm/v/@aegisjsproject/core)](https://www.npmjs.com/package/@aegisjsproject/core)\n![node-current](https://img.shields.io/node/v/@aegisjsproject/core)\n![npm bundle size](https://img.shields.io/bundlephobia/minzip/%40aegisjsproject%2Fcore)\n[![npm](https://img.shields.io/npm/dw/@aegisjsproject/core?logo=npm)](https://www.npmjs.com/package@/aegisjsproject/core)\n\n[![GitHub followers](https://img.shields.io/github/followers/AegisJSProject.svg?style=social)](https://github.com/AegisJSProject)\n![GitHub forks](https://img.shields.io/github/forks/AegisJSProject/core.svg?style=social)\n![GitHub stars](https://img.shields.io/github/stars/AegisJSProject/core.svg?style=social)\n[![Twitter Follow](https://img.shields.io/twitter/follow/shgysk8zer0.svg?style=social)](https://twitter.com/shgysk8zer0)\n\n[![Donate using Liberapay](https://img.shields.io/liberapay/receives/shgysk8zer0.svg?logo=liberapay)](https://liberapay.com/shgysk8zer0/donate \"Donate using Liberapay\")\n- - -\n\n- [Code of Conduct](./.github/CODE_OF_CONDUCT.md)\n- [Contributing](./.github/CONTRIBUTING.md)\n\u003c!-- - [Security Policy](./.github/SECURITY.md) --\u003e\n\n## Installation\n\n### CDN / `unpkg.com`\n\nThe preferred method of using Aegis is via `import` from `https://unpkg.com/aegisjsproject/core[@:version]`.\nYou may use [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity),\nbut this is only recommended *if* you include a version in the script URL. For\nconvenience, you maybe desire using [`\u003cscript type=\"importmap\"\u003e`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) in your development setup and a plug-in such as\n[`@shgysk8zer0/rollup-import`](https://www.npmjs.com/package/@shgysk8zer0/rollup-import)\nwhen bundling for production.\n\n### NPM/Node\n\nOf course, you could always stick with the the more familiar package installation:\n\n```bash\nnpm install aegisjsproject/core\n```\n\nThat works just fine, should you prefer.\n\n### Git Submodule\n\nA final option is installing via a [git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules).\n\n```bash\ngit submodule add https://github.com/AegisJSProject/core.git [:destination_path]\n```\n\nSubmodules ultimately make little difference compared to the CDN or installing the\npackage, should you prefer that option. There are no dependencies, and you probably\njust end up using a different source/URL for your `\u003cscript\u003e` or `import`. The one\nand only difference to consider is that this will not include the generated CommonJS\n(use for `require()`) version.\n\n## Security\n\nThis library is designed with security, and specifically strict [Content-Security-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy) and [`TrustedTypes`](https://developer.mozilla.org/en-US/docs/Web/API/trustedTypes), in mind.\n\nHowever, since the [Sanitizer API](https://github.com/WICG/sanitizer-api) is an\nin-development API and [`new CSStyleSheet()`](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet)\nis not universally supported, the polyfills require some minimal adjustments to\nany Content-Security-Policy:\n\n### CSP - `script-src`\n\nFor the recommended polyfills, allowing script from `https://unpkg.com/@shgysk8zer0/`\n(you can be more restrictive/specific to `https://unkg.com/@shgysk8zer0/polyfills@:version`) will\nbe necessary.\n\n### CSP - `style-src`\n\nThe recommended polyfill for `new CSSStyleSheet()` and `adoptedStyleSheets` requires\nuse of `URL.createObejctURL()`. As such, `style-src` is suggested to allow `blob:` URIs.\n\n### CSP - `trusted-types`\n\nFor the sake of the Sanitizer API polyfill, if you have `trusted-types` as part\nof your CSP, you must allow `empty#html` and `empty#script` (for `trustedTypes.emptyHTML`\nand `trustedTypes.emptyScript`).\n\n### Additional Security Considerations\n\n- All commits are PGP/GPG signed, ensuring the authenticity of the author\n- All releases use [Package Provenance](https://github.blog/2023-04-19-introducing-npm-package-provenance/),\nproving that the generated \u0026 published package was created by a specific (and signed)\ncommit\n\n## Compatibility\n\nThis library relies on the [Sanitizer API proposal](https://github.com/WICG/sanitizer-api)\nand [Constructable Stylesheets](https://web.dev/articles/constructable-stylesheets).\nAt minimum, there **MUST** be a polyfill for [`Element.prototype.setHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/setHTML).\n\n## Performance/Optimization Tips\n\n### HTML Templates / Fragments\nThe `html` function returns a `DocumentFragment` which cannot be directly reused\nin multiple places. Should you wish to reuse the fragment and only generate it once,\nplease use [`cloneNode(true)`](https://developer.mozilla.org/en-US/docs/Web/API/Node/cloneNode):\n\n```js\nimport { html } from '@aegisjsproject/core';\n\nconst tmp = html`\u003c!-- Your HTML here --\u003e`\n\ndocument.querySelector('.my-component').append(tmp.cloneNode(true));\n```\n\n### StyleSheets / CSS\n\nOn the other hand, `css` relies on `adoptedStyleSheets` for `Document`/`ShadowRoot`,\nwhich *does* allow for easy reuse without cloning. You may (and probably should)\nreuse where possible. You may use either `rootOrShadow.adoptedStyleSheets = [sheet]`\nor the provided `addStyles(target, ...sheets)` or `replaceStyles(target, ...sheets)`\nfunctions.\n\n### Use as ES Modules\n\nSince [`import attributes` / `import attributes` / CSS and HTML Modules](https://github.com/tc39/proposal-import-attributes)\nare not yet standardized or implemented anywhere, this library allows for easy\nHTML templates and styles via plain old ES/JS Modules:\n\n```js\nimport { html, css } from '@aegisjsproject/core';\n\nexport const template = html`\u003c!-- Your Markup Here --\u003e`;\n\nexport const sheet = css`/* Your Styles Here */`;\n```\n\n## Path to a Stable Release (v1.0.0)\n\nSince this relies on [`Element.prototype.setHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/setHTML),\nwhich is a developing proposal, Aegis will remain in pre-1.0.0/stable release until\nthat proposal is stable. Until then, you may use [`@shgysk8zer0/polyfills`](https://www.npmjs.com/package/@shgysk8zer0/polyfills) or any compatible polyfill of your choosing.\n\n## Basic Usage Notes\n\nOutside of usage in web components/custom elements, it is important to understand\nhow Constructable Stylesheets and [`adoptedStyleSheets`](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/adoptedStyleSheets)\nwork. When using `css`, stylesheets will be adopted by the `Document` and apply\nthe same as any other stylesheet (not scoped). Should you want to scope your styles\noutside of the context of web components (using `ShadowRoot`), you should create\na unique selector and utilize that when composing your stylesheets:\n\n```js\nimport { css, html, getUniqueSelector, addStyles } from '@aegisjsproject/core';\n\nconst scope = getUniqueSelector();\n\ndocument.body.append(html`\n  \u003cdiv id=\"${scope}\"\u003e\n    \u003cspan class=\"my-class\"\u003eHello, World!\u003c/span\u003e\n  \u003c/div\u003e\n`);\n\naddStyles(document, css`#${scope} .my-class {color: red;}`);\n```\n\n## Basic Web Component Example - `\u003cdad-joke\u003e`\n\n```js\nimport { html, css, registerComponent, registerCallback, attachListeners, EVENTS } from '@aegisjsproject/core';\n\nconst styles = css`:host {\n  display: block;\n}\n\np.joke {\n  font-family: system-ui;\n  padding: 1.3rem;\n  border-radius: 8px;\n  border: 1px solid #cacaca;\n}\n\nbutton {\n  cursor: pointer;\n}`;\n\nconst render = registerCallback('dad-joke:render', event =\u003e event.target.getRootNode().host.render());\n\nconst template = html`\u003cdiv part=\"container\"\u003e\n  \u003cdiv id=\"joke-container\"\u003e\u003c/div\u003e\n  \u003cbutton type=\"button\" class=\"btn btn-primary\" part=\"update-btn\" ${EVENTS.onClick}=\"${render}\"\u003eUpdate\u003c/button\u003e\n\u003c/div\u003e`;\n\nregisterComponent('dad-joke', class HTMLDataJokeElement extends HTMLElement {\n  constructor() {\n    super();\n    this.attachShadow({ mode: 'open' });\n    this.shadowRoot.adoptedStyleSheets = [styles];\n    this.shadowRoot.append(attachListeners(template.cloneNode(true)));\n  }\n\n  connectedCallback() {\n    this.render();\n  }\n\n  async render({ signal } = {}) {\n    this.shadowRoot.getElementById('joke-container').replaceChildren(\n      html`\u003cp class=\"joke\"\u003e${await HTMLDataJokeElement.getJoke({ signal })}\u003c/p\u003e`\n    );\n  }\n\n  static async getJoke({ signal } = {}) {\n    const resp = await fetch('https://icanhazdadjoke.com', {\n      headers: { Accept: 'text/plain' },\n      referrerPolicy: 'no-referrer',\n      signal,\n    });\n\n    return await resp.text();\n  }\n});\n```\n\n## Advanced Usage\n\nThe provided `html` uses the default white-list for elements and attributes,\nwhich does not allow for `\u003csvg\u003e`, `\u003cmath\u003e` (MathML), or custom elements by default.\nShould you have need of such features, you may use `createHTMLParser()` with the\ndesired config/options.\n\n**Note**: Directions and documentation for config options are not provided in these\nearly release, as the Sanitizer API is not stable and is subject to change.\n\nThere is also an additional `createCSSParser({ media, disabled, baseURI })` function\nwhich returns a custom `css` parsing function.\n\n### Advanced Exampled\n\n```js\nimport { createHTMLParser, createCSSParser } from '@aegisjsproject/core';\n\nconst html = createHTMLParser({\n  allowElements: ['h1', 'h2', 'span', 'a', 'img', 'blockquote'],\n  allowAttributes: ['href', 'class', 'id', 'src'],\n});\n\nconst css = createCSSParser({ media: '(prefers-color-scheme: dark)', baseURI: 'https://cdn.example.com' });\n\n// `html` \u0026 `css` then function as the regular / exported function, but with their\ncustom white/black lists / config options.\n```\n\n## Event handlers\n\nAlthough `onclick` and other event attributes are stripped out by the sanitizer,\nyou can still (more securely) add event listeners when authoring HTML.\n\nThis works by registering a callback (in a private `Map` object) which stores the\nname as the key and the registered callback/function as the value. `registerCallback()`\nadds the name and callback to the map and returns the key. `attachListeners()` can\nthen be used to call `addEventListener()` for the given value of the attribute by\nretrieving the function from the map.\n\n**NOTE**: The attribute name is subject to change, so you should only use `EVENTS.onClick`,\netc, instead of setting the attribute manually.\n\n```js\nimport { registerCallback } from '@aegisjsproject/core/callbackRegistry.js';\nimport { EVENTS, attachListeners } from '@aegisjsproject/core/events.js';\n\nconst log = registerCallback('log', console.log);\n\nconst logBtn = attachListeners(html`\u003cbutton ${EVENTS.onClick}=\"${log}\"\u003eClick Me!\u003c/button\u003e`);\nconst backBtn = attachListeners(html`\u003cbutton ${EVENTS.onCLick}=\"${registerCallback('back', () =\u003e history.back())}\"\u003eBack\u003c/button\u003e`\n```\n\n## SVG Generation\n\nThere is a provided `svg` function, but it should be noted that all SVGs **MUST**\ninclude `\u003csvg xmlns=\"http://www.w3.org/2000/svg\"\u003e`. This is due to the requirements\nof `new DOMParser().parseFromString(svgContent, 'image/svg+xml')`. You may also\nwant to set `viewBox` as necessary.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faegisjsproject%2Fcore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faegisjsproject%2Fcore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faegisjsproject%2Fcore/lists"}