-
Hello, I'm new to the world of reactivity. Before, I was using native JavaScript to build my applications, but as you know, this approach is becoming outdated in 2024. I'm currently stuck with data exchange. I want to create a form where the inputs are child components. Each input will validate itself, and the form will track the validation status of all inputs. Based on the validation status, the form will enable or disable the submit button. Here's what I've managed to do so far: +page.svelte <script lang="ts">
import Form from "$lib/components/base/Form.svelte";
import Input from "$lib/components/base/Input.svelte";
</script>
<Form>
<Input
title="Enter e-mail"
subtext="Description"
name="email"
type="email"
placeholder="Placeholder"
currentValue="[email protected]"
></Input>
<Input
title="Enter password"
subtext="Description"
name="password"
type="password"
placeholder="Placeholder"
></Input>
</Form> Form.svelte <script lang="ts">
const { children } = $props();
// areInputsValid?
</script>
<form>
{@render children()}
<!-- <button disabled={areInputsValid?}>Send</button> -->
</form> Input.svelte <script lang="ts">
const {
title = null,
subtext = null,
name,
currentValue = null,
type,
placeholder,
} = $props();
let value = $state(currentValue);
let isValid = $state(false);
function validate() {
isValid = value.length > 0;
}
</script>
{#if title}
<p>{title}</p>
{/if}
{#if subtext}
<p>{subtext}</p>
{/if}
<input {type} {name} {placeholder} bind:value oninput={validate} /> |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 4 replies
-
You could make an array or object and bind each item to a let {validated = $bindable()} = $props();
function validate() {
validated = isInputValid
} Then in the parent component you could see if all the validated values are |
Beta Was this translation helpful? Give feedback.
-
An approach that works through larger hierarchies would be a context. The form sets an object as context that inputs can register themselves in, the form then can query the state of all registered inputs. To make this reactive, the object in the context needs to be stateful and the access to the validation state must also be reactive (i.e. a closure over a local But I am not really a fan of disabled submit buttons, they have some questionable accessibility characteristics. I prefer using native HTML validation which automatically prevents form submissions and shows accessible validation errors. Context example: // Form.svelte
const inputs = setContext('form-inputs', new SvelteSet()); <button disabled={[...inputs].some(i => i.isValid == false)}>
Send
</button> // Input.svelte
let isValid = $state(false);
const inputs = getContext('form-inputs');
$effect(() => {
const input = { get isValid() { return isValid; } };
inputs.add(input);
return () => inputs.delete(input);
}); |
Beta Was this translation helpful? Give feedback.
An approach that works through larger hierarchies would be a context.
The form sets an object as context that inputs can register themselves in, the form then can query the state of all registered inputs. To make this reactive, the object in the context needs to be stateful and the access to the validation state must also be reactive (i.e. a closure over a local
$state
variable; either a function or a getter).But I am not really a fan of disabled submit buttons, they have some questionable accessibility characteristics. I prefer using native HTML validation which automatically prevents form submissions and shows accessible validation errors.
Context example: