Attributes set to undefined are not removed during hydration (spread and direct bindings)
#16184
undefined are not removed during hydration (spread and direct bindings)Development PR
Attributes set server-side but undefined on the client should be removed during hydration. This ensures expected cleanup behavior and resolves a mismatch between SSR and client-side rendering.
Fixes #16184
Issue
Describe the bug
When using SvelteKit with SSR, attributes that are set to an empty string on the server and undefined on the client (either via spread or direct bindings) are not removed during hydration. This results in mismatched DOM expectations, where data-* attributes persist even though their value becomes undefined on the client.
This behavior affects both spread attributes ({...map}) and direct bindings (data-test={value}), making it difficult to conditionally render and remove attributes correctly across server/client boundaries.
Reproduction
Repo: https://github.com/floriskn/sveltekit-attribute-mismatch
Steps to reproduce:
- Clone the repo and run the dev server
- Inspect the rendered
<p>element in the browser - Observe that
data-testanddata-directare present in the HTML, even though both are set toundefinedon the client
Example code from the repo:
<script lang="ts">
import { browser } from "$app/environment";
let attributeMap = {
"data-test": browser ? undefined : ""
};
let directValue = browser ? undefined : "";
</script>
<p {...attributeMap} data-direct={directValue}>
Inspect this element
</p>
Logs
System Info
System:
OS: Windows 10 10.0.19045
CPU: (16) x64 Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz
Memory: 12.30 GB / 31.92 GB
Binaries:
Node: 20.11.1 - C:\Program Files\nodejs\node.EXE
npm: 10.2.4 - C:\Program Files\nodejs\npm.CMD
pnpm: 9.15.0 - ~\AppData\Local\pnpm\pnpm.EXE
Browsers:
Edge: Chromium (127.0.2651.105)
Internet Explorer: 11.0.19041.5794
npmPackages:
@sveltejs/adapter-auto: ^6.0.0 => 6.0.1
@sveltejs/kit: ^2.16.0 => 2.21.5
@sveltejs/vite-plugin-svelte: ^5.0.0 => 5.1.0
svelte: ^5.0.0 => 5.34.3
vite: ^6.2.6 => 6.3.5
Severity
serious, but I can work around it
Additional Information
No response
Info
Moving this to the Svelte repo as it's not actually a Kit bug
Yeah, I initially thought it was a Kit bug, but after looking into the code I realized it wasn’t. Thanks for moving it over
Pro tip: You can prefix GitHub URLs of issues, PRs or discussions with svcl.dev/ to view them on this page! Also try it on a GitHub release ;)