{"id":13392,"library":"js-component-framework","title":"JS Component Framework","description":"JS Component Framework is a zero-dependency JavaScript library designed to simplify the configuration and attachment of JavaScript components to DOM elements. It is currently at stable version 3.2.0, with recent updates focusing on bug fixes and enhanced flexibility, such as improved `domContentLoaded` handling and custom root selector support. The framework allows components to be defined as either ES6 classes or functions, using `componentProvider` to automatically initialize them based on a configuration object. A key differentiator is its automatic collection of child nodes based on configuration, minimizing the need for manual DOM queries within components. This approach aims to streamline front-end development by centralizing DOM interaction logic and reducing boilerplate, offering a lightweight alternative to more comprehensive frameworks.","status":"active","version":"3.2.0","language":"javascript","source_language":"en","source_url":"https://github.com/alleyinteractive/js-component-framework","tags":["javascript","es6"],"install":[{"cmd":"npm install js-component-framework","lang":"bash","label":"npm"},{"cmd":"yarn add js-component-framework","lang":"bash","label":"yarn"},{"cmd":"pnpm add js-component-framework","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The `componentProvider` is the central export for configuring and initializing components in v3. `require()` is not supported in modern ESM contexts.","wrong":"const componentProvider = require('js-component-framework');","symbol":"componentProvider","correct":"import { componentProvider } from 'js-component-framework';"},{"note":"For projects migrating from v2 or needing core v2 functionality, the `Component` export is available via the `/v2` subpath. V3 uses `componentProvider` instead.","wrong":"import { Component } from 'js-component-framework';","symbol":"Component (v2 compatibility)","correct":"import { Component } from 'js-component-framework/v2';"},{"note":"`componentLoader` is exported individually for cases where automatic loading by `componentProvider` is not desired. It is a named export.","wrong":"import componentLoader from 'js-component-framework';","symbol":"componentLoader","correct":"import { componentLoader } from 'js-component-framework';"}],"quickstart":{"code":"import { componentProvider } from 'js-component-framework';\n\n// 1. Define your HTML component structure with a data-component attribute\n// <div data-component=\"my-greeting-component\">\n//   <h2 class=\"greeting-title\"></h2>\n//   <button data-action=\"say-hello\">Say Hello</button>\n// </div>\n\n// 2. Create your ES6 class or function component\nclass MyGreetingComponent {\n  constructor({ element, children, options }) {\n    this.element = element; // The root DOM element (e.g., <div data-component=\"my-greeting-component\">)\n    this.title = children.title; // Child element mapped by querySelector\n    this.sayHelloButton = children.sayHelloButton; // Child element mapped by querySelectorAll (or querySelector if unique)\n    this.message = options.message; // Arbitrary options passed in config\n\n    if (this.title) {\n      this.title.textContent = this.message || 'Hello from Component!';\n    }\n\n    if (this.sayHelloButton) {\n      this.sayHelloButton.addEventListener('click', this.handleSayHello.bind(this));\n    }\n  }\n\n  handleSayHello() {\n    alert(`Component says: ${this.message || 'Hello world!'}`);\n  }\n}\n\n// 3. Define the component configuration\nconst myGreetingConfig = {\n  name: 'my-greeting-component',\n  component: MyGreetingComponent,\n  querySelector: {\n    title: '.greeting-title'\n  },\n  querySelectorAll: {\n    sayHelloButton: '[data-action=\"say-hello\"]'\n  },\n  options: {\n    message: 'Welcome to the JS Component Framework!'\n  },\n  load: true // Automatically initialize on DOMContentLoaded\n};\n\n// 4. Initialize the component using componentProvider\ncomponentProvider(myGreetingConfig);\n\n// Example of deferred loading (if config.load was false)\n/*\nconst myDeferredComponentProvider = componentProvider({ ...myGreetingConfig, name: 'my-other-component', load: false });\nwindow.addEventListener('load', () => {\n  myDeferredComponentProvider(); // Manually initialize the component\n});\n*/","lang":"typescript","description":"Demonstrates how to define an ES6 class component, configure its properties including child selectors and options, and initialize it using `componentProvider` for automatic DOM attachment and event handling."},"warnings":[{"fix":"Refer to the official 'Updating to v3' documentation in the GitHub Wiki for a comprehensive upgrade guide. Components must be adapted to either ES6 classes or functions, configured via `componentProvider`.","message":"Version 3.0.0 introduced significant breaking changes, including a reimagined framework core that removes unused features, simplifies component structure, and centers around `componentProvider`. Existing projects on v2.x or earlier will require updates to component definitions and initialization patterns.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Ensure all imports use ES Module `import` syntax (e.g., `import { componentProvider } from 'js-component-framework';`). Update build configurations to handle ES Modules correctly if necessary.","message":"Starting with version 2.1.0, the framework embraced ES Modules. While v2.1.0 allowed both, v3.0.0+ is primarily designed for and expects ES Module imports. Using CommonJS `require()` syntax may lead to errors in modern build environments or direct browser usage.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Upgrade to version 3.2.0 or newer to benefit from the fix that ensures the `domContentLoaded` callback executes only once. Alternatively, implement custom debouncing or flag checks in older versions if `config.load` relies on `DOMContentLoaded`.","message":"In versions prior to 3.2.0, the `domContentLoaded` handler (default for `config.load`) could execute the component initialization callback more than once, leading to unintended side effects or multiple component instances.","severity":"gotcha","affected_versions":"<3.2.0"},{"fix":"For immediate loading in versions prior to 3.2.0, a custom `handler` function wrapping the provider call could be used. For `true` functionality, upgrade to v3.2.0+.","message":"The `config.load` property gained a new `true` option in v3.2.0 to immediately execute the provider function upon script parsing. Previous versions only supported `false` (return provider), an `[HTMLElement, event]` array, or a custom `handler` function.","severity":"gotcha","affected_versions":"<3.2.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Refactor your import statements to use ES Module syntax: `import { componentProvider } from 'js-component-framework';`.","cause":"Attempting to use CommonJS `require()` syntax in a modern JavaScript environment (browser, or Node.js with 'type: module') where `js-component-framework` is imported as an ES Module.","error":"ReferenceError: require is not defined"},{"fix":"Ensure `componentProvider` is imported as a named export: `import { componentProvider } from 'js-component-framework';`.","cause":"Incorrectly importing `componentProvider` as a default import or with a wrong named import when it is exported as a named export. This often happens with bundlers like Webpack.","error":"TypeError: (0, _js_component_framework__WEBPACK_IMPORTED_MODULE_0__.componentProvider) is not a function"},{"fix":"Verify that the `name` property in your component configuration exactly matches the `data-component` attribute value on your HTML element. Alternatively, if using `root`, ensure the CSS selector is correct and targets existing elements.","cause":"The `name` property in the component configuration does not match any `data-component` attribute in the DOM, or the `root` selector is incorrect, preventing the framework from finding the target element(s).","error":"Component 'my-component-name' not found in DOM for initialization."},{"fix":"Ensure your `config.component` property points to an actual ES6 class or a JavaScript function that defines your component's logic. Anonymous functions or arrow functions are valid if assigned correctly.","cause":"The `component` property in the configuration object was not provided as an ES6 class or a function, which are the only supported types for component definitions in v3.","error":"Error: `config.component` must be a function or a class."}],"ecosystem":"npm","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":null,"cli_name":"","cli_version":null}