Skip to content

Components Rules

Component props, folder naming, structure consistency, and SVG icons

7 rules3 auto-isFixable3 isConfigurable1 TypeScript-only

component-props-destructure

auto-isFixable

Component props must be destructured in the function parameter

Why: Destructured props make it clear what props a component uses
Correct
javascript
export const Button = ({ label, onClick }) => (    <button onClick={onClick}>{label}</button>);
Incorrect
javascript
export const Button = (props) => (    <button onClick={props.onClick}>{props.label}</button>);
eslint.config.js
javascript
"code-style/component-props-destructure": "error"

component-props-inline-type

auto-isFixableTypeScript only

Enforce inline type annotation for component props instead of interface reference

Why: Inline types keep prop definitions colocated with the component
Correct
javascript
export const Button = ({ label } : { label: string }) => (    <button>{label}</button>);
Incorrect
javascript
export const Button = ({ label }: ButtonPropsInterface) => (    <button>{label}</button>);
eslint.config.js
javascript
"code-style/component-props-inline-type": "error"

folder-based-naming-convention

auto-isFixableisConfigurable

Enforce naming based on folder: suffix for views/layouts/pages/providers, camelCase for data/constants/strings/reducers/schemas. Services folder function exports drop the Service suffix (Handler from function-naming-convention is enough). Local/private variables are not checked.

Why: Consistent naming based on folder structure makes purpose immediately clear. Service suffix is redundant on function exports because Handler suffix already conveys callability — combining both yields ugly names like getDataServiceHandler when getDataHandler suffices. Plural file names that match the folder suffix (e.g., services/services.js) are deduped to avoid ServicesService.

Options

OptionTypeDefaultDescription
chainOrderstring"child-parent"Order of folder chain in names
filesarray[]Per-path chainOrder overrides
eslint.config.js
javascript
"code-style/folder-based-naming-convention": ["error", { chainOrder: "child-parent", files: [] }]
Correct
javascript
// views/dashboard.tsxexport const DashboardView = () => <div>Dashboard</div>; // services/services.js — function export, no Service suffixexport const getDataHandler = async () => fetch("/api"); // services/user-service.ts — class/object export, Service suffix keptexport class UserService { /* ... */ }
Incorrect
javascript
// views/dashboard.tsxexport const Dashboard = () => <div>Dashboard</div>; // services/services.js — old behavior produced absurd chainexport const getDataServicesServiceHandlerServicesServiceHandler... = async () => {};
eslint.config.js
javascript
"code-style/folder-based-naming-convention": "error"

folder-structure-consistency

isConfigurablereport only

Enforce consistent folder structure (flat vs wrapped) in module folders

Why: Mixing flat files and wrapped folders creates inconsistency

Options

OptionTypeDefaultDescription
moduleFoldersstring[](built-in list)Module folders to check
extraModuleFoldersstring[][]Additional folders to check
eslint.config.js
javascript
"code-style/folder-structure-consistency": ["error", { moduleFolders: (built-in list), extraModuleFolders: [] }]
Correct
javascript
atoms/input.tsxatoms/calendar.tsx
Incorrect
javascript
atoms/input.tsxatoms/calendar/index.tsxatoms/calendar/helpers.ts
eslint.config.js
javascript
"code-style/folder-structure-consistency": "error"

no-redundant-folder-suffix

report only

Disallow file/folder names that redundantly include the parent folder name as a suffix

Why: The folder already provides context, so the name doesn't need to repeat it
Correct
javascript
layouts/main.tsx
Incorrect
javascript
layouts/main-layout.tsx
eslint.config.js
javascript
"code-style/no-redundant-folder-suffix": "error"

no-scattered-component-variants

isConfigurablereport only

Disallow scattered component variants that share a trailing name token — collapse them into one folder named by the shared token

Why: Siblings like copy-button and icon-button repeat the same suffix on every name; collapsing them into button/{copy,icon}.tsx groups related variants and removes the redundant suffix

Options

OptionTypeDefaultDescription
moduleFoldersstring[](built-in list)Module folders to check
extraModuleFoldersstring[][]Additional folders to check
eslint.config.js
javascript
"code-style/no-scattered-component-variants": ["error", { moduleFolders: (built-in list), extraModuleFolders: [] }]
Correct
javascript
ui/button/copy.tsx
Incorrect
javascript
ui/copy-button.tsx
eslint.config.js
javascript
"code-style/no-scattered-component-variants": "error"

svg-icon-naming-convention

report only

SVG components must end with 'Icon' suffix; 'Icon' suffix components must return SVG

Why: Consistent naming makes it clear which components render icons
Correct
javascript
export const SuccessIcon = () => (    <svg><path d="M9 12l2 2 4-4" /></svg>);
Incorrect
javascript
export const Success = () => (    <svg><path d="M9 12l2 2 4-4" /></svg>);
eslint.config.js
javascript
"code-style/svg-icon-naming-convention": "error"