API Reference
@humanspeak/svelte-scoped-props exports a Svelte preprocessor, a low-level transform
helper for tests and tooling, and a tiny runtime helper for dynamic ClassValue props.
Scoped Props
import { scopedProps } from '@humanspeak/svelte-scoped-props'
scopedProps(options?: ScopedPropsOptions): PreprocessorGroupimport { scopedProps } from '@humanspeak/svelte-scoped-props'
scopedProps(options?: ScopedPropsOptions): PreprocessorGroupUse this in svelte.config.ts.
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
import { scopedProps } from '@humanspeak/svelte-scoped-props'
export default {
preprocess: [
vitePreprocess(),
scopedProps({
runtimeModule: '@humanspeak/svelte-scoped-props/runtime'
})
]
}import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
import { scopedProps } from '@humanspeak/svelte-scoped-props'
export default {
preprocess: [
vitePreprocess(),
scopedProps({
runtimeModule: '@humanspeak/svelte-scoped-props/runtime'
})
]
}Put scopedProps() after CSS preprocessors. It computes the same default Svelte CSS
hash from the final style content, so transformed class props and Svelte’s compiled
CSS selectors agree.
Transform Scoped Props
import { transformScopedProps } from '@humanspeak/svelte-scoped-props'
transformScopedProps(
source: string,
options?: ScopedPropsOptions & { filename?: string }
): TransformResultimport { transformScopedProps } from '@humanspeak/svelte-scoped-props'
transformScopedProps(
source: string,
options?: ScopedPropsOptions & { filename?: string }
): TransformResultUse this directly in unit tests, codemods, and small transform experiments.
const result = transformScopedProps(
`<Child scoped:class="parent-owned" /><style>.parent-owned{color:purple}</style>`,
{ filename: 'src/Parent.svelte' }
)
console.log(result.code)
console.log(result.scopedAttributeCount)
console.log(result.dynamicAttributeCount)
console.log(result.hash)const result = transformScopedProps(
`<Child scoped:class="parent-owned" /><style>.parent-owned{color:purple}</style>`,
{ filename: 'src/Parent.svelte' }
)
console.log(result.code)
console.log(result.scopedAttributeCount)
console.log(result.dynamicAttributeCount)
console.log(result.hash)TransformResult:
type TransformResult = {
code: string
scopedAttributeCount: number
dynamicAttributeCount: number
hash: string
}type TransformResult = {
code: string
scopedAttributeCount: number
dynamicAttributeCount: number
hash: string
}Options
type ScopedPropsOptions = {
cssHash?: CssHashGetter
marker?: false | 'snippet'
normalizeFilename?: false | ((filename: string) => string)
runtimeModule?: string
}type ScopedPropsOptions = {
cssHash?: CssHashGetter
marker?: false | 'snippet'
normalizeFilename?: false | ((filename: string) => string)
runtimeModule?: string
}CSS Hash
Provide this when your Svelte config uses a custom cssHash.
scopedProps({
cssHash: ({ css, filename, hash }) => `my-${hash(filename ?? css)}`
})scopedProps({
cssHash: ({ css, filename, hash }) => `my-${hash(filename ?? css)}`
})The function receives the same ingredients Svelte’s default hash uses: final CSS, optional filename, and the package’s mirrored Svelte hash helper.
Marker
Defaults to 'snippet'.
Svelte removes unused scoped CSS selectors unless it can see the class in the component markup. The snippet marker keeps those selectors alive without rendering anything.
scopedProps({ marker: false })scopedProps({ marker: false })Disable the marker for transform-only tests where you do not compile the transformed component with Svelte.
Normalize Filename
Defaults to repo-relative POSIX paths for files inside process.cwd(). That matches
the Vite and SvelteKit shape most users see.
scopedProps({ normalizeFilename: false })scopedProps({ normalizeFilename: false })Use false for direct svelte.compile experiments that intentionally pass absolute
filenames.
Runtime Module
Dynamic values import scopedClass from this module.
scopedProps({
runtimeModule: '@humanspeak/svelte-scoped-props/runtime'
})scopedProps({
runtimeModule: '@humanspeak/svelte-scoped-props/runtime'
})Set this explicitly when testing the published scoped package. Literal scoped props do not use the runtime helper.
Runtime
import { scopedClass, type ClassValue } from '@humanspeak/svelte-scoped-props/runtime'import { scopedClass, type ClassValue } from '@humanspeak/svelte-scoped-props/runtime'For child component props that are passed directly to a Svelte class attribute,
prefer Svelte’s own type:
import type { ClassValue } from 'svelte/elements'import type { ClassValue } from 'svelte/elements'The runtime export is useful when you call scopedClass directly.
type ClassDictionary = Record<string, unknown>
type ClassArray = ClassValue[]
type ClassValue =
| string
| number
| boolean
| null
| undefined
| ClassDictionary
| ClassArray
function scopedClass(value: ClassValue, hash: string): stringtype ClassDictionary = Record<string, unknown>
type ClassArray = ClassValue[]
type ClassValue =
| string
| number
| boolean
| null
| undefined
| ClassDictionary
| ClassArray
function scopedClass(value: ClassValue, hash: string): stringscopedClass normalizes strings, arrays, and object maps, then appends the scope hash.
Falsy values and booleans become an empty string.
Transform Output
Literal values become normal quoted props.
<Child scoped:class="parent-owned" /><Child scoped:class="parent-owned" /><Child class="parent-owned svelte-abc123" /><Child class="parent-owned svelte-abc123" />Expression values become runtime helper calls.
<Child scoped:class={['parent-owned', { active }]} /><Child scoped:class={['parent-owned', { active }]} /><script>
import { scopedClass as __svelte_scoped_props_class } from '@humanspeak/svelte-scoped-props/runtime'
</script>
<Child class={__svelte_scoped_props_class(['parent-owned', { active }], 'svelte-abc123')} /><script>
import { scopedClass as __svelte_scoped_props_class } from '@humanspeak/svelte-scoped-props/runtime'
</script>
<Child class={__svelte_scoped_props_class(['parent-owned', { active }], 'svelte-abc123')} />Prop aliases are mechanical.
<Child scoped:internalClass="inner-panel" /><Child scoped:internalClass="inner-panel" /><Child internalClass="inner-panel svelte-abc123" /><Child internalClass="inner-panel svelte-abc123" />Diagnostics
The transform throws early for syntax that would be ambiguous or impossible to make safe.
scoped:directives can only be used on component tags, not native elements.scoped:must include a prop name, such asscoped:class.- Modifiers are not supported.
- The scoped prop must have an explicit value.
scoped:<prop>cannot be combined with a normal<prop>on the same component.
Component Tags
The transform treats uppercase tags and dotted tags as components.
<Child scoped:class="parent-owned" />
<motion.div scoped:class="parent-owned" /><Child scoped:class="parent-owned" />
<motion.div scoped:class="parent-owned" />Native elements are intentionally rejected.
<div scoped:class="parent-owned" /><div scoped:class="parent-owned" />Use normal Svelte class behavior for native elements.