More than 100 powerful ESLint rules for enforcing code quality, consistency, and modern JavaScript best practices
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Rules specific to DOM manipulation and browser environment patterns for web development.
Rules for modern DOM node manipulation methods.
/**
* Prefers Node.append() over Node.appendChild()
*/
'unicorn/prefer-dom-node-append': 'error' | 'warn' | 'off';
/**
* Prefers Node.remove() over parentNode.removeChild()
*/
'unicorn/prefer-dom-node-remove': 'error' | 'warn' | 'off';
/**
* Prefers Node.textContent over Node.innerText
*/
'unicorn/prefer-dom-node-text-content': 'error' | 'warn' | 'off';
/**
* Prefers dataset API over getAttribute/setAttribute for data attributes
*/
'unicorn/prefer-dom-node-dataset': 'error' | 'warn' | 'off';Usage Examples:
// ❌ Bad - legacy DOM manipulation
const parent = document.getElementById('container');
const child = document.createElement('div');
parent.appendChild(child);
// ✅ Good - modern DOM manipulation
const parent = document.getElementById('container');
const child = document.createElement('div');
parent.append(child);
// ❌ Bad - legacy node removal
const element = document.getElementById('target');
element.parentNode.removeChild(element);
// ✅ Good - modern node removal
const element = document.getElementById('target');
element.remove();
// ❌ Bad - using innerText
element.innerText = 'Hello World';
// ✅ Good - using textContent
element.textContent = 'Hello World';
// ❌ Bad - manual data attribute handling
element.setAttribute('data-user-id', '123');
const userId = element.getAttribute('data-user-id');
// ✅ Good - using dataset API
element.dataset.userId = '123';
const userId = element.dataset.userId;Rules for modern element selection methods.
/**
* Prefers querySelector/querySelectorAll over legacy methods
*/
'unicorn/prefer-query-selector': 'error' | 'warn' | 'off' | [
'error' | 'warn',
{
checkId?: boolean; // Default: true
checkClass?: boolean; // Default: true
checkTag?: boolean; // Default: false
checkAttribute?: boolean; // Default: true
}
];
/**
* Prefers modern DOM APIs over legacy methods
*/
'unicorn/prefer-modern-dom-apis': 'error' | 'warn' | 'off';Usage Examples:
// ❌ Bad - legacy element selection
const elementById = document.getElementById('myId');
const elementsByClass = document.getElementsByClassName('myClass');
const elementsByTag = document.getElementsByTagName('div');
// ✅ Good - modern element selection
const elementById = document.querySelector('#myId');
const elementsByClass = document.querySelectorAll('.myClass');
const elementsByTag = document.querySelectorAll('div');
// ❌ Bad - legacy DOM methods
element.setAttribute('hidden', '');
const isHidden = element.hasAttribute('hidden');
// ✅ Good - modern DOM properties
element.hidden = true;
const isHidden = element.hidden;Rules for modern event handling patterns.
/**
* Prefers addEventListener over on* properties
*/
'unicorn/prefer-add-event-listener': 'error' | 'warn' | 'off' | [
'error' | 'warn',
{
excludedPackages?: string[]; // Default: ['koa', 'sax']
}
];
/**
* Prefers EventTarget over other event handling patterns
*/
'unicorn/prefer-event-target': 'error' | 'warn' | 'off';
/**
* Prefers KeyboardEvent.key over KeyboardEvent.keyCode
*/
'unicorn/prefer-keyboard-event-key': 'error' | 'warn' | 'off';
/**
* Prevents invalid removeEventListener calls
*/
'unicorn/no-invalid-remove-event-listener': 'error' | 'warn' | 'off';Usage Examples:
// ❌ Bad - on* event properties
button.onclick = handleClick;
window.onload = initialize;
// ✅ Good - addEventListener
button.addEventListener('click', handleClick);
window.addEventListener('load', initialize);
// ❌ Bad - legacy keyboard event handling
document.addEventListener('keydown', (event) => {
if (event.keyCode === 13) { // Enter key
handleEnter();
}
if (event.keyCode === 27) { // Escape key
handleEscape();
}
});
// ✅ Good - modern keyboard event handling
document.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
handleEnter();
}
if (event.key === 'Escape') {
handleEscape();
}
});
// ❌ Bad - invalid removeEventListener
element.addEventListener('click', () => handleClick());
element.removeEventListener('click', () => handleClick()); // Won't work
// ✅ Good - proper removeEventListener
const clickHandler = () => handleClick();
element.addEventListener('click', clickHandler);
element.removeEventListener('click', clickHandler);Rules for modern browser APIs and patterns.
/**
* Prevents document.cookie usage in favor of proper cookie handling
*/
'unicorn/no-document-cookie': 'error' | 'warn' | 'off';
/**
* Prefers Blob reading methods over alternatives
*/
'unicorn/prefer-blob-reading-methods': 'error' | 'warn' | 'off';
/**
* Prevents invalid fetch options
*/
'unicorn/no-invalid-fetch-options': 'error' | 'warn' | 'off';
/**
* Requires postMessage target origin specification
*/
'unicorn/require-post-message-target-origin': 'error' | 'warn' | 'off';Usage Examples:
// ❌ Bad - direct document.cookie manipulation
const getCookie = (name) => {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
};
// ✅ Good - proper cookie handling with library or modern API
// Use a cookie library or the newer Cookie Store API when available
if ('cookieStore' in window) {
const cookie = await cookieStore.get(name);
}
// ❌ Bad - manual blob reading
const reader = new FileReader();
reader.onload = (event) => {
const text = event.target.result;
};
reader.readAsText(blob);
// ✅ Good - modern blob reading
const text = await blob.text();
const arrayBuffer = await blob.arrayBuffer();
const dataUrl = await blob.dataURL();
// ❌ Bad - invalid fetch options
fetch('/api/data', {
method: 'GET',
body: JSON.stringify(data), // Invalid: GET requests can't have body
});
// ✅ Good - valid fetch options
fetch('/api/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
// ❌ Bad - postMessage without target origin
window.postMessage(data, '*');
// ✅ Good - postMessage with specific target origin
window.postMessage(data, 'https://trusted-domain.com');Rules for modern form and input handling patterns.
/**
* Modern DOM APIs include better form handling patterns
*/
'unicorn/prefer-modern-dom-apis': 'error' | 'warn' | 'off';Usage Examples:
// ❌ Bad - legacy form data handling
const form = document.forms.myForm;
const data = {};
for (const element of form.elements) {
if (element.name) {
data[element.name] = element.value;
}
}
// ✅ Good - modern FormData API
const form = document.forms.myForm;
const formData = new FormData(form);
const data = Object.fromEntries(formData);
// ❌ Bad - manual input validation
const email = input.value;
const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
// ✅ Good - built-in constraint validation
const isValid = input.checkValidity();
const validationMessage = input.validationMessage;Rules for custom elements and web components.
/**
* EventTarget patterns for custom events
*/
'unicorn/prefer-event-target': 'error' | 'warn' | 'off';Usage Examples:
// ❌ Bad - manual event handling for custom elements
class MyElement extends HTMLElement {
constructor() {
super();
this.listeners = new Map();
}
on(event, handler) {
if (!this.listeners.has(event)) {
this.listeners.set(event, []);
}
this.listeners.get(event).push(handler);
}
emit(event, data) {
if (this.listeners.has(event)) {
this.listeners.get(event).forEach(handler => handler(data));
}
}
}
// ✅ Good - using EventTarget for custom elements
class MyElement extends HTMLElement {
constructor() {
super();
}
emitCustomEvent(type, detail) {
this.dispatchEvent(new CustomEvent(type, { detail }));
}
}
// Usage
const element = new MyElement();
element.addEventListener('custom-event', (event) => {
console.log(event.detail);
});
element.emitCustomEvent('custom-event', { data: 'value' });Rules for DOM performance optimization.
/**
* Query selector optimization patterns
*/
'unicorn/prefer-query-selector': [
'error',
{
checkId: true, // querySelector('#id') over getElementById
checkClass: true, // querySelectorAll('.class') over getElementsByClassName
checkTag: false, // Allow getElementsByTagName for performance
}
];Usage Examples:
// Performance considerations:
// ❌ Less efficient for simple ID lookups (sometimes)
const element = document.querySelector('#myId');
// ✅ More efficient for simple ID lookups (sometimes)
const element = document.getElementById('myId');
// But querySelector is more consistent and flexible:
// ✅ Consistent API for complex selectors
const elements = document.querySelectorAll('.class[data-active="true"]');
// ✅ Better for chaining and complex queries
const specificElement = container.querySelector('.item:nth-child(3)');export default [
{
plugins: {
unicorn: eslintPluginUnicorn,
},
rules: {
// DOM manipulation
'unicorn/prefer-dom-node-append': 'error',
'unicorn/prefer-dom-node-remove': 'error',
'unicorn/prefer-dom-node-text-content': 'error',
'unicorn/prefer-dom-node-dataset': 'error',
// Element selection
'unicorn/prefer-query-selector': ['error', {
checkId: true,
checkClass: true,
checkTag: false, // Keep for performance
checkAttribute: true,
}],
'unicorn/prefer-modern-dom-apis': 'error',
// Event handling
'unicorn/prefer-add-event-listener': 'error',
'unicorn/prefer-event-target': 'error',
'unicorn/prefer-keyboard-event-key': 'error',
'unicorn/no-invalid-remove-event-listener': 'error',
// Browser APIs
'unicorn/no-document-cookie': 'error',
'unicorn/prefer-blob-reading-methods': 'error',
'unicorn/no-invalid-fetch-options': 'error',
'unicorn/require-post-message-target-origin': 'error',
},
},
];export default [
{
plugins: {
unicorn: eslintPluginUnicorn,
},
rules: {
// DOM manipulation (less relevant in React)
'unicorn/prefer-dom-node-append': 'warn', // React handles this
'unicorn/prefer-dom-node-remove': 'warn', // React handles this
'unicorn/prefer-dom-node-text-content': 'error',
'unicorn/prefer-dom-node-dataset': 'error',
// Event handling (important for React)
'unicorn/prefer-add-event-listener': ['error', {
excludedPackages: ['react', '@types/react']
}],
'unicorn/prefer-keyboard-event-key': 'error',
'unicorn/no-invalid-remove-event-listener': 'error',
// Browser APIs (still relevant)
'unicorn/no-document-cookie': 'error',
'unicorn/prefer-blob-reading-methods': 'error',
'unicorn/no-invalid-fetch-options': 'error',
'unicorn/require-post-message-target-origin': 'error',
},
},
];export default [
{
plugins: {
unicorn: eslintPluginUnicorn,
},
rules: {
// Be more lenient with modern APIs for legacy support
'unicorn/prefer-modern-dom-apis': 'warn',
'unicorn/prefer-blob-reading-methods': 'off', // May not be supported
// Still enforce good practices
'unicorn/prefer-add-event-listener': 'error',
'unicorn/prefer-keyboard-event-key': 'error',
'unicorn/no-invalid-fetch-options': 'error',
'unicorn/no-document-cookie': 'warn', // May be necessary fallback
// Query selector support varies
'unicorn/prefer-query-selector': ['warn', {
checkId: false, // getElementById has better support
checkClass: false, // getElementsByClassName has better support
checkTag: false, // getElementsByTagName has better support
}],
},
},
];