monsto
monsto

Reputation: 1250

Using svelte/sveltekit, how do I manually trigger the HTML validation on a specific field?

enter image description here

I am doing a multi-tab form, a single <form> where the fields on the screen come from an array and are shown only by their corresponding tab.

On "Save" (<form on:submit>) I can take the user back to the tab with the incomplete data, but I need to pop the HTML 'field required' tooltip on the necessary fields.

Using svelte/sveltekit, how do I manually trigger the HTML validation on a specific form field? I know there's HTML methods for it, but I see how to get it done.

Upvotes: 0

Views: 1406

Answers (1)

brunnerh
brunnerh

Reputation: 185290

In general reportValidity() can be used to show a validation message. E.g.

<script>
    let input;
</script>

<input bind:this={input} type=email value="not an email" />

<button on:click={() => input.reportValidity()}>
    Validate
</button>

REPL

Buf for the tabs issue the main issues are:

  1. The submit event will not fire until the form is valid, so you need to hook into the submit button instead.
  2. You somehow need to identify the tab and switch to it, this depends entirely on the tab implementation.
  3. The input has to actually always exist, so the tab contents must not be inserted using logic like {#if tab == selectedTab}...{/if}. Instead inactive tab contents should only be hidden.

If the switch does happen without any delays, you may not have to reportValidity because the switch happens before the validation logic of the form is triggered. Otherwise you may need to wait for a tick after the tab switch.

Example using Carbon components for the tab implementation:

<script>
    import { Content, TextInput, Button, Tabs, Tab, TabContent } from 'carbon-components-svelte';
    
    let selected;

    function onSaveClick(e) {
        const firstInvalid = e.target.closest('form')
            .querySelector(':invalid');
        
        if (firstInvalid == null)
            return;
        
        // Somehow identify tab and switch to it
        const tabContainer = firstInvalid.closest('.bx--tab-content');
        selected = tabContainer.dataset.index;
    }
</script>

<Content>
    <form on:submit|preventDefault={() => alert('Submitted')}>
        <Tabs bind:selected>
            <Tab label="Tab 1" />
            <Tab label="Tab 2" />
            <svelte:fragment slot="content">
                <TabContent data-index={0}>
                    <TextInput type="email" labelText="E-Mail" value="[email protected]"/>
                </TabContent>
                <TabContent data-index={1}>
                    <TextInput type="email" labelText="E-Mail" value="not an e-mail"/>
                </TabContent>
            </svelte:fragment>
        </Tabs>

        <Button type="submit" on:click={onSaveClick}>
            Save
        </Button>
    </form>
</Content>

REPL

Upvotes: 1

Related Questions