-
-
Notifications
You must be signed in to change notification settings - Fork 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
Create a restore-focus option for progressively-enhanced GET forms #7895
Comments
Use <form>
<input autofocus name="q" />
<button>click</button>
</form> If you want the input to only focus after a submission, you can use <script>
import { afterNavigate } from '$app/navigation';
/** @type {HTMLInputElement} */
let input;
afterNavigate(({ type }) => {
if (type === 'form') {
input.focus();
}
});
</script>
<form>
<input bind:this={input} name="q" />
<button>click</button>
</form> A |
@Rich-Harris thanks for replying! I know you can sort of hack this with an afterNavigate event. And I know restore-focus wouldn’t restore focus to the textbox if you clicked a submit button. But it does seem lacking that you can call goto from a keyDown handler, with restoreFocus, and keep your input focused, but if you replace that with a form, it’s no longer possible. Also, the afterNavigate handler that checks for type === “form” would be a bit fragile. You’d only want it to restore focus if you submitted via pressing enter, but NOT if you clicked a submit button. autofocus is a decent middleground, but that causes the input to always focus after the page loads, regardless of what was focused, or what caused the navigation. |
The purpose of the progressive enhancement is to emulate the browser native behaviour but without reloading the page. If you want to only focus the input after an enter but not a button click, you could do this: <script>
import { beforeNavigate, afterNavigate } from '$app/navigation';
/** @type {HTMLElement} */
let focused;
beforeNavigate(({ type }) => {
focused = document.activeElement;
});
afterNavigate(({ type }) => {
if (type === 'form') {
focused?.focus();
}
});
</script>
<form>
<input name="q" />
<button>click</button>
</form> There's also nothing preventing you from providing a custom |
(To be clear: not ruling out a declarative option. Just exploring whether or not it's truly necessary, and providing a workaround until we reach a decision on that.) |
@Rich-Harris thanks! - yeah, the primitives are there. I'm sure some subset of the approaches above could be used to make a nice helper to streamline this. This certainly isn't any kind of blocking need, but I am curious if you think this would be a useful addition to SvelteKit at some point. |
Our replies criss-crosed - you answered my point - thank you! |
Coming back to this, I've been making a lot of progressive-enhanced-form demos with For example, I find myself doing this pattern for a debounced search input. Because I'm submitting the form as they're typing, I need to keep focus and want to replace state to avoid pushing a bunch of partial searches into the history. <script lang="ts">
import { goto } from '$app/navigation';
let form: HTMLFormElement;
const debouncedSubmit = debounce(() => {
// not supported in all browsers
if (typeof HTMLFormElement.prototype.requestSubmit == 'function') {
form.requestSubmit();
}
}, 300);
export function submitReplaceState(e: SubmitEvent) {
e.preventDefault();
const form = e.target as HTMLFormElement;
const url = new URL(form.action);
// @ts-expect-error
const params = new URLSearchParams(new FormData(form));
url.search = params.toString();
goto(url, { replaceState: true, keepFocus: true, noScroll: true });
}
</script>
<form bind:this={form} on:submit|preventDefault={submitReplaceState}>
<label for="q">Query</label>
<input
id="q"
type="text"
name="q"
on:input={debouncedSubmit}
/>
</form> I think it would be cool to be able to teach something like this without having to introduce a custom submit handler. Otherwise SvelteKit's automatic I'm sure this has been considered, but what about introducing new data-sveltekit link attributes for both |
Things like this are why I voted against SvelteKit handling this as a |
@dummdidumm more basically, is there some sort of structural problem why a keepFocus option can't / shouldn't be added to a form? That option already exists in the |
I don't think having a dedicated <form data-sveltekit-replacestate data-sveltekit-keepfocus> and <form use:enhanceGet={{ replaceState: true, keepFocus: true }}> either way, it's some sort of boolean flag. And I think it makes sense to have parity between our declarative navigation API ( |
I'd love a
and used It would be nicer to be able to decorate the |
This would be really nice to have, as mentioned - especially for those inline-saving fields. And I believe that passing |
@dummdidumm thank you!!! |
Describe the problem
There's an amazing, brand new feature whereby GET forms can now be progressively enhanced, which means we can use them to navigate to new search results, with less code, that will even work without JavaScript. This is a huge win. Unfortunately there's still one shortcoming: there's no way to have focus restored after the navigation.
In other words, type into the textbox, hit enter, have the new results show up, but also have focus restore into the same textbox
Describe the proposed solution
I guess there's be a data-sveltekit-restore-focus attribute?
Alternatives considered
n/a
Importance
would make my life easier - I think this feature (progressively enhanced GET forms) is severely hampered without this.
Additional Information
No response
The text was updated successfully, but these errors were encountered: