| .. | ||
| src | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| vite.config.ts | ||
@n8n/stylelint-config
Stylelint configuration for n8n projects with custom CSS variable naming convention enforcement.
Features
- Pre-configured stylelint rules for SCSS/Sass and Vue files
- Custom CSS variable naming convention based on the proposal.md
- Automatic enforcement via pre-commit hooks
- CI/CD integration
Installation
This package is already configured in n8n frontend packages. To use it in a new package:
{
"devDependencies": {
"@n8n/stylelint-config": "workspace:*"
}
}
Usage
Create a stylelint.config.mjs file:
import { baseConfig } from '@n8n/stylelint-config/base';
export default baseConfig;
Add scripts to your package.json:
{
"scripts": {
"lint:styles": "stylelint \"src/**/*.{scss,sass,vue}\" --cache",
"lint:styles:fix": "stylelint \"src/**/*.{scss,sass,vue}\" --fix --cache"
}
}
CSS Variable Naming Convention
The @n8n/css-var-naming rule enforces a structured naming pattern for CSS custom properties (variables).
Pattern Structure
--[namespace--][component[--part]--]property--value[--variant][--state][--mode][--media]
Required groups:
property: Property name from vocabulary (color, background, spacing, etc.)value: Semantic name or scale value
Optional groups (in order):
namespace:n8n,chat, orp(for primitives)component: Component name (e.g.,button,input)part: Sub-component (e.g.,menu,tab,arrow)variant: Visual style (e.g.,solid,outline,ghost)state: Interaction state (e.g.,hover,active,focus,disabled)mode: Theme/environment (e.g.,light,dark,hc)media: Breakpoint (e.g.,sm,md,lg)
Rules
- Pattern: Double dash
--between groups, single dash-within groups (kebab-case) - Case: Lowercase alphanumerics only
- Groups: Minimum 2, maximum 8 groups
- Order: Groups must follow the canonical order shown above
Valid Examples
/* Global tokens */
--color--primary: #0d6efd;
--spacing--md: 20px;
--text-color--muted: #888;
/* With namespace */
--n8n--color--primary: #0d6efd;
--chat--button--background--primary: #0d6efd;
--p--color--primary-500: #0d6efd;
--color--neutral-850: #2e3440;
/* Component tokens */
--button--background--primary: #0d6efd;
--button--text-color--on-primary: #fff;
--tabs--tab--text-color--muted: #888;
/* With states */
--button--background--primary--hover: #0b5ed7;
--input--border-color--primary--focus: blue;
/* With variants */
--button--background--primary--solid: #0d6efd;
--button--background--primary--outline: transparent;
/* With variants and states */
--button--background--primary--solid--hover: #0b5ed7;
--button--background--primary--outline--focus: rgba(13, 110, 253, 0.5);
/* With modes */
--color--primary--dark: #66a3ff;
--background--surface--dark: #000;
/* Complex patterns */
--n8n--button--background--primary--solid--hover--dark: #0a58ca;
Invalid Examples
/* ❌ Single dash between groups */
--color-primary: #0d6efd;
/* ❌ Only one group */
--primary: #0d6efd;
/* ❌ Uppercase letters */
--Color--Primary: #0d6efd;
/* ❌ Missing property from vocabulary */
--button--main--primary: #0d6efd;
/* ❌ Invalid value (too short) */
--color--xyz: #0d6efd;
/* ❌ Wrong order (state before variant) */
--button--background--primary--hover--solid: #0d6efd;
/* ❌ Missing required property */
--p--gray-740: #2e3440;
Property Vocabulary
The following properties are recognized:
| Property | CSS Mapping | Description |
|---|---|---|
color |
color |
Text/element color |
text-color |
color |
Text-specific color |
background |
background-color |
Background color |
border-color |
border-color |
Border color |
border-width |
border-width |
Border width |
icon-color |
fill/stroke |
Icon color |
radius |
border-radius |
Border radius |
shadow |
box-shadow |
Box shadow |
spacing |
margin/padding |
Spacing scale |
font-size |
font-size |
Font size |
font-weight |
font-weight |
Font weight |
line-height |
line-height |
Line height |
z |
z-index |
Z-index |
duration |
transition-duration |
Animation duration |
easing |
transition-timing-function |
Animation easing |
outline-color |
outline-color |
Outline color |
outline-width |
outline-width |
Outline width |
Value Types
Semantic Values
Use semantic names for values when possible:
- Colors:
primary,secondary,success,warning,danger,info,muted,surface,on-primary,on-surface - Variants:
solid,outline,ghost,link,soft,subtle - States:
hover,active,focus,focus-visible,visited,disabled,selected,checked,invalid,opened,closed,loading - Modes:
light,dark,hc(high-contrast),rtl,print
Scale Values
Use scale values for sizes and spacing:
- Size scales:
none,2xs,xs,sm,md,lg,xl,2xl,3xl - Special:
pill,full - Font weights:
regular,medium,semibold,bold - Numeric scales:
primary-100,primary-500,danger-700
Custom Values
Descriptive value names with 4+ characters are also accepted:
base,thin,thick,fast,slow,modal,tooltip,purple,teal
Usage in CSS/SCSS/Vue
Global Tokens
Define global design tokens in a central location:
:root {
--color--primary: #0d6efd;
--color--secondary: #6c757d;
--spacing--sm: 8px;
--spacing--md: 16px;
--spacing--lg: 24px;
}
Component Tokens
Create component-specific tokens that reference globals:
:root {
--button--background--primary: var(--color--primary);
--button--text-color--on-primary: #ffffff;
--button--radius--md: var(--radius--md);
--button--padding--md: var(--spacing--md);
}
Usage in Components
.button {
background: var(--button--background--primary);
color: var(--button--text-color--on-primary);
border-radius: var(--button--radius--md);
padding: var(--button--padding--md);
&:hover {
background: var(--button--background--primary--hover);
}
}
Theming
Override variables for different themes:
:root {
--color--primary: #0d6efd;
--color--surface: #ffffff;
--button--background--primary: var(--color--primary);
}
:root[data-theme="dark"] {
--color--primary: #66a3ff;
--color--surface: #0f1115;
/* button tokens automatically update through var() references */
}
Namespaced Tokens
Use namespaces for cross-app libraries:
/* In @n8n/design-system */
:root {
--n8n--color--primary: #ff6d5a;
--n8n--button--background--primary: var(--n8n--color--primary);
}
/* In @n8n/chat */
:root {
--chat--color--primary: #0d6efd;
--chat--button--background--primary: var(--chat--color--primary);
}
CI/CD Integration
The stylelint rule runs automatically in:
-
Pre-commit hooks (via lefthook):
- Validates CSS variables before commit
- Auto-fixes issues when possible
-
GitHub Actions CI:
- Runs on all pull requests
- Blocks merging if violations are found
Development
Running Tests
cd packages/@n8n/stylelint-config
pnpm test
Building
pnpm build
Testing the Rule
# Test on a specific file
pnpm stylelint "path/to/file.scss" --config stylelint.config.mjs
# Test with auto-fix
pnpm stylelint "path/to/file.scss" --fix --config stylelint.config.mjs
Troubleshooting
Common Issues
Issue: Rule not being applied
- Solution: Make sure package is built:
pnpm build
Issue: Too many violations in existing codebase
- Solution: Use
--fixto auto-fix pattern issues, or add/* stylelint-disable @n8n/css-var-naming */temporarily
Issue: False positive for a valid pattern
- Solution: Check the pattern follows the canonical structure. If it's a legitimate case, please file an issue.
Disabling the Rule
To disable for a specific line:
/* stylelint-disable-next-line @n8n/css-var-naming */
--legacy-var-name: value;
To disable for a file:
/* stylelint-disable @n8n/css-var-naming */
To disable in config (not recommended):
export default {
...baseConfig,
rules: {
...baseConfig.rules,
'@n8n/css-var-naming': null,
},
};
References
Contributing
When modifying the rule:
- Update the rule in
src/rules/css-var-naming.ts - Add/update tests in
src/rules/css-var-naming.test.ts - Run tests:
pnpm test - Build:
pnpm build - Update this README if needed
All tests must pass before submitting changes.