Browser-specific behavior complicates hydration mismatch issue.
The issue involves a hydration mismatch in SvelteKit caused by Safari Mobile automatically converting numbers into phone number links. A workaround exists using a meta tag, but a fix within SvelteKit may require deeper investigation into browser behavior and potential upstream changes.
All,
I've been pounding my head for the last 10 hours on why my SSR hydration fails but only on the iphone/ipad and no where else!
TLDR; Apple has this cool new feature that will automatically detect numbers that they THINK are phone numbers into an <a href="tel:XYZ>{number}. This will fail hydration and give a mismatch.
Proof: Normal browser output
Safari Iphone Output
To reproduct this just make a new sveltekit applicaiton and return a really long number, must be over 7 digits
+page.ts
export const load = async () => {
return { number: '15555555555' };
// return { number: 'pass15555555555' }; // this works because it wont be treated as a phone number
};
+page.svelte
<script lang="ts">
let { data } = $props();
</script>
<svelte:boundary onerror={(error) => console.log('error', JSON.stringify(error))}>
<p>The number is {data.number}</p>
{#snippet failed(error)}
<p>Error: {JSON.stringify(error)}</p>
{/snippet}
</svelte:boundary>
What happens is that the server will first render as part of SSR and send down a nice <p> tag and then safari will take that, add the <a> tag around what it thinks is a telephone number and then sveltekit will throw a hydration mismatch, effectively bringing your app to an error screen.
A workaround for now is to add this meta tag
<meta name="format-detection" content="telephone=no">
https://blog.identitydesign.us/safari-phone-number-blue-fix/
You can witness the issue because for a brief second you can see the server rendered DOM with a blue underline before it crashes.
It would be great if sveltekit could work around this somehow. I'm not sure but you are all smart. At the very least maybe ad
Claim this issue to let others know you're working on it. You'll earn 10 points when you complete it!