Function-based slot override (() => class) in app.config.ts merges instead of replacing when defined in multiple extended Nuxt layers
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 6.9k
- Forks
- 1.1k
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 57
Description
Environment
- Nuxt 4.5.2
- NuxtUi 4.11.0
Is this bug related to Nuxt or Vue?
Nuxt
Package
v4.x
Version
v4.11.0
Reproduction
layers/base/app.config.ts:
export default defineAppConfig({
ui: {
drawer: {
slots: {
header: () => 'foo-class'
}
}
}
})
app/app.config.ts (App layer extending base):
export default defineAppConfig({
ui: {
drawer: {
slots: {
header: () => 'bar-class'
}
}
}
})
nuxt.config.ts:
export default defineNuxtConfig({
extends: ['./layers/base']
})
Description
Per the Customize components docs, setting a slot to a function in app.config.ts should replace the component's default classes for that slot instead of merging them:
By default, these classes are merged onto the component's defaults. You can also set a slot to a function to
replace them instead.
This works correctly in a single-layer project. However, when using Nuxt layers (extends) and the same slot is overridden with a function in more than one layer's app.config.ts, the replace behavior breaks — the final result appears to merge/concatenate the classes instead of the last-applied function fully replacing the previous one.
Additional context
Expected: header slot classes should be exactly bar-class without default Nuxt classes. (App layer's function should fully replace, receiving Base layer's resolved defaults as its argument if needed, per docs).
Actual: The resulting classes on header appear to include both bar-class and default classes from Nuxt.
Additional observation: If the function override exists in only one of the two layers (either Base or App, doesn't matter which), it correctly replaces the component's built-in defaults as documented. The issue only manifests when two layers both provide a function for the same slot.
Suspected cause: The layer app.config.ts merging (likely via defu) doesn't have special handling for merging two function values for the same key — unlike the intentional function-detection/replace logic that exists for a single config source vs. component defaults. This may result in unexpected composition behavior when two function overrides for the same slot are merged across layers.
Logs
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the issue with layers/base/app.config.ts, app/app.config.ts, and nuxt.config.ts using the two function-based header overrides. Start by tracing Nuxt layer app.config merging, including the suspected defu behavior, and the slot function handling described in the Customize components docs. Done means the app-layer function produces exactly bar-class without the default classes, while still receiving resolved defaults if needed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- nuxtjs, typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100