-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SSR-safe ID generation #7517
Comments
Yes please was just looking for this as forms might be used more than once on the same page. |
To solve this you could use |
@kevmodrome this doesn't scale well. Form components usually either don't take props or take complex objects, whose identity depends on their location in memory, and is subject to change. Also this would mean that two components with the same props would get the same ID. The success of React's |
In theory, yes, but a bunch of edge cases even break with React's TL;DR It's complicated to implement: It is theoretically impossible, we either have to skip some IDs or guess some IDs. |
Is there a reproducible example of how this could currently create problems in SvelteKit and if not @illright could you create one? |
Considering the |
This has nothing to do with form submission, but with using the separated-tag approach for It’s even more required for various And, frankly, I need this in Svelte proper for ARIA as I’m not using SvelteKit. |
I look through the examples given on the linked issue and all of them require consistency of ids within the context of the browser, none of them require consistency across the server-client boundary. If the server renders this <label for="1234">
<input id="1234"> and Svelte hydrates this to <label for="5678">
<input id="5678"> Everything still works as expected because the ids are consistent within their context. This is something that can be achieved with any of the already mentioned methods, just generate the id one place and pass it to both components (it is exactly the same as you would do in React). React introduced So far I have not seen any example where it is of vital importance that both ids are the same on client and server. |
It's not clear to me whether a hydration mismatch is a big issue in Svelte (I'm coming from a React world)? Mismatch is pretty much guaranteed when doing SSR, because:
The solution for this is to put a function for getting the count in a store that is initialised during render of the top-most
import { setContext, getContext } from 'svelte'
import { readable, type Readable, get } from 'svelte/store'
import context from './context'
type GetCount = () => number
type UIDStore = Readable<GetCount>
export function initUIDStore() {
let count = 0
const uidStore: UIDStore = readable(() => ++count)
setContext(context.uid, uidStore)
}
export function initUIDGenerator() {
const uidStore = getContext<UIDStore>(context.uid)
let getCount: GetCount
if (!uidStore) {
console.warn(
`getContext(${context.uid}) returned undefined. You need to call initUIDStore() in the root page component.`,
)
getCount = () => 1
} else {
getCount = get(uidStore)
}
return (prefix: string) => `${prefix}_${getCount()}`
}
<script>
import { initUIDStore } from '$lib/uid-store'
initUIDStore()
</script>
<script lang="ts">
import { initUIDGenerator } from '$lib/uid-store'
const uid = initUIDGenerator()
const tabId = uid('tab')
const panelId = uid('tabpanel')
</script> 💡 The above will work flawlessly, unless you start introducing deliberate mismatches like rendering something on the client but not on the server. Happy to hear feedback on this, whether this makes sense at all. Even if hydration mismatch isn't a performance issue in Svelte, having a counter on the server that doesn't reset between visits is still an indirect way of exposing your website's visitor count. |
@gersomvg It's nice for a random color generator. That could be solved by generating the color in a in |
Describe the problem
There are many cases where an application needs to connect DOM nodes with IDs:
for
)aria-labelledby
)Given that these IDs do not need any semantic meaning, and given that humans are pretty terrible at coming up with app-level unique IDs, this is a job wonderfully suited for a framework. Taking SSR into consideration, we cannot simply use counter-based solutions or randomly generated IDs.
Describe the proposed solution
React 18 shipped its new
useId()
hook which allows utilizing all the component tree knowledge of the framework and using that to generate IDs that are stable across SSR and unique across component instances.I would like to see a similar thing in Svelte. It could look like this (
createInstanceId
):Alternatives considered
Variable
The ID could come from a compiler-populated instance-specific variable:
Another name could be
$$instanceId
, to reflect its instance-dependency. This isn't perfect though, as it still doesn't communicate clearly enough that this isn't a component-specific variable, but rather an instance-specific one. A function call communicates that much better, similarly tocreateEventDispatcher()
Userland solution
I have used naive ID-generation solutions in the past (namely,
lukeed/uid
) and they didn't seem to cause any visible issues, but it's very likely that I simply haven't run into a use-case where a mismatch between the client and the server would be a problem.Other userland solutions involve contexts, which is not great for developer experience, and might be problematic for asynchronous rendering (see reactwg/react-18#111 (reply in thread))
Importance
would make my life easier
Relevant mentions
#6932
The text was updated successfully, but these errors were encountered: