{"id":15388865,"url":"https://github.com/isabo/hyperapp-custom-element","last_synced_at":"2025-04-15T20:22:02.800Z","repository":{"id":39584633,"uuid":"289684003","full_name":"isabo/hyperapp-custom-element","owner":"isabo","description":"Build WebComponents/CustomElements using Hyperapp","archived":false,"fork":false,"pushed_at":"2022-09-18T06:33:26.000Z","size":92,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-29T01:01:35.299Z","etag":null,"topics":["custom-elements","customelements","hyperapp","web-components","webcomponents"],"latest_commit_sha":null,"homepage":"","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/isabo.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":"2020-08-23T12:43:41.000Z","updated_at":"2022-09-24T18:45:30.000Z","dependencies_parsed_at":"2023-01-17T18:15:25.842Z","dependency_job_id":null,"html_url":"https://github.com/isabo/hyperapp-custom-element","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isabo%2Fhyperapp-custom-element","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isabo%2Fhyperapp-custom-element/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isabo%2Fhyperapp-custom-element/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/isabo%2Fhyperapp-custom-element/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/isabo","download_url":"https://codeload.github.com/isabo/hyperapp-custom-element/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249145961,"owners_count":21220066,"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","customelements","hyperapp","web-components","webcomponents"],"created_at":"2024-10-01T14:58:28.838Z","updated_at":"2025-04-15T20:22:02.761Z","avatar_url":"https://github.com/isabo.png","language":"JavaScript","readme":"# Build CustomElements using Hyperapp\n\nThis library makes it easy to create a\n[WebComponents Custom Elements v1](https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements)-compliant\n[CustomElement](https://developers.google.com/web/fundamentals/web-components/customelements)\nthat uses the [Hyperapp](https://github.com/jorgebucaran/hyperapp)\nmicroframework to define its behaviour. Such components are extremely\nlightweight, even including this dependency -- it's only a 1.2K download.\n\nCustomElements created by this library can be consumed by any HTML/Javascript\nproject or framework -- Hyperapp is not required.\n\n## Hyperapp\n\nCustomElements built with this library are mini Hyperapp apps that compose their\nDOM structures using Hyperapp View functions. Their behaviour is governed by\nHyperapp Action, Effect and Subscription functions.\n\nUnlike regular Hyperapp apps, there are three additional types of external\nevents to which a CustomElement may need to react. An app that consumes a\nCustomElement component may:\n\n1. set HTML attributes in the component's HTML tag;\n2. set values of JavaScript properties that the component exposes;\n3. call JavaScript methods that the component exposes.\n\nIn addition, some or all of the Javascript properties and HTML attributes need\nto be kept in sync with each other.\n\n**This library provides functionality to configure and handle all of these\nbehaviours automatically.**\n\n## Installation\n\nInstall the library into your project:\n\n```\nnpm install hyperapp-custom-element\n```\n\nThen, import it into your app.\n\n```javascript\nimport { generateClass } from 'hyperapp-custom-element';\n```\n\nAlternatively, if you're just hacking around and have not yet configured a build\nstep with a packager, you can import it directly into a web page:\n\n```html\n\u003cscript type=\"module\"\u003e\n  import { generateClass } from 'https://unpkg.com/hyperapp-custom-element';\n\u003c/script\u003e\n```\n\n## How to Create a CustomElement\n\n```javascript\nimport { app, h, text } from 'hyperapp';\nimport { generateClass } from 'hyperapp-custom-element';\n\nconst MyCustomElement = generateClass({\n  // The library uses your imported version of Hyperapp.\n  app: app,\n\n  // The initial state of the component. It can be a state object, or anything\n  // dispatchable by Hyperapp.\n  init: { theThing: 'Nothing' },\n\n  // The Hyperapp View function that builds the component's DOM.\n  view: (state) =\u003e h('p', {}, text(`The thing is: ${state.theThing}`)),\n\n  // A function that returns an array of Hyperapp subscriptions (optional).\n  subscriptions: getSubscriptions,\n\n  // A dispatch initialiser function (optional).\n  // N.B.: This library defines its own dispatch function. If a dispatch\n  // initialiser is supplied here, it will be combined with the library's own\n  // function.\n  dispatch: dispatch,\n\n  // An array of Javascript properties and HTML attributes (they often come in\n  // pairs) that can be used by a consuming app to configure the component.\n  exposedConfig: [\n    {\n      // Name of HTML attribute.\n      // Specify attrName or propName or both.\n      // If both are specified, their values will be synchronised.\n      attrName: 'the-thing',\n\n      // Name of JS property.\n      // Specify attrName or propName or both.\n      // If both are specified, their values will be synchronised.\n      propName: 'theThing',\n\n      // Optional Action function that will incorporate the new property or\n      // attribute value into the component's state. If not specified, the\n      // value will be incorporated into the state thus:\n      // `newState[propName||attrName] = newValue;`\n      setter: SetTheThing,\n\n      // Optional function that receives the state and returns the property\n      // value. If not specified, the value will be obtained thus:\n      // `value = state[propName||attrName]`\n      getter: getTheThing,\n    },\n    {\n      // This is how to define an on\u003cevent\u003e attribute/property. Specify an event\n      // name and do not specify a getter or setter. When one of your effects\n      // dispatches an event with the specified eventType, the corresponding\n      // handler will be invoked.\n      attrName: 'onsomeevent',\n      propName: 'onsomeevent',\n      eventType: 'SomethingHappened',\n    },\n  ],\n\n  // Methods to expose to the consuming app, and the corresponding Actions that\n  // will be invoked when the methods are called. Just as the underlying Action\n  // it dispatches, a method can be called with a single payload argument.\n  exposedMethods: {\n    doIt: DoSomething,\n  },\n\n  // Whether to use Shadow DOM (true) or Light DOM (false).\n  useShadowDOM: true,\n});\n\n// Register the class and its tag name.\ncustomElements.define('my-tag', MyCustomElement);\n```\n\n### Extending Native Elements\n\n```javascript\nimport { app, h, text } from 'hyperapp';\nimport { generateClass } from 'hyperapp-custom-element';\n\nconst MyExtendedElement = generateClass({\n  // The native element class that is being extended.\n  parent: HTMLInputElement,\n\n  app,\n\n  // The initial state of the component.\n  init: { theThing: 'Nothing' },\n\n  // With an extended native element no DOM will be built. However, Hyperapp\n  // needs to have a view function, so provide something minimal. It will not\n  // be added to the DOM, though.\n  view: (state) =\u003e h('span', {}),\n\n  subscriptions: getSubscriptions,\n\n  dispatch: dispatch,\n\n  // When extending a native element, specify here only the properties,\n  // attributes and methods that are being *added* -- not those that the native\n  // element already has.\n  exposedConfig: [],\n\n  exposedMethods: {},\n\n  // When extending a native element, this needs to be false.\n  useShadowDOM: false,\n});\n\n// Register the class, its tag name, and the element that is being extended.\n// Note the additional options object, that tells the browser which tag we are\n// extending. This is necessary because some tags share the same HTMLElement\n// class.\ncustomElements.define('extended-tag', MyExtendedElement, { extends: 'input' });\n```\n\n### Dispatching Events\n\nIf your component has 'on\\\u003cevent\\\u003e' attributes and/or dispatches events, you can\nuse the convenient `dispatchEvent` effect generator function that is exported by\nthe module. This function should receive these two arguments: `eventType` and\n`eventInit`, which correspond to arguments of the [CustomEvent\nconstructor](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent),\n`typeArg` and `customEventInit`.\n\n```javascript\nimport { dispatchEvent } from 'hyperapp-custom-element';\n\nfunction DoSomething(state, props) {\n  const newState = {\n    ...state,\n    ...props,\n  };\n\n  const effect = dispatchEvent('DidSomething', { detail: 3 });\n\n  return [newState, effect];\n}\n```\n\n## Example\n\n- Counter component:\n  - A full example component: [my-counter.js](./examples/counter/my-counter.js)\n  - A web page that consumes and exercises this component:\n    [counter.html](./examples/counter/counter.html)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fisabo%2Fhyperapp-custom-element","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fisabo%2Fhyperapp-custom-element","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fisabo%2Fhyperapp-custom-element/lists"}