ESLint
The Svelte preprocessor fixes scoped:class during builds, but ESLint sees a
different path. eslint-plugin-svelte runs svelte/valid-compile against the source
it receives from ESLint, so raw scoped:class can fail before your Svelte build
preprocessor ever gets a turn.
Without the lint processor, a scoped prop can produce errors like:
Attributes should not contain ':' characters to prevent ambiguity with Svelte directives
Unused CSS selector ".parent-owned"Attributes should not contain ':' characters to prevent ambiguity with Svelte directives
Unused CSS selector ".parent-owned"Use the package’s ESLint processor to run the same scoped-props transform before Svelte lint rules compile the component.
Flat config
Add the scoped props config after eslint-plugin-svelte’s flat config.
import svelte from 'eslint-plugin-svelte'
import scopedProps from '@humanspeak/svelte-scoped-props/eslint'
export default [
...svelte.configs['flat/recommended'],
...scopedProps.configs.recommended
]import svelte from 'eslint-plugin-svelte'
import scopedProps from '@humanspeak/svelte-scoped-props/eslint'
export default [
...svelte.configs['flat/recommended'],
...scopedProps.configs.recommended
]ESLint only supports one active processor per file. Placing this config after the
Svelte config lets the Svelte parser and rules remain active while the scoped props
processor supplies transformed markup for .svelte files.
Custom options
If your Svelte preprocessor uses custom hash options, pass the same options to the ESLint processor.
import svelte from 'eslint-plugin-svelte'
import { createProcessor } from '@humanspeak/svelte-scoped-props/eslint'
export default [
...svelte.configs['flat/recommended'],
{
files: ['**/*.svelte'],
processor: createProcessor({
cssHash: ({ css, filename, hash }) => `my-${hash(filename ?? css)}`
})
}
]import svelte from 'eslint-plugin-svelte'
import { createProcessor } from '@humanspeak/svelte-scoped-props/eslint'
export default [
...svelte.configs['flat/recommended'],
{
files: ['**/*.svelte'],
processor: createProcessor({
cssHash: ({ css, filename, hash }) => `my-${hash(filename ?? css)}`
})
}
]The processor accepts the same option shape as scopedProps(): cssHash, marker, normalizeFilename, and runtimeModule.
What gets transformed
Static scoped props are rewritten into normal props before linting.
<ChildCard scoped:class="parent-owned" /><ChildCard scoped:class="parent-owned" /><ChildCard class="parent-owned svelte-abc123" /><ChildCard class="parent-owned svelte-abc123" />Dynamic ClassValue expressions use the same runtime helper call as the build
preprocessor.
<ChildCard scoped:class={['parent-owned', { active }]} /><ChildCard scoped:class={['parent-owned', { active }]} />Prop aliases work the same way.
<FancyCard scoped:internalClass="inner-panel" /><FancyCard scoped:internalClass="inner-panel" />Parent-side object spreads still cannot express scoped intent. Scope before the prop is collected into an object, then forward the transformed prop normally.
Message locations
The processor remaps lint messages back to the source you authored. Diagnostics from
other ESLint rules should point at scoped:class or the original expression, not at
the generated class={__svelte_scoped_props_class(...)} output.
Autofixes are kept when their ranges map cleanly to authored source. Fixes that would edit generated helper code or marker snippets are dropped.
CSS selector checks
For svelte/valid-compile, the processor also adds the same marker snippet used by
the build preprocessor. That marker lets Svelte’s CSS analysis see the local class
name, so the selector is not reported as unused just because the class is handed to a
child component prop.
The marker does not render.