{"id":13120,"library":"ember-primitives","title":"Ember Primitives","description":"Ember Primitives is a comprehensive collection of unstyled, accessible, and highly composable UI building blocks designed to accelerate the development of Ember.js applications. It provides low-level components and utilities that developers can style to match any design system, focusing on headless functionality for maximum flexibility. The library is actively maintained, with frequent patch and minor releases, as evidenced by version `0.55.2` released in April 2026 and numerous updates in the preceding months. Key differentiators include its deep integration with the Ember ecosystem, full TypeScript support via Glint, and a focus on providing foundational UI elements like switches, drawers, and ratings that are challenging to build from scratch with proper accessibility and behavior. It explicitly aims to work with various CSS frameworks like Open Props, Tailwind, and Bootstrap, and is compatible with modern Ember setups, including Embroider.","status":"active","version":"0.55.2","language":"javascript","source_language":"en","source_url":"https://github.com/universal-ember/ember-primitives","tags":["javascript","ember-addon"],"install":[{"cmd":"npm install ember-primitives","lang":"bash","label":"npm"},{"cmd":"yarn add ember-primitives","lang":"bash","label":"yarn"},{"cmd":"pnpm add ember-primitives","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Provides utilities for testing Ember applications, particularly for interacting with components and rendering.","package":"@ember/test-helpers","optional":false},{"reason":"Manages asynchronous operations during tests to ensure consistent and reliable test execution.","package":"@ember/test-waiters","optional":false},{"reason":"The foundational component model for modern Ember applications, essential for building UI components.","package":"@glimmer/component","optional":false},{"reason":"Provides type definitions and static analysis for Ember templates, enabling TypeScript usage within templates.","package":"@glint/template","optional":false},{"reason":"Enables the creation and usage of element modifiers in Ember templates, often used for DOM interactions or lifecycle hooks.","package":"ember-modifier","optional":false},{"reason":"Offers composable, stateful primitives for managing component lifecycle and reactive data flows in Ember.","package":"ember-resources","optional":false}],"imports":[{"note":"Components are typically named exports and reside in a nested `components` directory. ESM imports are standard for modern Ember apps.","wrong":"import Switch from 'ember-primitives/components/switch';\nconst Switch = require('ember-primitives/components/switch');","symbol":"Switch","correct":"import { Switch } from 'ember-primitives/components/switch';"},{"note":"For tree-shaking and explicit dependency, components should be imported directly from their specific paths.","wrong":"import { Drawer } from 'ember-primitives'; // Incorrect top-level import for components\nimport * as Drawer from 'ember-primitives/components/drawer';","symbol":"Drawer","correct":"import { Drawer } from 'ember-primitives/components/drawer';"},{"note":"Type imports for signatures (e.g., `RatingSignature`) should be used for Glint template type checking, typically following the same path but with `type` prefix.","wrong":"import { Rating } from 'ember-primitives/rating'; // Missing 'components' directory\nimport type { RatingSignature } from 'ember-primitives/components/rating';","symbol":"Rating","correct":"import { Rating } from 'ember-primitives/components/rating';"}],"quickstart":{"code":"import Component from '@glimmer/component';\nimport { tracked } from '@glimmer/tracking';\nimport { action } from '@ember/object';\nimport { Switch } from 'ember-primitives/components/switch';\nimport { Drawer } from 'ember-primitives/components/drawer';\nimport { Separator } from 'ember-primitives/components/separator';\nimport { Rating } from 'ember-primitives/components/rating';\n\ninterface MyDemoArgs {}\n\nexport default class MyDemo extends Component<MyDemoArgs> {\n  @tracked isDrawerOpen = false;\n  @tracked isSwitchOn = false;\n  @tracked currentRating = 3;\n\n  @action\n  toggleDrawer() {\n    this.isDrawerOpen = !this.isDrawerOpen;\n  }\n\n  @action\n  handleSwitchChange(checked: boolean, event: Event) {\n    this.isSwitchOn = checked;\n    console.log('Switch is now:', checked, 'Event:', event.type);\n  }\n\n  @action\n  handleRatingChange(rating: number) {\n    this.currentRating = rating;\n    console.log('New rating:', rating);\n  }\n}\n\n/*\n<template>\n  <h2 class=\"text-2xl font-bold mb-4\">Ember Primitives Demo</h2>\n\n  <div class=\"p-4 border rounded-md mb-4\">\n    <button type=\"button\" {{on \"click\" this.toggleDrawer}} class=\"bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded\">\n      Toggle Drawer\n    </button>\n\n    <Drawer @isOpen={{this.isDrawerOpen}} @onClose={{this.toggleDrawer}} class=\"bg-white dark:bg-gray-800 shadow-lg p-6\">\n      <div class=\"p-4\">\n        <h3 class=\"text-xl font-semibold mb-2\">Drawer Content</h3>\n        <p class=\"text-gray-700 dark:text-gray-300\">This is some content inside the drawer. It's fully customizable!</p>\n        <button type=\"button\" {{on \"click\" this.toggleDrawer}} class=\"mt-4 bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded\">\n          Close Drawer\n        </button>\n      </div>\n    </Drawer>\n  </div>\n\n  <div class=\"flex items-center space-x-2 my-4 p-4 border rounded-md\">\n    <Switch\n      @checked={{this.isSwitchOn}}\n      @onChange={{this.handleSwitchChange}}\n      id=\"my-switch\"\n      class=\"w-10 h-6 bg-gray-200 rounded-full peer dark:bg-gray-700 peer-checked:bg-blue-600 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all\"\n    />\n    <label for=\"my-switch\" class=\"text-gray-700 dark:text-gray-300\">Enable Feature ({{if this.isSwitchOn \"On\" \"Off\"}})</label>\n  </div>\n\n  <Separator class=\"my-6 border-t border-gray-300 dark:border-gray-600\" />\n\n  <div class=\"my-4 p-4 border rounded-md\">\n    <h3 class=\"text-xl font-semibold mb-2\">Rate this Component:</h3>\n    <Rating\n      @value={{this.currentRating}}\n      @max={{5}}\n      @onChange={{this.handleRatingChange}}\n      @item={{fn (mut (hash class=\"text-yellow-400 text-3xl cursor-pointer\"))}}\n    />\n    <p class=\"mt-2 text-gray-700 dark:text-gray-300\">Current rating: {{this.currentRating}} stars</p>\n  </div>\n</template>\n*/","lang":"typescript","description":"This quickstart demonstrates the usage of `Switch`, `Drawer`, `Separator`, and `Rating` components within an Ember Glimmer component, showcasing basic state management and event handling with TypeScript."},"warnings":[{"fix":"Update your `@onChange` handlers for `Switch` components to expect `(checked: boolean, event: Event)` as the argument order. Example: `@onChange={{this.handleSwitchChange}}` where `handleSwitchChange(checked: boolean, event: Event) { /* ... */ }`","message":"The argument order for the `@onChange` action on the `Switch` component was inverted in `v0.53.1`. It changed from `(event: Event, checked: boolean)` to `(checked: boolean, event: Event)`.","severity":"breaking","affected_versions":">=0.53.1"},{"fix":"Run `npm install` or `pnpm install` in your project to ensure all peer dependencies are resolved. Pay close attention to any warnings during installation regarding unmet peer dependency ranges.","message":"Ensure all peer dependencies are correctly installed and meet the specified version ranges. `ember-primitives` has several peer dependencies, including `@glint/template`, `@ember/test-helpers`, and `ember-resources`, which are critical for type safety, testing, and advanced reactivity.","severity":"gotcha","affected_versions":">=0.0.0"},{"fix":"Apply your preferred CSS framework classes directly to the components or wrap them in styled elements. Refer to the `ember-primitives` documentation for examples of styling various components.","message":"CSS for `ember-primitives` is unopinionated by design, meaning components are unstyled out-of-the-box. Developers are expected to provide their own styling, typically using a utility-first framework like Tailwind CSS or custom CSS.","severity":"gotcha","affected_versions":">=0.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure actions are properly decorated with `@action` in your component class and invoked correctly in templates using `{{on \"event\" this.actionName}}` or passed as arguments to child components via `@action={{this.actionName}}`.","cause":"Often occurs when an `@action` is not correctly bound or passed, especially in older Ember versions or when using `this.actionName()` directly without `{{action this.actionName}}` or `{{on 'event' this.actionName}}` in templates.","error":"TypeError: Cannot read properties of undefined (reading 'call')"},{"fix":"Verify the import path matches the component's file structure (e.g., `ember-primitives/components/switch`). Clear your Ember cache (`rm -rf tmp/ node_modules/.cache/ && npm install`) and restart the Ember development server (`ember s`).","cause":"Incorrect import path or the component was not properly discovered by the Ember build system (e.g., due to caching issues or a new component not being present).","error":"Could not find module 'ember-primitives/components/switch'"},{"fix":"Adjust your event handler function to match the expected signature, especially for components like `Switch` which changed argument order in `v0.53.1`. For example, for a `Switch`, ensure your function accepts `(checked: boolean, event: Event)`.","cause":"A Glint type error indicating a mismatch between the expected arguments of an `@onChange` handler (or similar event handler) and the provided function's signature.","error":"Argument of type '(...args: any[]) => void' is not assignable to parameter of type '(checked: boolean, event: Event) => void'."}],"ecosystem":"npm","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":null,"cli_name":""}