@gabegabegabe/stylelint-config
v6.0.0
Published
Gabe's stylelint config
Maintainers
Readme
@gabegabegabe/stylelint-config
Gabe's shareable Stylelint config: a small set of
opinionated rules — no named colors, no physical units (px/pt), logical
properties over physical, numeric font weights, double-colon pseudo-elements,
modern @use hygiene, kebab-case SCSS identifiers, and friends — composed on
top of the stylelint-config-standard* bases.
It is opinionated and tuned to a specific, modern toolchain: a Stylelint
17.x floor, the stylelint-config-standard /
stylelint-config-standard-scss bases, and postcss-html for Vue SFCs. It is
published for anyone to use, but makes no attempt to accommodate older Stylelint
versions or other stacks.
Usage
Install the package, stylelint, and the peer(s) for the leaf you want to
extend (see Requirements):
bun add -D @gabegabegabe/stylelint-config stylelint stylelint-config-standard-scssThen point your Stylelint config at the leaf that matches what you are linting:
export default {
extends: ['@gabegabegabe/stylelint-config/scss']
};Which config do I extend?
Pick by what you are linting, not by your framework. Each leaf is defined by exactly one (dialect, host) pair — the stylesheet language, and where the styles physically live.
| You are linting | Extend |
| ---------------- | ---------- |
| Plain CSS | css |
| SCSS | scss |
| CSS in Vue SFCs | vue |
| SCSS in Vue SFCs | vue-scss |
opinions and scss-opinions are exported too, but they are layers —
internal building blocks the leaves compose. Extend a leaf, not a layer.
Mixed projects (CSS and SCSS together)
There is no default entry point; each file type extends its own leaf through
overrides. Stylelint requires a rules property at the config root, so give
the root an empty one:
export default {
rules: {},
overrides: [
{
files: ['**/*.css'],
extends: ['@gabegabegabe/stylelint-config/css']
},
{
files: ['**/*.scss'],
extends: ['@gabegabegabe/stylelint-config/scss']
}
]
};The empty rules: {} is load-bearing: Stylelint 17 rejects an overrides-only
config with No rules found within configuration.
Migrating from v5
v6 is a ground-up redesign. To upgrade:
- Replace the default import with a leaf. v5's bare entry point
(
extends: ['@gabegabegabe/stylelint-config']) is gone — there is no default export. Point each config (or eachoverridesentry) at the leaf for what you are linting:/css,/scss,/vue, or/vue-scss. See Which config do I extend?. - Bump Stylelint and the bases.
stylelint16.x→17.x,stylelint-config-standard36.x→40.x, andstylelint-config-standard-scss13.x→17.x. Node>=20.19is now required. - Swap the Vue peer. If you lint Vue SFCs, replace
stylelint-config-standard-vuewithpostcss-html; the Vue leaves now setcustomSyntaxand the Vue allowances themselves (see ADR 0001). - Expect stricter results. v6 adopts Stylelint 17's newer rules and a more aggressive logical-property / relative-unit stance, so existing stylesheets may surface new warnings. Full details in the changelog.
Architecture
The configs are assembled from small composable layers via Stylelint's
native extends. Consumers extend a leaf; the layers are the building
blocks.
| File | Kind | Composes |
| ------------------ | ----- | ------------------------------------------------------------------------------------ |
| opinions.js | layer | The dialect-agnostic CSS taste (named colors, units, casing, empty lines, …). |
| scss-opinions.js | layer | The SCSS-only rules, plus the declaration-property-value-no-unknown null override. |
| css.js | leaf | stylelint-config-standard + opinions. |
| scss.js | leaf | stylelint-config-standard-scss + opinions + scss-opinions. |
| vue.js | leaf | css, but for SFCs: postcss-html + the ported Vue allowances. |
| vue-scss.js | leaf | scss, but for SFCs: postcss-html + the ported Vue allowances. |
Three invariants govern the composition:
- Compose opinions last. Every leaf lists Gabe's layers after the upstream
stylelint-config-standard*base, so the opinions win the merge. - Options replace, not merge. Stylelint merges the
rulesmap key-by-key, but replaces a rule's options wholesale. Where a leaf adds to an option a layer already set —value-keyword-casein the Vue leaves carries bothcamelCaseSvgKeywords(fromopinions) andignoreFunctions: ['v-bind']— it restates the whole option. - Be explicit; depend on nothing version-volatile. The Vue leaves own
customSyntax: postcss-htmland the Vue allowances directly rather than extending the dormantstylelint-config-standard-vue— see ADR 0001.
A config exists for each (dialect, host) pair, never for a project role. "A
component library" and "an app" lint SCSS the same way, so both extend scss;
roles are documented here, not given their own configs.
Requirements
stylelint 17.x is required. The rest are optional peers — install only the
ones for the leaves you extend:
| Leaf | Peer dependencies |
| ---------- | ------------------------------------------------ |
| css | stylelint-config-standard |
| scss | stylelint-config-standard-scss |
| vue | stylelint-config-standard, postcss-html |
| vue-scss | stylelint-config-standard-scss, postcss-html |
Development
bun run lint # ESLint the config + test files
bun run format # Prettier the whole tree
bun test # Lint each leaf against its valid + invalid fixtures
bun outdated # Check for dependency updates