or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

component-rules.mdcomputed-property-rules.mdember-utils.mdindex.mdlegacy-configuration.mdmigration-rules.mdmodern-configuration.mdplugin-configuration.mdroute-rules.mdservice-rules.mdtest-rules.md
tile.json

component-rules.mddocs/

Component Rules

Linting rules specific to Ember components, enforcing modern component patterns and preventing common anti-patterns. These rules help maintain consistency and best practices in Ember component development.

Core Imports

const eslintPluginEmber = require('eslint-plugin-ember');

// Access component rules
const componentRules = eslintPluginEmber.rules;

ES Module:

import eslintPluginEmber from 'eslint-plugin-ember';

// Access component rules  
const componentRules = eslintPluginEmber.rules;

Capabilities

Actions and Event Handling Rules

Rules governing action handling and event management in components.

/**
 * Disallow the actions hash in components, controllers, and routes
 * Encourages use of @action decorator instead
 */
'ember/no-actions-hash': ESLintRule;

/**
 * Disallow on() calls in components
 * Prevents direct event binding in component lifecycle
 */
'ember/no-on-calls-in-components': ESLintRule;

/**
 * Require closure actions over sendAction
 * Enforces modern action passing patterns
 */
'ember/closure-actions': ESLintRule;

Usage Examples:

// ❌ Bad - actions hash (triggers no-actions-hash)
export default Component.extend({
  actions: {
    handleClick() {
      // action logic
    }
  }
});

// ✅ Good - @action decorator
export default class MyComponent extends Component {
  @action
  handleClick() {
    // action logic
  }
}

// ❌ Bad - sendAction (triggers closure-actions)
this.sendAction('onUpdate', value);

// ✅ Good - closure action
this.args.onUpdate(value);

Component Lifecycle Rules

Rules for managing component lifecycle hooks and preventing deprecated patterns.

/**
 * Disallow component lifecycle hooks that are deprecated
 * Enforces modern lifecycle patterns
 */
'ember/no-component-lifecycle-hooks': ESLintRule;

/**
 * Require super calls in lifecycle hooks
 * Ensures proper inheritance chain execution
 */
'ember/require-super-in-lifecycle-hooks': ESLintRule;

Usage Examples:

// ❌ Bad - deprecated lifecycle hook
export default Component.extend({
  didInsertElement() {
    // This hook is deprecated
  }
});

// ✅ Good - modern patterns with modifiers
<template>
  <div {{did-insert this.setup}}></div>
</template>

// ❌ Bad - missing super call
export default class extends Component {
  willDestroy() {
    this.cleanup();
    // Missing super call
  }
}

// ✅ Good - proper super call
export default class extends Component {
  willDestroy() {
    super.willDestroy(...arguments);
    this.cleanup();
  }
}

Component Property Rules

Rules governing component properties and attribute handling.

/**
 * Disallow this.attrs in components
 * Enforces args usage over deprecated attrs
 */
'ember/no-attrs-in-components': ESLintRule;

/**
 * Disallow attrs snapshot usage
 * Prevents deprecated attrs.foo pattern
 */
'ember/no-attrs-snapshot': ESLintRule;

/**
 * Disallow empty attrs objects
 * Removes unnecessary empty attrs declarations
 */
'ember/no-empty-attrs': ESLintRule;

Usage Examples:

// ❌ Bad - using this.attrs (triggers no-attrs-in-components)
export default Component.extend({
  someProperty: computed('attrs.value', function() {
    return this.attrs.value * 2;
  })
});

// ✅ Good - using args
export default class MyComponent extends Component {
  @computed('args.value')
  get someProperty() {
    return this.args.value * 2;
  }
}

// ❌ Bad - empty attrs (triggers no-empty-attrs)
export default Component.extend({
  attrs: {}
});

// ✅ Good - no attrs declaration needed
export default class MyComponent extends Component {
  // No attrs needed
}

Classic vs Modern Component Rules

Rules enforcing modern component patterns over classic Ember patterns.

/**
 * Disallow classic component patterns
 * Encourages native class components
 */
'ember/no-classic-components': ESLintRule;

/**
 * Disallow classic classes in general
 * Promotes native ES classes
 */
'ember/no-classic-classes': ESLintRule;

/**
 * Disallow empty Glimmer component classes
 * Removes unnecessary empty component files
 */
'ember/no-empty-glimmer-component-classes': ESLintRule;

Usage Examples:

// ❌ Bad - classic component (triggers no-classic-components)
export default Component.extend({
  tagName: 'div',
  classNames: ['my-component']
});

// ✅ Good - modern Glimmer component
export default class MyComponent extends Component {
  // Modern component patterns
}

// ❌ Bad - empty Glimmer component (triggers no-empty-glimmer-component-classes)
export default class MyComponent extends Component {
  // Empty class with no purpose
}

// ✅ Good - component with actual functionality
export default class MyComponent extends Component {
  @tracked isVisible = true;
  
  @action
  toggle() {
    this.isVisible = !this.isVisible;
  }
}

Component Organization Rules

Rules for organizing component properties and maintaining consistent structure.

/**
 * Enforce order of properties in components
 * Maintains consistent component structure
 */
'ember/order-in-components': ESLintRule;

/**
 * Require tagless components
 * Encourages modern component architecture
 */
'ember/require-tagless-components': ESLintRule;

Usage Examples:

// ❌ Bad - incorrect property order (triggers order-in-components)
export default Component.extend({
  actions: {},
  someProperty: 'value',
  init() {
    this._super(...arguments);
  },
  classNames: ['my-component']
});

// ✅ Good - correct property order
export default Component.extend({
  classNames: ['my-component'],
  
  someProperty: 'value',
  
  init() {
    this._super(...arguments);
  },
  
  actions: {}
});

// ❌ Bad - component with wrapper element
export default Component.extend({
  tagName: 'div'
});

// ✅ Good - tagless component
export default class MyComponent extends Component {
  // No wrapper element needed
}

Component Template Rules

Rules for component template handling and built-in component usage.

/**
 * Disallow built-in form components
 * Encourages custom form component patterns
 */
'ember/no-builtin-form-components': ESLintRule;

Usage Examples:

// ❌ Bad - built-in form components (triggers no-builtin-form-components)
{{input value=this.name}}
{{textarea value=this.description}}

// ✅ Good - custom form components
<Input @value={{this.name}} @onInput={{this.updateName}} />
<Textarea @value={{this.description}} @onInput={{this.updateDescription}} />

Component State Management Rules

Rules for managing component state and preventing common pitfalls.

/**
 * Disallow assignment of untracked properties used in tracking contexts
 * Prevents reactivity issues
 */
'ember/no-assignment-of-untracked-properties-used-in-tracking-contexts': ESLintRule;

/**
 * Disallow tracked properties derived from args
 * Prevents unnecessary tracking overhead
 */
'ember/no-tracked-properties-from-args': ESLintRule;

Component Decorator Rules

Rules for managing component decorators and modern class patterns.

/**
 * Enforce using correct hooks for both classic and non-classic classes
 * Ensures proper lifecycle hook usage in modern components
 */
'ember/classic-decorator-hooks': ESLintRule;

/**
 * Disallow usage of classic APIs in classes not decorated with @classic
 * Prevents mixing classic and modern patterns incorrectly
 */
'ember/classic-decorator-no-classic-methods': ESLintRule;

Usage Examples:

// ❌ Bad - using classic hook in modern class (triggers classic-decorator-hooks)
export default class MyComponent extends Component {
  didInsertElement() {
    // Classic hook in modern class
  }
}

// ✅ Good - using modern patterns
export default class MyComponent extends Component {
  @action
  setupElement(element) {
    // Modern pattern with modifiers or actions
  }
}

// ❌ Bad - classic API without @classic (triggers classic-decorator-no-classic-methods)
export default class MyComponent extends Component {
  init() {
    this.set('value', 0); // Classic API in modern class
  }
}

// ✅ Good - modern property assignment
export default class MyComponent extends Component {
  @tracked value = 0; // Modern tracked property
}

Component Template Integration Rules

Rules for component template handling and render modifier usage.

/**
 * Disallow importing from @ember/render-modifiers
 * Prevents usage of deprecated render modifier imports
 */
'ember/no-at-ember-render-modifiers': ESLintRule;

Usage Examples:

// ❌ Bad - deprecated render modifier import (triggers no-at-ember-render-modifiers)
import { modifier } from '@ember/render-modifiers';

// ✅ Good - use ember-modifier package instead
import { modifier } from 'ember-modifier';

// ❌ Bad - untracked property in tracking context export default class MyComponent extends Component { someValue = 0; // Not tracked but used in template }

// ✅ Good - properly tracked property export default class MyComponent extends Component { @tracked someValue = 0; }

// ❌ Bad - tracked property from args (triggers no-tracked-properties-from-args) export default class MyComponent extends Component { @tracked derivedValue = this.args.value; }

// ✅ Good - computed property from args export default class MyComponent extends Component { get derivedValue() { return this.args.value; } }