{"id":14990382,"url":"https://github.com/devpunks/snuggsi","last_synced_at":"2025-05-15T02:08:10.284Z","repository":{"id":862236,"uuid":"598315","full_name":"devpunks/snuggsi","owner":"devpunks","description":"snuggsi ツ - Easy Custom Elements in ~1kB","archived":false,"fork":false,"pushed_at":"2025-04-15T01:11:10.000Z","size":36435,"stargazers_count":397,"open_issues_count":46,"forks_count":17,"subscribers_count":20,"default_branch":"main","last_synced_at":"2025-04-24T02:42:32.908Z","etag":null,"topics":["custom-elements","dom","ecmascript","es6","frontend","html","javascript","template-literals","webcomponents"],"latest_commit_sha":null,"homepage":"https://snuggsi.com","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/devpunks.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"patreon":"devpunks"}},"created_at":"2010-04-07T04:30:03.000Z","updated_at":"2025-04-15T01:11:16.000Z","dependencies_parsed_at":"2023-08-16T19:39:13.419Z","dependency_job_id":"c52fb40b-7714-49bc-908f-983f914e2f97","html_url":"https://github.com/devpunks/snuggsi","commit_stats":{"total_commits":14412,"total_committers":14,"mean_commits":"1029.4285714285713","dds":"0.0047876769358867755","last_synced_commit":"474239bf297618cc36878047f5fc080e4870e121"},"previous_names":["snuggs/snuggsi"],"tags_count":1649,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devpunks%2Fsnuggsi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devpunks%2Fsnuggsi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devpunks%2Fsnuggsi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devpunks%2Fsnuggsi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devpunks","download_url":"https://codeload.github.com/devpunks/snuggsi/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254259384,"owners_count":22040820,"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":["custom-elements","dom","ecmascript","es6","frontend","html","javascript","template-literals","webcomponents"],"created_at":"2024-09-24T14:20:01.013Z","updated_at":"2025-05-15T02:08:10.235Z","avatar_url":"https://github.com/devpunks.png","language":"JavaScript","funding_links":["https://patreon.com/devpunks"],"categories":["Libraries"],"sub_categories":["WebComponents"],"readme":"\u003ch1 align=center\u003esnuggsi ツ - Easy Custom Elements in \u003ca href=https://github.com/devpunks/snuggsi/tree/master/dist#readme\u003e~1kiloByte\u003c/a\u003e \u003c/h1\u003e\n\n\u003cp align=center\u003e\n  \u003ca href=https://www.npmjs.com/package/snuggsi target=external\u003e\n    \u003cimg alt='npm version' src=https://img.shields.io/npm/v/snuggsi.svg\u003e\u003c/a\u003e\n\n  \u003ca href=https://npmjs.org/package/snuggsi target=external\u003e\n    \u003cimg alt='NPM monthly downloads' src=https://img.shields.io/npm/dm/snuggsi.svg?style=flat\u003e\u003c/a\u003e\n\n  \u003ca href=https://github.com/devpunks/snuggsi/tree/master/dist#readme target=external\u003e\n    \u003cimg alt='Brotli size' src=https://img.shields.io/badge/Brotli%20size:-~%201kB-ff69b4.svg\u003e\u003c/a\u003e\n\n  \u003ca href=https://github.com/devpunks/snuggsi/actions/workflows/nightly.yml target=external\u003e\n    \u003cimg alt='Crank Snuggsi' src=https://github.com/devpunks/snuggsi/actions/workflows/nightly.yml/badge.svg\u003e\u003c/a\u003e\n\n  \u003ca href=https://github.com/devpunks/snuggsi/issues target=external\u003e\n    \u003cimg src=https://img.shields.io/badge/PRs-welcome-brightgreen.svg alt='Pull requests welcome!'\u003e\n  \u003c/a\u003e\n\n  \u003ca href=https://github.com/devpunks/snuggsi/blob/master/LICENSE.txt target=external\u003e\n    \u003cimg alt=license src=https://img.shields.io/npm/l/snuggsi.svg\u003e\u003c/a\u003e\n\n\u003c!-- CodeCov\n  \u003ca href='https://codecov.io/github/devpunks/snuggsi?branch=master' target=external\u003e\n    \u003cimg src=https://codecov.io/gh/devpunks/snuggsi/branch/master/graph/badge.svg alt='Coverage via Codecov'\u003e\n  \u003c/a\u003e\n--\u003e\n\n\u003cp align=center\u003e\n  \u003cstrong align=center\u003eAll you need is a browser and basic understanding of \u003ca href=https://developer.mozilla.org/en-US/docs/Web/HTML target=mdn\u003eHTML\u003c/a\u003e, \u003ca href=https://developer.mozilla.org/en-US/docs/Web/CSS target=mdn\u003eCSS\u003c/a\u003e, \u0026amp; \u003ca href=https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes target=mdn\u003eJavaScript Classes\u003c/a\u003e to be productive!\u003c/strong\u003e\n\n\u003cp align=center\u003e\n  \u003cq\u003e\u003cem\u003ePerformance is the art of avoiding work\u003c/em\u003e\u003c/q\u003e - #FreeJewelry 💍 💎\n\u003c/p\u003e\n\n\n# Navigation\n\n - [Why ?](#why-)\n - [Easy Installation](#easy-installation)\n - [Browser Support](#browser-support)\n - [Quick Tour](#quick-tour)\n   - [\u0026lt;`custom-elements`\u0026gt;](#custom-elements)\n     - [`HTML` Declaration](#html-declaration)\n     - [`Element` Definition](#element-definition)\n     - [`class` Description](#class-description)\n   - [`Template`](#template)\n - [Build Process](#build-process)\n - [References](#references)\n - [Contributors](#contributors)\n\n\n# [Why ?](https://github.com/devpunks/snuggsi/wiki/Why%3F)\n\n  1. You prefer to be [D.R.Y.](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) and build reusable web components on a gradual learning curve.\n  2. Because [You _(probably)_ don't need a JavaScript Framework](https://dev.to/steelvoltage/you-probably-don-t-need-a-front-end-framework-26o6).\n  3. You prefer [convention over configuration](https://en.wikipedia.org/wiki/Convention_over_configuration).\n\n  4. [Web Components](https://developer.mozilla.org/en-US/docs/Web/Web_Components)\n     are [ready](https://twitter.com/domenic/status/904114041752358913)\n     for [production](https://twitter.com/WebReflection/status/761316429559922688)\n     \u0026amp; [Custom Elements v1](https://www.w3.org/TR/custom-elements) has\n     [support for every modern 🍃 greenfield browser](#browser-support).\n\n\n# Easy Installation\n\nMade with [💖 Vanilla JS™](http://vanilla-js.com) No need to learn Node.js, React, Webpack, Babel, or Gulp.\n_(You can if ya **want** to use **snuggsiツ**  with those tools. But you don't **need** to!)_\n\n__*#UseThePlatform*__\n\n**snuggsiツ** works in a plain 'ol HTML file! Simply place the following **\u0026lt;script\u0026gt;** within your webpage:\n\n```html\n\u003cscript src=https://unpkg.com/snuggsi\u003e\u003c/script\u003e\n```\n\nEt Voila _(that's it!)_ ツ\n\n# Browser Support\n\n_**snuggsiツ** provides a [prolyfill](https://github.com/devpunks/snuggsi/wiki/What-is-a-ProlyFill) for the following native web platform features:_\n\n\n  | Support    | Edge* | Chrome* | Firefox* | Safari 9+ | Android* | iOS Safari* |\n  |:----------:|:-----:|:-------:|:--------:|:---------:|:--------:|:--------------:|\n  | [Templates](#templates) |✅ |✅ |✅ |✅ |✅ |✅ |\n  | [Custom Elements](#custom-elements) |✅ |✅ |✅ |✅ |✅ |✅ |\n  | Slot Replacement |✅ |✅ |✅ |✅ |✅ |✅ |\n\n  _\\*Indicates the current version of the browser_\n\n# Quick Tour\n\n**snuggsiツ** encourages [convention over configuration](https://en.wikipedia.org/wiki/Convention_over_configuration) using familiar techniques that are native to all browsers.\n\nGone are the sleepless nights where your code [suffers from `\u003cdiv\u003e`itus](https://css-tricks.com/css-beginner-mistakes-1/), or need to install packages on a terminal just to write `HTML`. **People who are more comfortable with `HTML` should be able to start marking up their ideas immediately!** You shouldn't have to know CSS or JavaScript! _(But it definitely helps if you need styling and functionality)_.\n\n **snuggsiツ** believes in using [Progressive Enhancement](https://en.wikipedia.org/wiki/Progressive_enhancement). Not just with your code, but also with your Developer eXperience _(DX)_. We will start from the beginning with a simple Custom Element and gradually enhance functionality step-by-step.\n\n\n## [\u0026lt;`custom-elements`\u0026gt;](/element#readme)\n\nWhen picking a name for your custom element [there are a few naming conventions](https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name) you must be aware of. We can simply use `hello-world` for now.\n\n\n### `HTML` Declaration\n\n`HTML` has always been a declarative language. Why not just use it to declare Custom Elements?\nIf you know [how to write `HTML`](https://developer.mozilla.org/en-US/docs/Web/HTML) you can start using **snuggsiツ**. Sometimes you need to sandbox a section of your page for styling. Other times you need a custom container of complex functionality. Either way you usually start with a plain ole' `HTML` element declaration:\n\n\n#### A Brief History Lesson\n\n_Not all HTML tags are created equal!_\n\nA _\"valid `HTML` Element\"_ has always _allowed_ non-standard tag names _(as long as you remember to provide a closing tag)_. In the bad old days of the web, [`HTML5` elements were once _\"non-standard\"_ to `HTML 4.0`](https://johnresig.com/blog/html5-shiv). However, these days we have far more flexibility in our markup:\n\n```html\n\u003ca\u003e…\u003c/a\u003e \u003c!-- valid (hyperlink) --\u003e\n\u003cb\u003e…\u003c/b\u003e \u003c!-- valid (HTML4.01)--\u003e\n\u003cc\u003e…     \u003c!-- invalid (no closing tag) --\u003e\n\u003cc\u003e…\u003c/c\u003e \u003c!-- valid (HTMLUnknownElement) --\u003e\n\u003cp\u003e…\u003c/p\u003e \u003c!-- valid (with closing tag)  --\u003e\n\u003cp\u003e…     \u003c!-- valid (with optional closing tag)  --\u003e\n\u003cimg /\u003e  \u003c!-- valid (x-HTML self closing tag)  --\u003e\n\u003chr\u003e     \u003c!-- valid (no content tag)  --\u003e\n```\n👍 Rule of thumb: _Close all **non-standard** `HTML` Element tags!_\n\n\u003chr\u003e\n\nAs you learned earlier there are a few conventions to adhere to be considered a _\"valid **Custom** Element\"_ you will need an alpha-numeric character followed by a hyphen in the tag name _(at minimum)_:\n\n```html\n\u003cfoo\u003e\u003c/foo\u003e \u003c!-- invalid (CUSTOM element but valid HTML element) --\u003e\n\u003cfoo-bar\u003e   \u003c!-- invalid (no closing tag) --\u003e\n\u003ca-\u003e\u003c/a-\u003e   \u003c!-- valid (you only need a character and a hyphen) --\u003e\n\u003cfoo-bar\u003e\u003c/foo-bar\u003e \u003c!-- valid --\u003e\n```\n\n👍 Rule of thumb: _Use [kebab case (with hyphens)](https://en.wiktionary.org/wiki/kebab_case) for tag names._\n\n\u003chr\u003e\n\nWe now know enough to be dangerous and make your own Custom Element tag:\n\n```html\n\u003chello-world\u003e\u003c/hello-world\u003e\n```\n\nEt Voila ツ _(No really … That's it!)_\n\n\u003chr\u003e\n\nAt this point your **custom** element can be styled using CSS just like any other element.\n\n```html\n\u003cstyle\u003e\nhello-world {\n  background: #bada55\n}\n\u003c/style\u003e\n\n\u003chello-world\u003e\n  Hello\n\u003c/hello-world\u003e\n```\nSee [A JavaScript-free custom element implementation](https://www.stefanjudis.com/notes/a-javascript-free-custom-element-implementation/)\nAnd [Building a `\u003ctool-tip\u003e` component](https://web.dev/building-a-tooltip-component/) for more _(sans JavaScript)_ custom elements CSS fun!\n\n\u003chr\u003e\n\n\n#### Live `{token}` Declarations\n\n\nThe `{token}` is simply a [well named dynamic variable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Variables) you will **Describe** later. `{token}`s are placeholders which watch for changes to your custom element's `class` property of the same name. Since they are _\"placeholders\"_ and not live code, Front-end designers are no longer blocked by needing to install a JavaScript framework just to write `CSS`!\n\n```html\n\u003cfoo-bar\u003e This is a token 👉 {baz} and {bat} is another! \u003c/foo-bar\u003e\n```\n👍 Rule of thumb: _If the `{token}` name is [not in a thesaurus](https://en.wikipedia.org/wiki/Metasyntactic_variable) then I probably shouldn't use it._\n\n\u003chr\u003e\n\nA _\"live token\"_ is a declarative way to bind data values to your Custom Element. A nice convention to a real historical P.I.T.A. of keeping values updated. Live `{token}`s are also _\"✨ automagically\"_ updated each time the element re-renders.\n\nLet's add a `{token}` to `\u003chello-world\u003e`:\n\n```html\n\u003chello-world\u003e\n\n  Hello {planet}\n\n\u003c/hello-world\u003e\n```\n👍 Rule of thumb: _A `{token}` is not _\"live\"_ until there is a `class` description for its functionality._\n\n\u003chr\u003e\n\nLastly, we can visually enhance your `\u003chello-world\u003e` Custom Element by making it [_\"block level\"_](https://developer.mozilla.org/en-US/docs/Web/HTML/Block-level_elements) with CSS `display: block`. This way your element plays nicely in your layout:\n\n```html\n\u003chello-world\u003e\n\n  Hello {planet}\n\n  \u003cstyle\u003e\n    hello-world { display: block }\n  \u003c/style\u003e\n\n\u003c/hello-world\u003e\n```\n\nWe have finished your Custom Element **Declaration** using `HTML`, \u0026 `CSS`!🌟  Now on to your **Definition**.\n\n\n\u003chr\u003e\n\n\n### `Element` Definition\n\nEvery Custom `Element` **MUST** be [_Defined_ within the `CustomElementsRegistry`](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry). This is simple with **snuggsiツ**\n\nLet's `define` your element using the `Element` interface:\n\n```javascript\n// \u003chello-world\u003e … \u003c/hello-world\u003e\n\nElement `hello-world`\n```\n👍 Rule of thumb: _Use backticks around tag names (``)._\n\nThis syntax is not JSX. It's actually called [tagged template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates) and is native to the platform.\nCustom elements use the native `Element` interface definition strategy for two reasons:\n\n  1. To prevent you from worrying about browser inconsistencies as the technology matures.\n  2. Prevent global namespace pollution. _([`Element` has been native to the web platform for decades!](https://developer.mozilla.org/en-US/docs/Web/API/Element))_\n\nClassic JavaScript syntax may also be used. However [this should be the job of a transpiler not the developer](https://en.wikipedia.org/wiki/Source-to-source_compiler).\nTranspilers take care of [normalizing Modern JavaScript to a specific retrograde](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript).\n\n```javascript\nElement ('hello-world') // classic javascript definition\n```\n\n\u003chr\u003e\n\n\n### `class` Description\n\nGreat so far!🎉  Although your Element behaves like any other `HTMLElement`, we should add some functionality custom to your needs.\n\nNext, we need to pass a `class` description to the function returned by your `Element` definition.\n\n```javascript\n// \u003chello-world\u003e … \u003c/hello-world\u003e\n\nElement `hello-world`\n\n( class HelloWorld extends HTMLElement { … } )\n```\n\n👍 Rule of thumb: _**MUST** define [a `class` which `extends HTMLElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement)_\n\nLet's shorten your description up a bit by using an [anonymous class expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/class) to describe the `class`. This convention is preferred as using an [explicit `class` declaration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class) name can potentially pollute the global namespace:\n\n```javascript\n// \u003chello-world\u003e … \u003c/hello-world\u003e\n\nElement `hello-world`\n\n( class extends HTMLElement { … } )\n```\n\n👍 Rule of thumb: _Use enclosing parenthesis around `(class …)` definitions._\n\n\n\u003chr\u003e\n\n\n#### Live `{token}` Definitions\n\nSince we [previously declared a `{planet}` token](#live-tokens) within your `\u003chello-world\u003e` element we need to also define a `class property` **of the same name** to replace the `{planet}` token with a value.\n\nClass properties may look like typical JavaScript Functions. However, they are treated as properties. _(called without parenthesis)_. `class` properties are described by using the [`get`ter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) and [`set`ter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) annotations before the name.\n\nLet's add a property to your `class` definition and give `{planet}` some life:\n\n```javascript\n// \u003chello-world\u003e … {planet} … \u003c/hello-world\u003e\n\nElement `hello-world`\n\n(class extends HTMLElement {\n\n  get planet () // used for {planet} token\n    // \"✨ automagic\" token binding\n    { return 'world 🌎' }\n})\n```\n\n👍 Rule of thumb: _`class` properties are functions begining with the keywords `get` \u0026amp; `set`._\n\n👍 Rule of thumb: _`{tokens}` will use the `class` property value of the same name by default._\n\n⚠️ The Live `{token}` value is updated after each re-render but it beyond the scope of this simple example.\n\nSince your `hello-world` Custom Element is an `HTMLElement` at its core, we can access your property directly from the DOM!\n\n```javascript\n// \u003chello-world\u003e … \u003c/hello-world\u003e\n\ndocument.querySelector\n  ('hello-world').planet // world 🌎\n```\n👍 Rule of thumb: _Do not use parenthesis `()` when calling `get`ters \u0026amp; `set`ters._\n\n\u003chr\u003e\n\n\n#### Global `event` Listeners\n\n`event` handlers can be any method function which can be placed on any child elements and also onto the custom element itself _(i.e.`onclick=eatBacon`)_. However, you will not have to explicitly set the handler in HTML when you follow native naming conventions.  This is the magic behind **snuggsiツ** Global `event` Listeners. They register themselves onto the custom element and _\"listen\"_ for you! As a convenience, your new custom element uses [Event Delegation](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_delegation) to capture all its children's [event bubbles of the same name](https://javascript.info/bubbling-and-capturing).\n\n```javascript\n// \u003chello-world\u003e\n//   `onclick` is \"automagically\" attached\n//\n//   \u003ca onclick=onsneeze\u003e ACHOO! \u003c/a\u003e\n// \u003c/hello-world\u003e\n\nElement `hello-world`\n\n(class extends HTMLElement {\n\n  // native event handler names\n  // are \"✨automagically\" attached to `hello-world`\n  onclick (event) {\n\n    // prevent event from bubbling\n    // Custom Element will re-render\n    // after event unless prevented\n    event.preventDefault ()\n\n    event.target // element which triggered event\n\n    this // is ALWAYS bound to the Custom Element container 🎉\n  }\n\n  onsneeze (event) {\n    /* must be declared in HTML\n      \u003cbutton onclick=onsneeze\u003e\n    */\n  }\n})\n```\n\n👍 Rule of thumb: _Use native `GlobalEventHandlers`_ names if you don't want to explicitly set listeners in HTML.\n\n\n_See full list of [Global Event Handlers on MDN](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers)_\n\nLastly, all `event` handlers _(and global `event` listeners)_ are passed a native [`event` object](https://developer.mozilla.org/en-US/docs/Web/API/Event).\n\n_P.S._ **YES** the event handler will _auto`bind`_ `this` to the **current** custom element instance! :tada:\n\n\u003chr\u003e\n\n\n### Hello World! _(simple)_\n\n[Play `\u003chello-world\u003e` Demo](http://jsfiddle.net/vw4u6ycx)\n\n_…or just copy \u0026 🍝pasta  into a new HTML file and have at it!_\n\n```html\n\n\u003c!-- 👇 Declaration ---------------------------\u003e\n\n\u003chello-world\u003e\n\n  Hello {planet}\n\n  \u003cbutton onclick=speak\u003eGreet\u003c/button\u003e\n\u003c/hello-world\u003e\n\n\n\u003cscript src=//unpkg.com/snuggsi\u003e\u003c/script\u003e\n\u003cscript\u003e\n\n// 👇 Definition -------------------------------\n\nElement `hello-world`\n\n// 👇 Description ------------------------------\n\n(class extends HTMLElement {\n\n  get planet () // property token\n    // \"✨ automagic\" token binding\n    { return 'world 🌎' }\n\n  onclick (e) { // event handler\n    // \"✨ automagic\" event registration\n    alert(`You clicked on ${e.target.tagName}`)\n  }\n  \n  speak(e) { // bound event handler\n    e.preventDefault()\n    alert('One small step...')\n  }\n})\n\n\u003c/script\u003e\n\n```\n\n\u003chr\u003e\n\n\n### Hello Kitty! _(advanced)_\n\n[Play `\u003chello-kitty\u003e` Demo](https://jsfiddle.net/yLdatmvz)\n\n_…or just copy \u0026 🍝pasta  into a new HTML file and have at it!_\n\n```html\n\n\u003chello-kitty icon=😻 \u003e\n\n  \u003cheader\u003e{greeting}\u003c/header\u003e\n\n  \u003cfigure\u003e\n    \u003cfigcaption\u003e\n      \u003cbutton onclick=meow\u003eHello new kitty!\u003c/button\u003e\n    \u003c/figcaption\u003e\n\n    \u003cimg alt='Random kitty cat' src={url} onclick=pet \u003e\n  \u003c/figure\u003e\n\n  \u003cstyle\u003e\n    hello-kitty *\n      { margin: 1em; text-align: center }\n  \u003c/style\u003e\n\n\u003c/hello-kitty\u003e\n\n\u003cscript src=//unpkg.com/snuggsi\u003e\u003c/script\u003e\n\u003cscript\u003e\n\nElement `hello-kitty`\n\n(class extends HTMLElement {\n\n// CONSTRUCTOR ---------------------------------------\n\n  initialize ()\n    // see `meow` event handler\n    { this.url = 'https://placekitten.com/400/400?image=' }\n\n\n// PROPERTIES ----------------------------------------\n\n  set icon // on element\n    // default to html attribute\n    ( value = this.getAttribute `icon` )\n      // set html attribute to new value\n      { this.setAttribute (`icon`, value) }\n\n  get icon () // from element\n    { return this.getAttribute `icon` }\n\n  get greeting () // \"✨ automagic\" token binding\n    { return `\u003chello-kitty\u003e Carousel ${ this.icon }` }\n\n\n// METHODS -------------------------------------------\n\n  random () {\n    return Math.round\n      ( Math.random `` * 16 )\n  }\n\n\n// EVENT HANDLERS ------------------------------------\n\n  onclick (e) {\n    // \"✨ automagic\" global event handler registration\n    alert (`You clicked on ${e.target.tagName} ${ this.icon }`)\n  }\n\n  pet ()\n    { alert `Puuuuuurrrrrrrrrrrr!!!` }\n\n  meow (e) { // custom handler\n    e.preventDefault ``\n\n    this.querySelector `img`\n      .setAttribute (`src`, this.url + this.random () )\n\n    // element will \"✨ automagically\" re-render !!!\n  }\n})\n\n\u003c/script\u003e\n\n```\n\n## [`Template`](/html-template-element#readme)\n\nThe `\u003ctemplate\u003e` is used to define custom element content for use within multiple elements.\n\nUseful when we need to:\n\n1. Separate a custom element definition into a [Web Component](https://developer.mozilla.org/en-US/docs/Web/Web_Components)\n2. Bind a context to the template using An `Array` or POJO _(Plain Ol' JavaScript `Object`)_\n3. Append rendered template to the document:\n    - If `context` is an object `bind` a single `\u003ctemplate\u003e`\n    - If `context` is a collection _(i.e. an `Array`)_ `bind` a sequential  `\u003ctemplate\u003e` [`DocumentFragment`](https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment) per item\n\n\n### `\u003ctemplate\u003e` With `Object` Context\n\n```html\n\u003ctemplate name=developer\u003e\n  \u003c!-- `{nickname}` will bind to `context` property `nickname` --\u003e\n  \u003ch1\u003e{nickname}\u003c/h1\u003e\n\u003c/template\u003e\n\n\u003cscript src=//unpkg.com/snuggsi\u003e\u003c/script\u003e\n\u003cscript\u003e\n\nconst\n  template = Template `developer`\n, context  = { nickname: 'That Beast' }\n\ntemplate.bind (context)\n\n\u003c/script\u003e\n```\n\n### Rendered Result\n```html\n\u003ctemplate name=\"developer\"\u003e\n\u003c!-- invisible\n  \u003ch1\u003e{name}\u003c/h1\u003e\n --\u003e\n\u003c/template\u003e\n\n\u003ch1\u003eThat Beast\u003c/h1\u003e\u003c!-- template is used as head for tail insertion --\u003e\n```\n\n\n### `\u003ctemplate\u003e` With `Array` of `Object`s Context\n\n  Each `\u003ctemplate name\u003e` will be mapped over each\n  context item within the array. When the array items\n  are objects each property will map to a respective\n  `{token}` of the same name.\n\n  _**Note:** The `#` symbol is used to retrieve the collection's current index of iteration._\n\n```html\n\u003cul\u003e\n  \u003ctemplate name=item\u003e\n    \u003cli\u003eHello {name}! Your index # is {#}\n  \u003c/template\u003e\n\u003c/ul\u003e\n\n\u003cscript src=//unpkg.com/snuggsi\u003e\u003c/script\u003e\n\u003cscript\u003e\n\n// when context is a collection\nconst\n  template = Template `item`\n, context  = [ {name: 'DevPunk'}, {name: 'Snuggsi'} ]\n\n// internal template render for each item in context\ntemplate.bind (context)\n\n\u003c/script\u003e\n```\n\n### Rendered Result\n```html\n\u003cul\u003e\n  \u003ctemplate name=\"item\"\u003e\n  \u003c!-- invisible\n    \u003cli\u003eHello {name}! Your index # is {#}\n  --\u003e\n  \u003c/template\u003e\n\n  \u003cli\u003eHello DevPunk! Your number index # is 0\u003c/li\u003e\n  \u003cli\u003eHello Snuggsi! Your number index # is 1\u003c/li\u003e\n\u003c/ul\u003e\n```\n\n\n### `\u003ctemplate\u003e` With Scalar `Array` Context\n\n  Each `\u003ctemplate name\u003e` will be mapped over each\n  context item within the array. When the array items\n  are scalar _(i.e. strings, numbers, booleans)_\n  each item will map to a `{self}` helper token.\n\n  _**Note:** The `#` symbol is used to retrieve the collection's current index of iteration._\n\n```html\n\u003cdl\u003e\n  \u003ctemplate name=recipe\u003e\n    \u003cdt\u003e Step {#}.\n    \u003cdd\u003e {self}.\n\n  \u003c/template\u003e\n\u003c/dl\u003e\n\n\u003cscript src=//unpkg.com/snuggsi\u003e\u003c/script\u003e\n\u003cscript\u003e\n\n// when context is a collection of scalar variables (i.e. Strings)\nconst\n  template = Template `recipe`\n, context  = [\n    \"Preheat oven\"\n  , \"Place pre-made cake in oven\"\n  , \"Don't burn the cake\"\n  , \"Nom Nom\"\n  ]\n\n// internal template render for each item in context\ntemplate.bind (context)\n\n\u003c/script\u003e\n```\n\n\n### Rendered Result\n```html\n\u003cdl\u003e\n  \u003ctemplate name=\"recipe\"\u003e … \u003c/template\u003e\n\n  \u003cdt\u003e Step 1.\u003c/dt\u003e\n  \u003cdd\u003e Preheat oven.\u003c/dd\u003e\n\n  \u003cdt\u003e Step 2.\u003c/dt\u003e\n  \u003cdd\u003e Place pre-made cake in oven.\u003c/dd\u003e\n\n  \u003cdt\u003e Step 3.\u003c/dt\u003e\n  \u003cdd\u003e Don't burn the cake!\u003c/dd\u003e\n\n  \u003cdt\u003e Step 4.\u003c/dt\u003e\n  \u003cdd\u003e Nom Nom!\u003c/dd\u003e\n\n\u003c/dl\u003e\n```\n\n\n## [Build Process](./dist#build-process)\n\n**snuggsiツ** is able to use modern compression algorithms to create\nbundles as small as *~1500 OCTETS* _(or one 1500byte Ethernet packet frame)_\n\n[Read More](./dist#readme)\n\n\n### [CalVer _(Calendar Versioning)_](./bin/README.md#version)\n\nA chronological [CalVer](https://calver.org) strategy is used instead of [SemVer](https://semver.org).\n[Read More](bin#version)\n\n\n## References\n\n  - [WebComponents Will outlive Your JavaScript Framework](https://youtube.com/watch?v=1vF6puwX3bE)\n\n\n## Contributors\n\nPlease read [CONTRIBUTING.md](/CONTRIBUTING.md) before contributing.\n\nContributing while using [Visual Studio Code](https://code.visualstudio.com/) is simple!  _[Read More](./.vscode#readme)_\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevpunks%2Fsnuggsi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevpunks%2Fsnuggsi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevpunks%2Fsnuggsi/lists"}