{"id":43252087,"url":"https://github.com/thoughtsunificator/userinterface.js","last_synced_at":"2026-02-01T13:12:35.987Z","repository":{"id":46622516,"uuid":"372182048","full_name":"thoughtsunificator/userinterface.js","owner":"thoughtsunificator","description":"Models based front-end library ","archived":false,"fork":false,"pushed_at":"2023-08-16T11:10:17.000Z","size":1623,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-12T19:10:44.110Z","etag":null,"topics":["front-end","library","userinterface-js"],"latest_commit_sha":null,"homepage":"http://userinterface-js.unificator.me","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/thoughtsunificator.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-05-30T10:14:17.000Z","updated_at":"2024-11-28T20:52:03.000Z","dependencies_parsed_at":"2022-07-20T18:49:25.673Z","dependency_job_id":null,"html_url":"https://github.com/thoughtsunificator/userinterface.js","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/thoughtsunificator/userinterface.js","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thoughtsunificator%2Fuserinterface.js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thoughtsunificator%2Fuserinterface.js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thoughtsunificator%2Fuserinterface.js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thoughtsunificator%2Fuserinterface.js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thoughtsunificator","download_url":"https://codeload.github.com/thoughtsunificator/userinterface.js/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thoughtsunificator%2Fuserinterface.js/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28978967,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-01T12:13:08.691Z","status":"ssl_error","status_checked_at":"2026-02-01T12:13:08.356Z","response_time":56,"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":["front-end","library","userinterface-js"],"created_at":"2026-02-01T13:12:35.326Z","updated_at":"2026-02-01T13:12:35.978Z","avatar_url":"https://github.com/thoughtsunificator.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# userinterface.js\n\nuserinterface.js is a front-end library built around the idea that logic relating to how the visual looks and how the visual works should be distinguished.\n\n## Getting started\n\n### Installing\n\n#### Scaffold\n\nSee [https://github.com/thoughtsunificator/userinterface.js-skeleton](https://github.com/thoughtsunificator/userinterface.js-skeleton).\n\n#### Standalone\n\n``git submodule add https://github.com/thoughtsunificator/userinterface.js.git lib/userinterface.js``\n\nAdd userinterface.js to the head section of your web page:\n\n```html\n\u003cscript src=\"./lib/userinterface.js/src/userinterface.js\"\u003e\u003c/script\u003e\n```\n\n### Model\n\nA ```Model``` is an object representation of a [Node](https://developer.mozilla.org/en-US/docs/Web/API/Node).\nIt has three required properties depending on the [method](#methods): ```name```, ```method``` and ```properties``` or ```callback```,\n\nThe ```name``` property will be the identifier of your model it will be used whenever you need to run your model but also to associate a binding to your model.\nThe ```method``` property will describe how your model should be ran.\nThe ```properties``` and ```callback``` properties will contain the properties of your Elements.\n\nA ```Model``` often goes along with a [Binding](#Binding) and an [Object](#Object).\n\n#### Basic model\n\nHere we create a model named ```simple model``` using the [method](#methods) ```appendChild``` it has a one ```LI``` [element](https://developer.mozilla.org/en-US/docs/Web/API/Element) child. `LI` has the className ```simplemodel``` and textContent ```My first simple model```.\nThis model uses the `textContent`, `className` and `tagName` propertie however you might use any Element properties the DOM API offers.\n\n``src/userinterface/simplemodel.js``\n```javascript\nUserInterface.model({\n  name: \"simplemodel\",\n  method: UserInterface.appendChild,\n  properties: {\n    tagName: \"li\", // required\n    className: \"simplemodel\",\n    textContent: \"My first simple model\"\n  }\n});\n```\n\n```javascript\nUserInterface.runModel(\"simplemodel\", { parentNode: document.querySelector(\"ul\") });\n```\nOutput:\n```html\n\u003cul\u003e\n  \u003cli class=\"simplemodel\"\u003eMy first simple model\u003c/li\u003e\n\u003c/ul\u003e\n```\n\n#### Children\n\nIn the previous example we created a simple model, but what if we wanted to do more and add some children to it ?\nThe ```children``` property is here for that, it is an Array where you can specify child elements.\n\n``src/userinterface/children.js``\n```javascript\nUserInterface.model({\n  name: \"children\",\n  method: UserInterface.appendChild,\n  properties: {\n    tagName: \"div\",\n    className: \"model\",\n    children: [\n      {\n        tagName: \"div\",\n        className: \"child\",\n        textContent: \"My first child\"\n        // and so on..\n      }\n    ]\n  }\n});\n```\n\n```javascript\nUserInterface.runModel(\"children\", { parentNode: document.body });\n```\nOutput:\n```html\n\u003cbody\u003e\n  \u003cdiv class=\"model\"\u003e\n    \u003cdiv class=\"child\"\u003eMy first child\u003c/div\u003e\n  \u003c/div\u003e\n\u003c/body\u003e\n```\n#### Callback\n\nModels are required to have either the ```properties``` property or ```callback``` property, but exactly what does the ```callback``` property do ?\nIt is used when you want to echo some data in your model.\n\nFor example here, we have a model called ```echomodel``` that has the ```callback``` property. This property works the same as the ```properties``` property does except that an extra step is added before your model is ran.\nThe ```callback``` will return a ```properties``` object accordingly to the data you passed through ```runModel```.\n\n``src/userinterface/echomodel.js``\n```javascript\nUserInterface.model(\n  name: \"echomodel\",\n  method: UserInterface.appendChild,\n  callback: data =\u003e ({\n    tagName: \"p\",\n    className: \"echomodel\",\n    textContent: \"My \"+data.text+\" model\"\n  })\n);\n```\n\n```javascript\nUserInterface.runModel(\"echomodel\", { parentNode: document.body, data: {\"text\": \"echo\" } });\n```\n\nOutput:\n```html\n\u003cp class=\"echomodel\"\u003eMy echo model\u003c/p\u003e\n```\n\n#### Processed properties\n\n- ``children`` Add children to an element\n\n\n### Binding\n\nA ```Binding``` is a callback function that, when bound to a model, is automatically called whenever the model has ran.\n```Bindings``` will make your models more alive, an example of that would be adding an event listener to your model, that is the place where you will be doing it.\n\nYou can also do much more such as using event listeners to connect all of your models together!\n\nA Binding is way to give life to your models enabling them to do things whenever their respective method is executed.\nThat means if you want to add a listener to an Element that's where you will be doing it.\n\nIn this example we will change the textContent of our model root element.\n\n``src/userinterface/button.js``\n```javascript\nUserInterface.model({\n  name: \"button\",\n  method: UserInterface.appendChild,\n  properties: {\n    tagName: \"button\"\n  }\n});\n\nUserInterface.bind(\"button\", function(element) {\n  element.textContent = \"bound\";\n});\n```\n\n```javascript\nUserInterface.runModel(\"button\", { parentNode: document.body });\n```\n\nOutput:\n```html\n\u003cbutton\u003ebound\u003c/button\u003e\n```\n\n### Methods\n\n- ``appendChild`` Append your model to the target\n\n- ``insertBefore`` Insert your model before the target\n\n- ``removeElement`` Remove the target\n\n- ``replaceElement`` Replace the target with your model\n\n- ``updateElement`` Update the target according to your model\n\n- ``wrapElement`` Wrap the target inside your model\n\n- ``removeListeners`` Remove the listeners of the target\n\n### Objects\n\n```Objects``` are the backbone of your models they will store and manipulate data for your ```Binding```.\nThat's where you want to hide the complicated stuff.\n\n### Listeners\n\nListeners enable intercommunication for your models.\n\n#### Main object\n\nYou usually wants to have a ``main object`` that you will pass to most of your models so that they communicate with each other through a central.\n\nNote that you are not forced to have one and you could have multiple observables and still be able to handle inter-model communication.\n\nMost of the time we call it ``application``.\n\n#### Listening to events\n\nIn this example we are creating and running a model called ```myModel``` that will listen for the event ``greeting`` on through the ``application`` context.\n\nA Context represent a reserved area (a channel) that events will be bound to, they're often represented as an instance of an object but could pretty much be anything.\n\n``src/userinterface/my-model.js``\n```javascript\nUserInterface.model({\n  name: \"myModel\",\n  method: UserInterface.appendChild,\n  properties: {\n    tagName: \"div\"\n  }\n});\nUserInterface.bind(\"myModel\", function(element, application) {\n\n  UserInterface.listen(application, \"greeting\", async (message) =\u003e {\n    console.log(message)\n  })\n\n});\n```\n\n\n```javascript\nconst application = {}\n\nUserInterface.runModel(\"myModel\", { parentNode: document.body, bindingArgs: [application] });\n```\n\nFor the moment we are only listening to the ``greeting`` event, we haven't announced anything to it yet.\n\n#### Announcing events\n\nIn the previous example we setup a ``greeting`` listener on ``application``.\n\nNow, let's try to announce to the event.\n\n``src/userinterface/another-model.js``\n```javascript\nUserInterface.model({\n  name: \"anotherModel\",\n  method: UserInterface.appendChild,\n  properties: {\n    tagName: \"div\"\n  }\n});\nUserInterface.bind(\"anotherModel\", function(element, application) {\n\n  UserInterface.announce(application, \"greeting\", \"Hello!\");\n\n});\n```\n\n```javascript\nconst application = {}\n\nUserInterface.runModel(\"myModel\", { parentNode: document.body, bindingArgs: [application] });\nUserInterface.runModel(\"anotherModel\", { parentNode: document.body, bindingArgs: [application] });\n```\n\nIf everything went well you should be able see a ``Hello!`` log message in the console.\n\n#### Removing event listeners\n\nSometimes you might want your model to be dynamically added and removed, meaning that it will be added upon an action and removed upon another action.\n\nUsually what you want to do is to create ``_listener`` variable and push all the listeners to this array and then remove them as needed using ``forEach`` for example.\n\nIn this example, we create a listener ``message`` and remove it whenever the event ``done`` is emitted.\n\n```javascript\nUserInterface.bind(\"myDynamicModel\", function(element, application) {\n\n  const _listeners = []\n\n  _listeners.push(UserInterface.listen(application, \"message\", async data =\u003e {\n    console.log(data)\n  }))\n\n  _listeners(UserInterface.listen(application, \"done\", async () =\u003e {\n    _listeners.forEach(listener =\u003e UserInterface.removeListener(listener))\n  }))\n\n})\n```\n\n## API\n\nYou can read the API by visiting [http://userinterface-js.unificator.me](http://userinterface-js.unificator.me).\n\n## Common errors\n\n### Cannot set property 'binding' of undefined\n\nUserInterface.js could not find the model specified when calling ``UserInterface.bind``.\n\n### Cannot destructure property 'method' of 'model' as it is undefined.\n\nUserInterface.js could not find the model specified when calling ``UserInterface.runModel``.\n\nFeel free to [open an issue](https://github.com/thoughtsunificator/userinterface.js/issues) if you need assistance.\n\n## Collection\n\nuserinterface.js also provides a collection that contains a few basic models to get you started. See [https://github.com/thoughtsunificator/userinterface.js-collection](https://github.com/thoughtsunificator/userinterface.js-collection).\n\n## Extensions\n\nSee [https://github.com/topics/userinterface-js-extension](https://github.com/topics/userinterface-js-extension).\n\n## Demos\n\nSee [https://github.com/topics/userinterface-js-demo](https://github.com/topics/userinterface-js-demo).\n\n## Testing\n\n- ``npm install``\n- ``npm test``\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthoughtsunificator%2Fuserinterface.js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthoughtsunificator%2Fuserinterface.js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthoughtsunificator%2Fuserinterface.js/lists"}