{"id":15069945,"url":"https://github.com/dumijay/caldom","last_synced_at":"2025-04-13T00:11:41.986Z","repository":{"id":49977324,"uuid":"266712684","full_name":"dumijay/CalDOM","owner":"dumijay","description":"An agnostic, reactive \u0026 minimalist (3kb) JavaScript UI library with direct access to native DOM.","archived":false,"fork":false,"pushed_at":"2021-07-27T16:55:39.000Z","size":407,"stargazers_count":187,"open_issues_count":0,"forks_count":4,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-24T06:53:13.092Z","etag":null,"topics":["alternative","browser","components","custom-elements","dom","javascript","jquery","library","lightweight","minamalist","react","reactive","simple","small","tiny","ui","virtual-dom","vue","web-components"],"latest_commit_sha":null,"homepage":"https://caldom.org","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/dumijay.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":null,"patreon":"dumijay","open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2020-05-25T07:27:35.000Z","updated_at":"2025-03-03T20:09:17.000Z","dependencies_parsed_at":"2022-09-17T06:20:24.762Z","dependency_job_id":null,"html_url":"https://github.com/dumijay/CalDOM","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dumijay%2FCalDOM","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dumijay%2FCalDOM/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dumijay%2FCalDOM/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dumijay%2FCalDOM/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dumijay","download_url":"https://codeload.github.com/dumijay/CalDOM/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248647285,"owners_count":21139086,"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":["alternative","browser","components","custom-elements","dom","javascript","jquery","library","lightweight","minamalist","react","reactive","simple","small","tiny","ui","virtual-dom","vue","web-components"],"created_at":"2024-09-25T01:45:48.445Z","updated_at":"2025-04-13T00:11:41.955Z","avatar_url":"https://github.com/dumijay.png","language":"JavaScript","funding_links":["https://patreon.com/dumijay"],"categories":[],"sub_categories":[],"readme":"![CalDOM JS Logo](https://www.caldom.org/images/caldom_logo.png)\n\nAn agnostic, reactive \u0026 minimalist (3kb) JavaScript UI library with direct access to native DOM.\n\nInstead of pulling you into a library-specific magical world, CalDOM let you **fully access the DOM** directly while keeping the **reactivity** 💥.\nSo you could take full advantage of native APIs \u0026 mix it with other libraries to gain superior performance \u0026 flexibility in the development process.\n\nA 2-in-1 virtual-DOM \u0026 no-virtual-DOM approach if you will.\n\n0️⃣ Zero tooling,  0️⃣ zero dependencies,  0️⃣ zero new syntax, just pure JS.\n\nIn essence, CalDOM is just a wrapper around the native Node/Element. The overall performance drop is about 0.04x compared to vanilla/pure JavaScript. This is based on averaged unit level benchmarks in handling single \u0026 multiple-element instances: [View Benchmark Results](https://caldom.org/benchmark/) against Vanilla JS, jQuery, React JS, Vue \u0026amp; more.\n\nOfficial site: [caldom.org](https://www.caldom.org)\n\nDocumentation: [caldom.org/docs/](https://caldom.org/docs/)\n\n## Hello World!\nUse it as a chainable DOM traverser and a manipulator, a lightweight jQuery alternative.\n\n```js\n_(\"#output-1\")\n    .append(\n        _(\"+h1\").text(\"Hello World!\")\n    );\n\n//Short append\n_( \"#output-1\", _(\"+p\", \"This is CalDOM.\") );\n```\n\n## Hello World - Reactive\nBuild reactive components. Use it as a lightweight React JS/Vue JS alternative.\nNot using classes, similar to React Hooks, but simpler.\n\n```js\nlet app = _().react(\n    {},\n    {\n        render: state =\u003e\n            _( \"+h1\", `Hello ${state.name}` ) //This is XSS safe by design\n    }\n)\n\n_(\"#output-2\", app );\n\n//Edit below line to update state\napp.state.name = \"World Reactively 💥\";\n```\n\n## Hello World - Reactive (ES6)\nAlso works as an extended ES6 class.\n\n```js\nclass HelloWorld extends _.Component{\n \n    constructor(state){\n        super();\n   \n        this.react(state);\n    }\n \n    render(state){\n        return _(\"+div\", [ //Can pass children as an array too\n            _( \"+h1\", \"Hello \" + state.name ),\n            \n            _( \"+p\", [\"The time is: \", state.time] )\n        ]);\n    }\n\n    tick(){\n        this.state.time = new Date().toTimeString().substr(0, 8);\n    }\n\n    didMount(){\n        setInterval( () =\u003e this.tick(), 1000);\n    }\n \n}\n\nlet app = new HelloWorld( { name: \"World!\", time: \"\" } );\n\n_(\"#output-3\", app);\n```\n\n## Reactive Native DOM Elements\nNative DOM Node is a first-class citizen. Also, a CalDOM instance is just a wrapper around them.\nThis agnostic interoperability allows for an infinite amount of powerful integrations.\n\n```js\nlet app = _().react(\n    {},\n    {\n        render: state =\u003e{\n            let div = document.createElement(\"div\");\n\n            let heading = document.createElement(\"h1\");\n            heading.textContent = `I'm a reactive ${state.name}`;\n\n            div.appendChild(heading);\n\n            //.elem gives you the direct Element\n            div.appendChild( _(\"+h2\", \"💥💥💥\").elem ) \n\n            return div;\n        }\n    }\n)\n\n_(\"#output-3-1\", app );\n\napp.state.name = \"native DOM Element. 🙀\";\n```\n\n## Make existing HTML reactive\nNot a fan of rendering \u0026 virtual-DOM thingies? Use CalDOM to update() pre-defined HTML content reactively.\nCalDOM's API is inspired by jQuery.\n\n```js\nlet person_one = _(\"#person-1\").react(\n    {},\n\n    {\n        update: function(state, person){\n            person.find(\".name\").text( state.name );\n            person.find(\".age\").text( state.age );\n        }\n    }\n)\n\n//CalDOM batches these 2 state updates to only render once.\nperson_one.state.name = \"Jane Doe\";\nperson_one.state.age = 22;                 \n```\n\n## Summon the power of both worlds!\nEfficiently update() the DOM directly and/or proceed to virtual-DOM render if it's more suitable.\nUse this.$ to hold direct DOM Node references. CalDOM keeps them in sync even when render() drastically alter the DOM structure.\n\n```js\nclass Person extends _.Component{\n    constructor(){\n        super();\n\n        this.react({ name: \"John\", likes: [\"SpongeBob\"] });\n    }\n\n    render(state){\n        return _(\"+div\", [\n            //Saving a reference to the direct DOM Element\n            this.$.title = _( \"+h1\", `I'm ${state.name}` ).elem,\n            \n            _( \"+p\", \"I like \" + state.likes.join(\" \u0026 \") )       \n        ]);\n    }\n\n    update(state, person, changed_keys, changes_count){\n        \n        if( changes_count != 1 || !(\"name\" in changed_keys) )\n            // Too complex to update, proceed to render.\n            return true;\n            \n        else //Update name directly using the DOM reference\n            this.$.title\n                .textContent = `I'm ${state.name} Directly. 🦄`;\n    }\n}\n\nlet user = new Person();\n_(\"#output-4\", user );\n\nuser.state.likes.push( \"Hulk\" ); //This is handled by render()\n\nsetTimeout( () =\u003e \n    user.state.name = \"Jane\" //This is handled by update()\n, 1000);\n```\n\n## Supercharge Native Web Components\nCalDOM integrates seamlessly with [Web Components](https://developer.mozilla.org/en-US/docs/Web/Web_Components).\nUse CalDOM to create stateful \u0026 reactive Web Components. It also accepts web components as inputs.\n\n```js\nclass CustomElement extends HTMLElement{\n    connectedCallback(){\n        \n        let title = _().react(\n            { msg: \"Hello World!\" },\n            {\n                render: state =\u003e \n                    _( \"+h2\", state.msg )\n            }\n        );\n\n        // Appending H2 as a child, keeping root intact\n        // this = \u003ccustom-element\u003e\n        _( this, title );\n\n        //Just a shortcut to access state easily\n        this.state = title.state;\n    }\n    \n    doSomething(){\n        alert(\"Cool Eh!\");\n    }\n}\n\n//Registering custom element.\ncustomElements.define(\"custom-element\", CustomElement);\n\nlet hello = document.createElement(\"custom-element\");\ndocument.getElementById(\"output-5-1\").appendChild( hello );\n\nhello.state.msg = \"I'm a Reactive, Stateful \u0026 Native Web Component. 🔥\";\n\n//Creating a new web component using CalDOM\n_(\"#output-5-1\").prepend( _(\"+custom-element\") )\n```\n\nYou can use these custom elements in HTML code natively as usual.\nNote that browser support for [Web Components](https://caniuse.com/custom-elementsv1) is relatively new (95%). The future looks bright! 🔮\n\n```html\n\u003ccustom-element onclick=\"doSomething()\"\u003e\n\u003c/custom-element\u003e\n\n\u003ccustom-element onclick=\"state.msg = 'Native Web Components are awesome! ✌️'\"\u003e\n\u003c/custom-element\u003e\n```\n\n## You can even make jQuery reactive\nBasic building box of CalDOM is just native Node/Element. Thus, making it compatible with almost any DOM library on the web.\n\n```js\nclass HelloJquery extends _.Component{\n\n    constructor(){\n        super();\n\n        this.react({ prompt: \"\" });\n    }\n\n    render(state){\n        //Creating element \u0026 attaching click event using jQuery\n        return $(\"\u003ch1\u003e\u003c/h1\u003e\")\n            .text( state.prompt )\n            .click( () =\u003e state.prompt = \"Hello from jQuery!\")[0];\n    }\n}\n\nlet app = new HelloJquery();\n_(\"#output-6\", app);\n\napp.state.prompt = \"Click Me!\" \n```\n\n## CalDOM also runs on Node JS\nYou can use a library like [JS-DOM](https://github.com/jsdom/jsdom) to implement a browser context on the server.\n\n```js\nconst { JSDOM } = require(\"jsdom\"); \n\n//Set window in the global scope\nwindow = new JSDOM().window;\n\nconst _ = require(\"caldom\");\n\nclass ServerApp extends _.Component{\n\n    constructor(){\n        super();\n\n        this.react( { msg: \"\" } );\n    }\n\n    render(state){\n        return _(\"+p\", state.msg)\n            .css(\"color\", \"#199646\")\n    }\n}\n\nlet app = new ServerApp();\n_(\"body\", app);\n\napp.react( { msg: \"Hello from NodeJS \" + process.version  } );\n\n//Saving generated HTML by the component to a file\nrequire(\"fs\").writeFileSync(\n    \"static_content.html\", \n    window.document.body.innerHTML \n);\n```\n\nVisit [caldom.org](https://www.caldom.org) to experiment with many live code examples.\n\n___\n\n# Get Started\n\n## CDN\n\n```html\n\u003cscript src=\"https://unpkg.com/caldom\"\u003e\u003c/script\u003e\n```\nCalDOM is using '_' variable as a global short-hand by default. To use a different alias, set window['_cal_dom_alias'] = 'different_alias' before loading it.\n\n## Download\n\n* Minified versions are at [dist](./dist/)\n* Source code is at [src](./src/)\n\n## Use it as a Module\nCalDOM is not attaching anything to the global environment when used as a module.\n\n```sh\nnpm install caldom\n```\n\n```js\n//CalDOM also runs on Node JS with js-dom\nconst _ = require('caldom');\n```\n\n```js\n//RequireJS\nrequirejs( [\"caldom\"], function(_){} );\n```\n\n```js\n//ES6 Module\nimport _ from \"./dist/caldom.min.mjs.js\";\n```\n\n# Contributing\n\nYour contributions are very welcome and thank you in advance.\nPlease make sure to unit-test after changes.\n\n## Key Principles\n\n* Performance, being agnostic(interoperability with native DOM) \u0026 minimalism is prioritized above all.\n* The richness in short-hand methods and features is secondary.\n* Supporting legacy browsers is not a priority.\n\n## To-Do\n* ~~Implement tests~~\n    * Need to expand the variety of tests to different use cases. (Currently, it's biased towards my personal coding style).\n* A beginner-friendly documentation/guide. Current one is too technical.\n* Implement helpful debug outputs for the development version.\n* Thorough browser version tests.\n* Further optimize virtual DOM diffing algorithm. [See benchmark here](https://caldom.org/benchmark/)\n    * The diffing algorithm is just 140+ lines of code.\n    * I believe there is so much room for improvement if some bright minds look at it from a fresh angle.\n\n* Need to benchmark bigger implementations (Like in a spreadsheet where each cell is a sub-component?)\n\n## Building\nCurrently, the entire source code is in one file. So there isn't a huge build process other than using uglify-js to minify it.\n\nThis simply build the .min.js \u0026 .min.mjs.js \u0026 related .map files in the ./dist/ folder.\n\n```sh\n# Install dev dependencies\nnpm install\n\n# Build\nnpm run build\n```\n\n## Unit Testing \u0026 Benchmarking\nTests and benchmarks sources are at the ./tests_and_benchmarks.\nCalDOM is using a brand new unit-testing \u0026 benchmarking framework called [pFreak](https://github.com/dumijay/pfreak). Which was created as a side project of CalDOM.\n\nUnit test results for the latest build is available at [caldom.org/tests/](https://caldom.org/tests/)\n\nInitiate pFreak after installation to set sym links properly\n```shell\npfreak init ./tests_and_benchmarks/internal/\npfreak init ./tests_and_benchmarks/external/\n```\n\nUnit Tests\n```shell\nnpm test\n```\n\nor \n\n```shell\npfreak test ./tests_and_benchmarks/internal/\n```\n\nRun benchmarks against other libraries (This takes a lot of time, you can run tasks selectively using flags.)\n\n```shell\ncd ./tests_and_benchmarks/external/\npfreak benchmark\n```\n\nrefer pFreak's help for details\n```shell\npfreak --help\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdumijay%2Fcaldom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdumijay%2Fcaldom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdumijay%2Fcaldom/lists"}