Reusable ESLint plugin for frontend projects: enforces consistent naming, design, and code quality rules for React and TypeScript, including Typography components, color usage, file naming, export style, and more.
npm install eslint-frontend-rulesReusable ESLint plugin for frontend projects. Enforces code consistency, design standards, and best practices for React/TypeScript codebases.
```
npm install --save-dev eslint-frontend-rules
Add eslint-frontend-rules to your ESLint config:
`json`
{
"extends": [
frontendRules.configs.recommended,
],
"plugins": {
"eslint-frontend-rules": frontendRules,
},
"rules": {
// Optionally override rule levels or options here
}
}
Enforces the use of Typography components instead of raw HTML tags (, , -, ) in React JSX.
- Native tags are only allowed in typography.tsx tag detected. Use Typography components (e.g., TypographyP, TypographyH1, TypographyBlockquote). (or configure ignore patterns).ignore
- Error: Raw
- Options: (array of glob patterns)
Prevents the use of direct color values in inline styles or classNames.
- Disallows hex codes, rgb(a), hsl(a), and named colors in style/className.
- Allows CSS variables or theme tokens.
- Error: Do not use direct color values (e.g., '#fff', 'red', 'rgb(0,0,0)').
- Options: ignore (array of glob patterns)
Requires top-level const variable names to be ALL_CAPS (snake case) in .tsx files.
- Functions are ignored.
- Options: ignore (array of glob patterns)
Flags non-interactive elements (e.g., - Skips custom components and interactive HTML elements. Enforces kebab-case format for file names. - Default: Enforces naming conventions for TypeScript interfaces and types. - Interfaces: must start with Disallows default exports; enforces named exports only. - Options: Warns on inline arrow functions in JSX props (e.g., - Options: Enforces the use of alias import paths instead of relative paths (e.g., '@/components/Button' instead of '../../components/Button'). - Helps maintain consistent and readable import statements by requiring configured alias prefixes. Example configuration: Disallows defining a new component inside another component. - Prevents declaring a React component (function or class) inside the body of another component. Why? - Inner components are recreated on every render, breaking memoization and harming performance. Warns if React fragments ( - Warns when a fragment wraps only a single child or is not needed for grouping. Example: return ( return ( // OK: Warns if a root-level function (not a React component or hook) lacks a JSDoc comment. - Only applies to root-level functions (not inside a component/class). Example configuration: Example: const doSomething = () => { // OK (has JSDoc): // OK (component): // OK (hook): Warns if a root-level React component lacks a JSDoc comment. - Only applies to root-level functions that are React components (name starts with uppercase letter). Example configuration: Example: const Button = () => ; // OK (has JSDoc): Warns if a root-level React hook lacks a JSDoc comment. - Only applies to root-level functions that are hooks (name starts with Example configuration: Example: const useSomething = () => { // OK (has JSDoc): Warns if JSX props use unnecessary curly braces for string literals. - Example: Example: // OK: Warns if the - Example: Example configuration: Example: // OK: Disallows empty or whitespace-only - Flags cases where Error: Empty className string found. Remove it or add valid classes. Example: // ✅ OK: MIT) with onClick but missing role="button" or onKeyDown.ignore
- Options: (array of glob patterns).js$3
, .ts, .jsx, .tsx, .json, .css (configurable)ignore
- Checks only the part before the first dot.
- Options: , extensions (array)I$3
or end with Props.T
- Types: must start with or end with Props.ignore
- Options: (array of glob patterns)ignore$3
(array of glob patterns)onClick={() => ...}$3
).ignore (array of glob patterns)@$3
- Default allowed alias: . You can configure more aliases in your ESLint config.aliases
- Options:
- : Array of allowed alias prefixes for import paths (e.g., ['@', '@components', '@utils']).ignore
- : Array of glob patterns to ignore files or import paths.`js`
// .eslintrc.js
rules: {
'eslint-frontend-rules/enforce-alias-import-paths': [
'error',
{
aliases: ['@', '@components', '@utils'],
ignore: ['*/.test.tsx']
}
]
}ignore$3
- All components should be defined at the top level of the file for performance and maintainability.
- Error: Do not define a new component inside another component. Move it to the top level of the file.
- Options: (array of glob patterns)<>...>
- Encourages clear, maintainable code structure.$3
, , or ) are unnecessary.<>...>
- Supports both short syntax () and named fragments (, ).`
- Helps keep JSX clean and readable by removing redundant fragments.
- No options.jsx`
// Warns:
return (
<>
>
);
);
);
return (
<>
>
);use$3
- Skips React components (names starting with uppercase) and hooks (names starting with ).utils/
- Supports folder restriction via options (e.g., only in ).folders
- Error: Root-level function "myFunction" should have a JSDoc comment.
- Options:
- : Array of glob patterns to restrict rule to certain folders/files.`js`
rules: {
'eslint-frontend-rules/require-jsdoc-on-root-function': [
'warn',
{ folders: ['src/utils/**'] }
]
}`js`
// Warns:
function myUtil() {
/ ... /
}
/ ... /
};
/**
* Adds two numbers.
*/
function add(a, b) {
return a + b;
}
function MyComponent() {
return
}
function useCustomHook() {
/ ... /
}components/$3
- Supports folder restriction via options (e.g., only in ).folders
- Error: Root-level React component "MyComponent" should have a JSDoc comment.
- Options:
- : Array of glob patterns to restrict rule to certain folders/files.`js`
rules: {
'eslint-frontend-rules/require-jsdoc-on-component': [
'warn',
{ folders: ['src/components/**'] }
]
}`js`
// Warns:
function MyComponent() {
return ;
}
/**
* My button component.
*/
function Button() {
return ;
}use$3
followed by uppercase letter or digit).hooks/
- Supports folder restriction via options (e.g., only in ).folders
- Error: Root-level React hook "useCustom" should have a JSDoc comment.
- Options:
- : Array of glob patterns to restrict rule to certain folders/files.`js`
rules: {
'eslint-frontend-rules/require-jsdoc-on-hook': [
'warn',
{ folders: ['src/hooks/**'] }
]
}`js`
// Warns:
function useCustom() {
// ...
}
/ ... /
};
/**
* Custom hook for ...
*/
function useCustom() {
// ...
}$3
(should be ){'xyz'}
- Auto-fixable: will convert to "xyz" in props.`
- No options.jsx`
// Warns and auto-fixes:className$3
prop in JSX is set to a template string (e.g., className={foo ${bar}} ) instead of using a function or library (like cn).(should usecn or a similar utility)className="foo bar"
- Allows plain string literals (e.g., ) and empty string by default.allow
- Options:
- : Array of allowed string literal values for className (default: [""]).`js`
rules: {
'eslint-frontend-rules/enforce-classname-utility': [
'warn',
{ allow: [""] }
]
}`jsx
// Warns:} />} />`className$3
attributes in JSX.className is set but contains no usable value.className=""
- Helps keep code clean by avoiding unnecessary , className=" ", or className={""}.`
- Works with string literals, expression containers, and template literals.
- No options.jsx
// ❌ Warns: } />``Example: Custom Rule Options
json``
{
"rules": {
"eslint-frontend-rules/enforce-typography-components": [
"error",
{ "ignore": ["/legacy//*.tsx"] }
],
"eslint-frontend-rules/no-direct-colors": [
"error",
{ "ignore": ["/test-utils/"] }
],
"eslint-frontend-rules/enforce-kebab-case-filenames": [
"error",
{ "extensions": [".js", ".ts", ".json"] }
],
"eslint-frontend-rules/no-inline-arrow-functions-in-jsx": [
"warn",
{ "ignore": ["/storybook/"] }
],
"eslint-frontend-rules/enforce-alias-import-paths": [
"error",
{
"aliases": ["@"],
"ignore": ["/node_modules/"]
}
]
}
}License