svelte-form-easy
v2.0.2
Published
[![npm version](https://badge.fury.io/js/svelte-form-easy.svg)](https://badge.fury.io/js/svelte-form-easy)
Downloads
3
Maintainers
Readme
Svelte Form Easy
Svelte realtime form validator with yup validation
Install
Install svelte-form-easy
package
npm i svelte-form-easy
Install yup
package
npm i yup
Use
Step 1 Create interface
// src/interfaces/ISignupForm.ts
interface ISignupForm {
username: string;
email: string;
password: string;
confirmPassword: string;
termsAndConditions: boolean;
}
Step 2 Create schema validation
// src/schemas/signupSchema.ts
import * as Yup from 'yup';
import type { AnySchema } from 'yup';
import type { ISignupForm } from './../interfaces/ISignupForm';
export const signupSchema = Yup.object<
Record<keyof ISignupForm, AnySchema>
>().shape({
username: Yup.string()
.min(3, 'Username must be at least 3 characters')
.required('Username is required')
.matches(/^\S*$/, 'Whitespace is not allowed'),
email: Yup.string().email('Email is invalid').required('Email is required'),
password: Yup.string()
.min(8, 'Password must be at least 8 characters')
.required('Password is required')
.matches(/^\S*$/, 'Whitespace is not allowed'),
confirmPassword: Yup.string()
.required('Confirm password is required')
.test('passwords-match', 'Password does not match', function (value) {
return this.parent.password === value;
}),
termsAndConditions: Yup.boolean().oneOf(
[true],
'Terms and conditions is required'
),
});
Step 3 Use in components (App.svelte)
VERSION 2.0.0 OR LATEST
<script lang="ts">
import * as Yup from 'yup';
import type { AnySchema } from 'yup';
import type { ISignupForm } from './interfaces/ISignupForm';
import { signupSchema } from './schemas/signupSchema';
import type { FormSubmit } from 'svelte-form-easy';// Import this
import { Form, Field, ErrorMessage, Button } from 'svelte-form-easy'; // Import this
// Create initial values
const initialValues: ISignupForm = {
username: '',
email: '',
password: '',
confirmPassword: '',
termsAndConditions: false,
};
const handleSubmit = ({
valid,
form,
reset,
forceTouched,
}: FormSubmit<ISignupForm>) => {
if (valid.isValid) {
console.log(form);
reset();
} else {
forceTouched();
}
};
</script>
<main>
<h1>Svelte Form Easy</h1>
<Form
class="form-signup"
{handleSubmit}
{initialValues}
validationSchema={signupSchema}
>
<div class="input-field">
<label for="username">Username</label>
<!-- reference name--->
<Field
type="text"
name="username"
id="username"
autocomplete="off"
placeholder="Enter Username"
/>
<ErrorMessage name="username" />
</div>
<div class="input-field">
<label for="email">Email</label>
<!-- reference name--->
<Field
type="text"
name="email"
id="email"
autocomplete="off"
placeholder="Enter Email"
/>
<ErrorMessage name="email" />
</div>
<div class="input-field">
<label for="password">Password</label>
<!-- reference name--->
<Field
type="password"
name="password"
id="password"
autocomplete="off"
placeholder="Enter Password"
/>
<ErrorMessage name="password" />
</div>
<div class="input-field">
<label for="confirmPassword">Confirm Password</label>
<!-- reference name--->
<Field
type="password"
name="confirmPassword"
id="confirmPassword"
placeholder="Confirm Password"
autocomplete="off"
/>
<ErrorMessage name="confirmPassword" />
</div>
<div class="input-terms">
<!-- reference name--->
<Field
type="checkbox"
name="termsAndConditions"
id="termsAndConditions"
className="terms"
/>
<label for="termsAndConditions">
<p>
By creating an account you agree to our <a
href="/terms-and-conditions">Terms & Conditions</a
>.
</p>
</label>
<ErrorMessage name="termsAndConditions" className="terms-invalid-feedback" />
</div>
<div class="input-field">
<Button type="submit">Signup</Button>
</div>
</Form>
</main>
<style type="scss">
/*Use as same version 1.0.0*/
</style>
VERSION 1.0.0 OR LATEST
<script lang="ts">
import * as Yup from 'yup';
import type { AnySchema } from 'yup';
import type { ISignupForm } from './interfaces/ISignupForm';
import { signupSchema } from './schemas/signupSchema';
import { useForm } from 'svelte-form-easy'; // Import this
// Create initial values
const initialValues: ISignupForm = {
username: '',
email: '',
password: '',
confirmPassword: '',
termsAndConditions: false,
};
const {
form,
touched,
useValidForm,
useValidTouch,
handleChange,
handleTouch,
handleReset,
handleForceTouched,
} = useForm<ISignupForm>({
initialValues: initialValues,
validationSchema: signupSchema,
});
$: valid = useValidForm($form);
$: dirty = useValidTouch($touched);
const handleSubmit = (e) => {
e.preventDefault();
if (valid.isValid) {
console.log($form);
handleReset();
} else {
handleForceTouched();
}
};
</script>
<main>
<h1>Svelte Form Easy</h1>
<form on:submit={handleSubmit}>
<div class="input-field">
<label for="username">Username</label>
<input
type="text"
name="username" <!-- reference name--->
id="username"
on:focus={handleTouch}
on:change={handleChange}
bind:value={$form.username}
class={valid.errors?.username && $touched.username
? 'is-invalid'
: $touched.username
? 'is-valid'
: ''}
autocomplete="off"
placeholder="Enter Username"
/>
{#if valid.errors?.username && $touched.username}
<span class="invalid-feedback">{valid.errors?.username}</span>
{/if}
</div>
<div class="input-field">
<label for="email">Email</label>
<input
type="text"
name="email" <!-- reference name--->
id="email"
on:focus={handleTouch}
on:change={handleChange}
bind:value={$form.email}
class={valid.errors?.email && $touched.email
? 'is-invalid'
: $touched.email
? 'is-valid'
: ''}
autocomplete="off"
placeholder="Enter Email"
/>
{#if valid.errors?.email && $touched.email}
<span class="invalid-feedback">{valid.errors?.email}</span>
{/if}
</div>
<div class="input-field">
<label for="password">Password</label>
<input
type="password"
name="password" <!-- reference name--->
id="password"
on:focus={handleTouch}
on:change={handleChange}
bind:value={$form.password}
class={valid.errors?.password && $touched.password
? 'is-invalid'
: $touched.password
? 'is-valid'
: ''}
autocomplete="off"
placeholder="Enter Password"
/>
{#if valid.errors?.password && $touched.password}
<span class="invalid-feedback">{valid.errors?.password}</span>
{/if}
</div>
<div class="input-field">
<label for="confirmPassword">Confirm Password</label>
<input
type="password"
id="confirmPassword"
name="confirmPassword" <!-- reference name--->
on:focus={handleTouch}
on:change={handleChange}
bind:value={$form.confirmPassword}
class={valid.errors?.confirmPassword && $touched.confirmPassword
? 'is-invalid'
: $touched.confirmPassword
? 'is-valid'
: ''}
placeholder="Confirm Password"
autocomplete="off"
/>
{#if valid.errors?.confirmPassword && $touched.confirmPassword}
<span class="invalid-feedback">{valid.errors?.confirmPassword}</span>
{/if}
</div>
<div class="input-terms">
<input
type="checkbox"
name="termsAndConditions" <!-- reference name--->
id="termsAndConditions"
on:focus={handleTouch}
on:change={handleChange}
bind:checked={$form.termsAndConditions}
class="terms"
/>
<label for="termsAndConditions">
<p>
By creating an account you agree to our <a
href="/terms-and-conditions">Terms & Conditions</a
>.
</p>
</label>
{#if valid.errors?.termsAndConditions && $touched.termsAndConditions}
<span class="terms-invalid-feedback"
>{valid.errors?.termsAndConditions}</span
>
{/if}
</div>
<div class="input-field">
<button type="submit" disabled={!valid.isValid && dirty}>Signup</button>
</div>
</form>
</main>
<style type="scss">
$color: #ff3e00;
main {
text-align: center;
padding: 1em;
margin: 0 auto;
}
h1 {
color: $color;
text-transform: uppercase;
font-size: 2.5em;
font-weight: 100;
}
form {
margin: 0 auto;
max-width: 380px;
width: 100%;
padding: 1rem 0;
}
.input-field {
width: 100%;
text-align: left;
position: relative;
}
.input-field label {
color: #555;
}
input {
&:not(.terms) {
min-width: 250px;
}
width: 100%;
outline: none;
border: none;
line-height: 1;
padding: 12px 20px;
margin: 14px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
&:focus {
outline: none;
border: 1px solid #aaa;
}
&.is-valid,
&:focus.is-valid {
border: 2px solid #4caf50;
}
&.is-invalid,
&:focus.is-invalid {
border: 2px solid #dc3545;
}
}
.invalid-feedback,
.terms-invalid-feedback {
position: absolute;
bottom: -2px;
left: 0;
padding-left: 5px;
font-size: 0.875em;
color: #dc3545;
}
.terms-invalid-feedback {
bottom: -10px;
}
.input-terms {
display: flex;
flex-direction: row;
margin: 8px 0;
position: relative;
}
input.terms {
width: 20px;
}
.input-terms label {
width: 250px;
}
button {
width: 100%;
background-color: #4caf50;
color: white;
font-size: 18px;
padding: 14px 20px;
margin: 12px 0;
border: none;
border-radius: 4px;
cursor: pointer;
&:disabled {
cursor: unset;
background-color: #c8c8c8;
&:hover {
cursor: unset;
background-color: #c8c8c8;
}
}
&:hover {
background-color: #45a049;
}
}
</style>