Basic example
TW elements Validation allows you to show the result of you validation in a
simple and elegant way. You can use just the styling that
Validation
component provides or you can add rules and messages
for each input. Validation
component is fully customizable.
If you want to control the validation yourself and only use the styling, add
data-twe-validated="true"
to the form and
data-twe-validation-state="valid/invalid"
to the element if
it's value is valid.
To initialize the component use
data-twe-validation-init
attribute and add
data-twe-validate="input"
to the wrapper of element you want
the styles to be applied to.
Inside the data-twe-validate
attribute you can provide
-
input
- for TW Elements input components basic
- for native inputscheckbox
- for checkboxes and switchesradio
- radio component
<form id="form-1" data-twe-validation-init>
<div
class="relative mb-3"
id="input-1"
data-twe-input-wrapper-init
data-twe-validate="input">
<input
type="text"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:autofill:shadow-autofill dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0"
id="exampleFormControlInput1"
placeholder="Example label" />
<label
for="exampleFormControlInput1"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[1.6] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[0.9rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Example label
</label>
</div>
<button
type="button"
id="validation-1"
class="inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong">
Validate
</button>
</form>
import {
Validation,
Input,
initTWE,
} from "tw-elements";
initTWE({ Validation, Input });
const validation1 = document.getElementById("validation-1");
const form1 = document.getElementById("form-1");
const input1 = document.getElementById("input-1");
let valid = true;
validation1.addEventListener("click", (e) => {
e.preventDefault();
input1.setAttribute(
"data-twe-validation-state",
valid ? "valid" : "invalid"
);
form1.setAttribute("data-twe-validated", true);
valid = !valid;
});
const validation1 = document.getElementById("validation-1");
const form1 = document.getElementById("form-1");
const input1 = document.getElementById("input-1");
let valid = true;
validation1.addEventListener("click", (e) => {
e.preventDefault();
input1.setAttribute(
"data-twe-validation-state",
valid ? "valid" : "invalid"
);
form1.setAttribute("data-twe-validated", true);
valid = !valid;
});
Advanced Example
Add data-twe-validation-ruleset
attribute with a
|
separated list of validation rules to make the component
check them for you. Add data-twe-submit-btn-ref
to the submit
button so that you don't have to listen on the button clicks yourself.
Click the Validate
button to validate the form again.
<form data-twe-validation-init>
<div
class="relative mb-3"
data-twe-input-wrapper-init
data-twe-validate="input"
data-twe-validation-ruleset="isRequired">
<input
type="text"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:autofill:shadow-autofill dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0"
id="exampleFormAdvancedInput1"
placeholder="Example label" />
<label
for="exampleFormAdvancedInput1"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[1.6] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[0.9rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Example label
</label>
</div>
<button
type="button"
class="inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
data-twe-submit-btn-ref>
Validate
</button>
</form>
// Initialization for ES Users
import {
Validation,
Input,
initTWE,
} from "tw-elements";
initTWE({ Validation, Input });
Existing validation rules
In TW elements validation we have already provided few rules that can be
used to check the value of inputs. You can extend the list with use of
customRules
and customErrorMessages
options.
Example on how to do this can be found in section
Custom Validation
isRequired
- checks if any value was setisEmail
- checks for valid email address-
isLongerThan
- checks if string is longer than (n) length -
isShorterThan
- checks if string is shorter than (n) length isChecked
- checks if value was checked-
isPhone
- checks if the value has length equal to 9 isNumber
- checks if value is type numberisString
- checks if value is type string-
isBoolean
- checks if value is type boolean -
isDate
- checks if value is a date in format DD/MM/YYYY -
is12hFormat
- checks if value is time in 12h format -
is24hFormat
- checks if value is time in 24h format
Supported components
The Validation
component supports:
Select
Used rules: isRequired
<form data-twe-validation-init>
<div data-twe-validate="input" data-twe-validation-ruleset="isRequired">
<select data-twe-select-init data-twe-select-clear-button="true">
<option value="" hidden selected></option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
<option value="4">Four</option>
<option value="5">Five</option>
<option value="6">Six</option>
<option value="7">Seven</option>
<option value="8">Eight</option>
</select>
<label data-twe-select-label-ref>Example label</label>
</div>
<button
type="button"
class="mt-2 inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
data-twe-submit-btn-ref>
Validate
</button>
</form>
// Initialization for ES Users
import {
Validation,
Select,
initTWE,
} from "tw-elements";
initTWE({ Validation, Select });
Datepicker
Used rules: isRequired, isDate
<form data-twe-validation-init>
<div
class="relative mb-3"
data-twe-datepicker-init
data-twe-input-wrapper-init
data-twe-validate="input"
data-twe-validation-ruleset="isRequired|isDate">
<input
type="text"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:autofill:shadow-autofill dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0"
placeholder="Select a date" />
<label
for="floatingInput"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[1.6] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[0.9rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Select a date</label
>
</div>
<button
type="button"
class="mt-2 inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
data-twe-submit-btn-ref>
Validate
</button>
</form>
// Initialization for ES Users
import {
Validation,
Datepicker,
Input,
initTWE,
} from "tw-elements";
initTWE({ Validation, Datepicker, Input });
Timepicker
Used rules: isRequired, is12hFormat
<form data-twe-validation-init>
<div
class="relative mb-3"
data-twe-timepicker-init
data-twe-input-wrapper-init
data-twe-validate="input"
data-twe-validation-ruleset="isRequired|is12hFormat">
<input
type="text"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:autofill:shadow-autofill dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0"
id="form1" />
<label
for="form1"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[1.6] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[0.9rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Select a time</label
>
</div>
<button
type="button"
class="mt-2 inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
data-twe-submit-btn-ref>
Validate
</button>
</form>
// Initialization for ES Users
import {
Validation,
Timepicker,
Input,
initTWE,
} from "tw-elements";
initTWE({ Validation, Timepicker, Input });
Input Group
With default input. Used rules: isRequired
<form data-twe-validation-init>
<div class="relative flex flex-nowrap items-start">
<span
class="flex items-center whitespace-nowrap rounded-s border border-e-0 border-solid border-neutral-200 px-3 py-[0.25rem] text-center text-base font-normal leading-[1.6] text-surface dark:border-white/10 dark:text-white"
id="addon-wrapping"
>@</span
>
<div
class="relative inline-block w-full"
data-twe-validate="basic"
data-twe-validation-ruleset="isRequired">
<input
type="text"
class="relative m-0 block w-full flex-auto rounded-e border border-solid border-neutral-200 bg-transparent bg-clip-padding px-3 py-[0.25rem] text-base font-normal leading-[1.6] text-surface outline-none transition duration-200 ease-in-out placeholder:text-neutral-500 focus:z-[3] focus:border-primary focus:shadow-inset focus:outline-none motion-reduce:transition-none dark:border-white/10 dark:text-white dark:placeholder:text-neutral-200 dark:autofill:shadow-autofill dark:focus:border-primary"
placeholder="Username"
aria-label="Username"
aria-describedby="addon-wrapping" />
</div>
</div>
<button
type="button"
class="mt-2 inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
data-twe-submit-btn-ref>
Validate
</button>
</form>
// Initialization for ES Users
import {
Validation,
initTWE,
} from "tw-elements";
initTWE({ Validation });
With TE Input. Used rules: isRequired
<form data-twe-validation-init>
<div
class="relative mb-4 flex items-stretch"
data-twe-input-wrapper-init
data-twe-input-group-ref
data-twe-validate="input"
data-twe-validation-ruleset="isRequired">
<span
class="flex items-center whitespace-nowrap border-e border-solid border-secondary-500 px-3 py-[0.25rem] text-center text-base font-normal leading-[1.6] text-surface dark:border-neutral-400 dark:text-white"
id="basic-addon1"
data-twe-input-group-text-ref
>@</span
>
<input
type="text"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:autofill:shadow-autofill dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0"
placeholder="Username"
aria-label="Username"
id="exampleFormControlInput"
aria-describedby="basic-addon1" />
<label
for="exampleFormControlInput"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[1.6] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[0.9rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Example label
</label>
</div>
<button
type="button"
class="mt-2 inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
data-twe-submit-btn-ref>
Validate
</button>
</form>
// Initialization for ES Users
import {
Validation,
Input,
initTWE,
} from "tw-elements";
initTWE({ Validation, Input });
Textarea
Used rules: isRequired
<form data-twe-validation-init>
<div
class="relative mb-4 flex items-stretch"
data-twe-input-wrapper-init
data-twe-validate="input"
data-twe-validation-ruleset="isRequired">
<textarea
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0"
id="exampleFormControlTextarea1"
rows="3"
placeholder="Your message"></textarea>
<label
for="exampleFormControlTextarea1"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[1.6] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[0.9rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Example textarea</label
>
</div>
<button
type="button"
class="mt-2 inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
data-twe-submit-btn-ref>
Validate
</button>
</form>
// Initialization for ES Users
import {
Validation,
Input,
initTWE,
} from "tw-elements";
initTWE({ Validation, Input });
Checkbox
Used rules: isChecked
<form data-twe-validation-init>
<div
class="relative block min-h-[1.5rem] ps-[1.5rem]"
data-twe-validate="checkbox"
data-twe-validation-ruleset="isChecked">
<input
class="relative float-left -ms-[1.5rem] me-[6px] mt-[0.15rem] h-[1.125rem] w-[1.125rem] appearance-none rounded-[0.25rem] border-[0.125rem] border-solid border-secondary-500 outline-none before:pointer-events-none before:absolute before:h-[0.875rem] before:w-[0.875rem] before:scale-0 before:rounded-full before:bg-transparent before:opacity-0 before:shadow-checkbox before:shadow-transparent before:content-[''] checked:border-primary checked:bg-primary checked:before:opacity-[0.16] checked:after:absolute checked:after:-mt-px checked:after:ms-[0.25rem] checked:after:block checked:after:h-[0.8125rem] checked:after:w-[0.375rem] checked:after:rotate-45 checked:after:border-[0.125rem] checked:after:border-l-0 checked:after:border-t-0 checked:after:border-solid checked:after:border-white checked:after:bg-transparent checked:after:content-[''] hover:cursor-pointer hover:before:opacity-[0.04] hover:before:shadow-black/60 focus:shadow-none focus:transition-[border-color_0.2s] focus:before:scale-100 focus:before:opacity-[0.12] focus:before:shadow-black/60 focus:before:transition-[box-shadow_0.2s,transform_0.2s] focus:after:absolute focus:after:z-[1] focus:after:block focus:after:h-[0.875rem] focus:after:w-[0.875rem] focus:after:rounded-[0.125rem] focus:after:content-[''] checked:focus:before:scale-100 checked:focus:before:shadow-checkbox checked:focus:before:transition-[box-shadow_0.2s,transform_0.2s] checked:focus:after:-mt-px checked:focus:after:ms-[0.25rem] checked:focus:after:h-[0.8125rem] checked:focus:after:w-[0.375rem] checked:focus:after:rotate-45 checked:focus:after:rounded-none checked:focus:after:border-[0.125rem] checked:focus:after:border-l-0 checked:focus:after:border-t-0 checked:focus:after:border-solid checked:focus:after:border-white checked:focus:after:bg-transparent rtl:float-right dark:border-neutral-400 dark:checked:border-primary dark:checked:bg-primary"
type="checkbox"
value=""
id="checkboxChecked"
checked />
<label
class="inline-block ps-[0.15rem] hover:cursor-pointer"
for="checkboxChecked">
Checked checkbox
</label>
</div>
<button
type="button"
class="mt-2 inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
data-twe-submit-btn-ref>
Validate
</button>
</form>
// Initialization for ES Users
import {
Validation,
initTWE,
} from "tw-elements";
initTWE({ Validation });
Switch
Used rules: isChecked
<form data-twe-validation-init>
<div
class="relative block min-h-[1.5rem]"
data-twe-validate="checkbox"
data-twe-validation-ruleset="isChecked">
<input
class="me-2 mt-[0.3rem] h-3.5 w-8 appearance-none rounded-[0.4375rem] bg-black/25 before:pointer-events-none before:absolute before:h-3.5 before:w-3.5 before:rounded-full before:bg-transparent before:content-[''] after:absolute after:z-[2] after:-mt-[0.1875rem] after:h-5 after:w-5 after:rounded-full after:border-none after:bg-white after:shadow-switch-2 after:transition-[background-color_0.2s,transform_0.2s] after:content-[''] checked:bg-primary checked:after:absolute checked:after:z-[2] checked:after:-mt-[3px] checked:after:ms-[1.0625rem] checked:after:h-5 checked:after:w-5 checked:after:rounded-full checked:after:border-none checked:after:bg-primary checked:after:shadow-switch-1 checked:after:transition-[background-color_0.2s,transform_0.2s] checked:after:content-[''] hover:cursor-pointer focus:outline-none focus:before:scale-100 focus:before:opacity-[0.12] focus:before:shadow-switch-3 focus:before:shadow-black/60 focus:before:transition-[box-shadow_0.2s,transform_0.2s] focus:after:absolute focus:after:z-[1] focus:after:block focus:after:h-5 focus:after:w-5 focus:after:rounded-full focus:after:content-[''] checked:focus:border-primary checked:focus:bg-primary checked:focus:before:ms-[1.0625rem] checked:focus:before:scale-100 checked:focus:before:shadow-switch-3 checked:focus:before:transition-[box-shadow_0.2s,transform_0.2s] dark:bg-white/25 dark:after:bg-surface-dark dark:checked:bg-primary dark:checked:after:bg-primary"
type="checkbox"
role="switch"
id="flexSwitchCheckDefault" />
<label
class="inline-block ps-[0.15rem] hover:cursor-pointer"
for="flexSwitchCheckDefault"
>Default switch checkbox input</label
>
</div>
<button
type="button"
class="mt-2 inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
data-twe-submit-btn-ref>
Validate
</button>
</form>
// Initialization for ES Users
import {
Validation,
initTWE,
} from "tw-elements";
initTWE({ Validation });
Radio
Used rules: isChecked
<form data-twe-validation-init>
<div
class="relative block min-h-[1.5rem] ps-[1.5rem]"
data-twe-validate="radio"
data-twe-validation-ruleset="isChecked">
<input
class="relative float-left -ms-[1.5rem] me-1 mt-0.5 h-5 w-5 appearance-none rounded-full border-2 border-solid border-secondary-500 before:pointer-events-none before:absolute before:h-4 before:w-4 before:scale-0 before:rounded-full before:bg-transparent before:opacity-0 before:shadow-checkbox before:shadow-transparent before:content-[''] after:absolute after:z-[1] after:block after:h-4 after:w-4 after:rounded-full after:content-[''] checked:border-primary checked:before:opacity-[0.16] checked:after:absolute checked:after:left-1/2 checked:after:top-1/2 checked:after:h-[0.625rem] checked:after:w-[0.625rem] checked:after:rounded-full checked:after:border-primary checked:after:bg-primary checked:after:content-[''] checked:after:[transform:translate(-50%,-50%)] hover:cursor-pointer hover:before:opacity-[0.04] hover:before:shadow-black/60 focus:shadow-none focus:outline-none focus:ring-0 focus:before:scale-100 focus:before:opacity-[0.12] focus:before:shadow-black/60 focus:before:transition-[box-shadow_0.2s,transform_0.2s] checked:focus:border-primary checked:focus:before:scale-100 checked:focus:before:shadow-checkbox checked:focus:before:transition-[box-shadow_0.2s,transform_0.2s] rtl:float-right dark:border-neutral-400 dark:checked:border-primary"
type="radio"
name="flexRadioDefault"
id="radioDefault01" />
<label
class="mt-px inline-block ps-[0.15rem] hover:cursor-pointer"
for="radioDefault01">
Default radio
</label>
</div>
<button
type="button"
class="mt-2 inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
data-twe-submit-btn-ref>
Validate
</button>
</form>
// Initialization for ES Users
import {
Validation,
initTWE,
} from "tw-elements";
initTWE({ Validation });
Active validation
Add data-twe-active-validation="true"
to make the validation
listen to the input
changes.
<form
data-twe-validation-init
data-twe-active-validation="true"
autocomplete="off">
<div
class="relative mb-3"
data-twe-input-wrapper-init
data-twe-validate="input"
data-twe-validation-ruleset="isRequired|isNumber|isLongerThan(2)|isShorterThan(6)">
<input
type="text"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:autofill:shadow-autofill dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0"
id="exampleActive1"
placeholder="Example label" />
<label
for="exampleActive1"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[1.6] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[0.9rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Example label
</label>
</div>
<button
type="button"
class="inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
data-twe-submit-btn-ref>
Validate
</button>
</form>
// Initialization for ES Users
import {
Validation,
Input,
initTWE,
} from "tw-elements";
initTWE({ Validation, Input });
Custom validation
You can add custom rules to the validation. Simply add a new method to the
customRules
option and add customErrorMessages
for
that method. You can also add a callback to the validation so that the
Validation
component will call it after the validation is done.
Check the inspect tools to see how it works.
<form id="form-0" data-twe-active-validation="true">
<div
class="relative mb-3"
data-twe-input-wrapper-init
data-twe-validate="input"
data-twe-validation-ruleset="isRequired|isNumber|isLongerThan(2)">
<input
type="text"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:autofill:shadow-autofill dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0"
id="exampleInput1"
placeholder="Example label" />
<label
for="exampleInput1"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[1.6] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[0.9rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Example label
</label>
</div>
<div
class="relative mb-3"
data-twe-input-wrapper-init
data-twe-validate="input"
data-twe-validation-ruleset="isRequired|isEmail|contains(test)">
<input
type="text"
name="email"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:autofill:shadow-autofill dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0"
id="exampleInput2"
placeholder="Example label" />
<label
for="exampleInput2"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[1.6] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[0.9rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Example label
</label>
</div>
<div
class="relative mb-3"
data-twe-datepicker-init
data-twe-input-wrapper-init
data-twe-validate="input"
data-twe-validation-ruleset="isRequired|isDate">
<input
type="text"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:autofill:shadow-autofill dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0"
placeholder="Select a date" />
<label
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[1.6] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[0.9rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Select a date</label
>
</div>
<div
class="relative mb-3"
data-twe-timepicker-init
data-twe-input-wrapper-init
data-twe-validate="input"
data-twe-validation-ruleset="isRequired|is12hFormat">
<input
type="text"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:autofill:shadow-autofill dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0"
id="exampleInput3" />
<label
for="exampleInput3"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[1.6] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[0.9rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Select a time</label
>
</div>
<button
type="button"
class="inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
data-twe-submit-btn-ref>
Validate
</button>
<button
class="inline-block rounded px-2 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-danger hover:text-danger-600 focus:text-danger-600 focus:outline-none focus:ring-0 active:text-danger-700"
id="dispose">
Dispose validation
</button>
</form>
import {
Validation,
Input,
Datepicker,
Timepicker,
initTWE,
} from "tw-elements";
initTWE({ Input, Datepicker, Timepicker });
const fullValidationDisposeBtn = document.getElementById("dispose");
const fullValidationForm = document.getElementById("form-0");
const fullValidation = new Validation(fullValidationForm, {
customErrorMessages: {
contains: "The field must contain the '{contains}' word",
},
customRules: {
contains: (value, message, string) => {
return value.includes(string)
? true
: message.replace("{contains}", string);
},
},
submitCallback: (e, valid) => {
console.log("Do something ...", "Validation passed: ", valid);
},
});
fullValidationDisposeBtn.addEventListener("click", (e) => {
e.preventDefault();
fullValidation.dispose();
});
fullValidationForm.addEventListener("invalid.twe.validation", (e) => {
console.log("Something went wrong!");
});
fullValidationForm.addEventListener("valid.twe.validation", (e) => {
console.log("All good!");
});
const fullValidationDisposeBtn = document.getElementById("dispose");
const fullValidationForm = document.getElementById("form-0");
const fullValidation = new twe.Validation(fullValidationForm, {
customErrorMessages: {
contains: "The field must contain the '{contains}' word",
},
customRules: {
contains: (value, message, string) => {
return value.includes(string)
? true
: message.replace("{contains}", string);
},
},
submitCallback: (e, valid) => {
console.log("Do something ...", "Validation passed: ", valid);
},
});
fullValidationDisposeBtn.addEventListener("click", (e) => {
e.preventDefault();
fullValidation.dispose();
});
fullValidationForm.addEventListener("invalid.twe.validation", (e) => {
console.log("Something went wrong!");
});
fullValidationForm.addEventListener("valid.twe.validation", (e) => {
console.log("All good!");
});
Validation with tooltips
Use emitted events to show tooltips on validation results.
<form id="tooltips" class="me-10" data-twe-active-validation="true">
<div
class="relative mb-3"
data-twe-input-wrapper-init
data-twe-validate="input"
data-twe-validation-ruleset="isRequired|isLongerThan(4)">
<input
type="text"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0 dark:autofill:shadow-autofill"
name="name" />
<label
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[1.6] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[0.9rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Full name
</label>
<span
class="absolute -end-8 top-1/2 -translate-y-1/2 cursor-pointer text-neutral-500 dark:text-neutral-200 [&>svg]:h-5 [&>svg]:w-5"
id="fullNameInfo">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z" />
</svg>
</span>
</div>
<div
class="relative mb-3"
data-twe-input-wrapper-init
data-twe-validate="input"
data-twe-validation-ruleset="isRequired|isEmail">
<input
type="text"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0 dark:autofill:shadow-autofill"
name="email" />
<label
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[1.6] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[0.9rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Email address
</label>
<span
class="absolute -end-8 top-1/2 -translate-y-1/2 cursor-pointer text-neutral-500 dark:text-neutral-200 [&>svg]:h-5 [&>svg]:w-5"
id="emailInfo">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z" />
</svg>
</span>
</div>
<div
class="relative mb-4 flex items-stretch"
data-twe-input-wrapper-init
data-twe-validate="input"
data-twe-validation-ruleset="isRequired|isLongerThan(10)">
<textarea
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0"
rows="3"
name="issue"></textarea>
<label
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[1.6] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[0.9rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Describe your issue</label
>
<span
class="absolute -end-8 top-1/2 -translate-y-1/2 cursor-pointer text-neutral-500 dark:text-neutral-200 [&>svg]:h-5 [&>svg]:w-5"
id="issueInfo">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z" />
</svg>
</span>
</div>
<button
type="button"
class="mt-2 inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
data-twe-submit-btn-ref>
Validate
</button>
</form>
import {
Validation,
Input,
Tooltip,
initTWE,
} from "tw-elements";
initTWE({ Input });
const tooltipsForm = document.getElementById("tooltips");
const tooltipsInfo = [
{
element: document.getElementById("fullNameInfo"),
name: "name",
message: {
isRequired: "This value is required",
isLongerThan: "Must be longer than 4 characters",
},
},
{
element: document.getElementById("emailInfo"),
name: "email",
message: {
isRequired: "This value is required",
isEmail: "Must be a valid email address",
},
},
{
element: document.getElementById("issueInfo"),
name: "issue",
message: {
isRequired: "This value is required",
isLongerThan: "Must be longer than 10 characters",
},
},
];
const generateMessage = (result, message) =>
`<p class="${result ? 'text-success' : 'text-danger'}">${message}</p>`;
tooltipsInfo.forEach((tooltip) => {
const title = Object.entries(tooltip.message)
.map(([key, value]) => generateMessage(false, value))
.join("");
tooltip.instance = new Tooltip(tooltip.element, {
html: true,
template: `
<div>
<div class="bg-white text-xs p-4 ms-4 rounded border dark:bg-body-dark dark:border-black/40" data-twe-tooltip-inner-ref></div>
</div>
`,
placement: "right",
title,
});
});
const tooltipsValidation = new Validation(tooltipsForm);
tooltipsForm.addEventListener("valueChanged.twe.validation", (e) => {
const element = tooltipsInfo.find(
(tooltip) => tooltip.name === e.value.name
);
element.instance.dispose();
const title = Object.entries(element.message)
.map(([key, value]) => {
const result = e.value.validation.find(
(res) => key === res.name
).result;
return generateMessage(result, value);
})
.join("");
const borderColor =
e.value.result === "valid" ? "border-success" : "border-danger";
element.instance = new Tooltip(element.element, {
html: true,
template: `
<div>
<div class="bg-white text-xs p-4 ms-4 rounded border dark:bg-body-dark dark:border-black/40" data-twe-tooltip-inner-ref></div>
</div>
`,
placement: "right",
title: title,
});
});
const tooltipsForm = document.getElementById("tooltips");
const tooltipsInfo = [
{
element: document.getElementById("fullNameInfo"),
name: "name",
message: {
isRequired: "This value is required",
isLongerThan: "Must be longer than 4 characters",
},
},
{
element: document.getElementById("emailInfo"),
name: "email",
message: {
isRequired: "This value is required",
isEmail: "Must be a valid email address",
},
},
{
element: document.getElementById("issueInfo"),
name: "issue",
message: {
isRequired: "This value is required",
isLongerThan: "Must be longer than 10 characters",
},
},
];
const generateMessage = (result, message) =>
`<p class="${result ? 'text-success' : 'text-danger'}">${message}</p>`;
tooltipsInfo.forEach((tooltip) => {
const title = Object.entries(tooltip.message)
.map(([key, value]) => generateMessage(false, value))
.join("");
tooltip.instance = new twe.Tooltip(tooltip.element, {
html: true,
template: `
<div>
<div class="bg-white text-xs p-4 ms-4 rounded border dark:bg-body-dark dark:border-black/40" data-twe-tooltip-inner-ref></div>
</div>
`,
placement: "right",
title,
});
});
const tooltipsValidation = new twe.Validation(tooltipsForm);
tooltipsForm.addEventListener("valueChanged.twe.validation", (e) => {
const element = tooltipsInfo.find(
(tooltip) => tooltip.name === e.value.name
);
element.instance.dispose();
const title = Object.entries(element.message)
.map(([key, value]) => {
const result = e.value.validation.find(
(res) => key === res.name
).result;
return generateMessage(result, value);
})
.join("");
const borderColor =
e.value.result === "valid" ? "border-success" : "border-danger";
element.instance = new twe.Tooltip(element.element, {
html: true,
template: `
<div>
<div class="bg-white text-xs p-4 ms-4 rounded border dark:bg-body-dark dark:border-black/40" data-twe-tooltip-inner-ref></div>
</div>
`,
placement: "right",
title: title,
});
});
Show results with Alert
Use the data provided by events to show the validation results with an Alert.
<form id="form-results" data-twe-active-validation="true">
<div
class="relative mb-3"
data-twe-input-wrapper-init
data-twe-validate="input"
data-twe-validation-ruleset="isRequired|isLongerThan(2)">
<input
type="text"
name="name"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:autofill:shadow-autofill dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0"
id="exampleAlertInput1"
placeholder="Example label" />
<label
for="exampleAlertInput1"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[1.6] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[0.9rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Full name
</label>
</div>
<div
class="relative mb-3"
data-twe-input-wrapper-init
data-twe-validate="input"
data-twe-validation-ruleset="isRequired|isEmail">
<input
type="text"
name="email"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[1.6] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:autofill:shadow-autofill dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0"
id="exampleAlertInput2"
placeholder="Example label" />
<label
for="exampleAlertInput2"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[1.6] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[0.9rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Email address
</label>
</div>
<button
type="button"
class="inline-block rounded bg-primary px-6 pb-2 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
data-twe-submit-btn-ref>
Validate
</button>
</form>
<div
id="result-container"
class="fixed right-4 top-4 z-[100] mb-3 hidden w-1/4 items-center rounded-lg bg-primary-100 px-6 py-4 text-base text-primary-800 data-[twe-alert-show]:inline-flex"
role="alert"
data-twe-alert-init
data-twe-autohide="true"
data-twe-delay="4000">
Result
</div>
import {
Validation,
Input,
Alert,
initTWE,
} from "tw-elements";
initTWE({ Input, Alert });
const resultContainer = document.getElementById("result-container");
const alertInstance = Alert.getInstance(resultContainer);
const resultsForm = document.getElementById("form-results");
const resultValidation = new Validation(resultsForm);
resultsForm.addEventListener("valid.twe.validation", (e) => {
const results = [];
resultsForm.querySelectorAll("input").forEach((input) => {
results.push({ [input.name]: input.value });
});
resultContainer.innerHTML = `
<div>
<h3 class="mb-3">Validation passed! Here is the result:</h3>
<div>${JSON.stringify(results, null, 2)}</div>
</div>
`; alertInstance.show(); });
const resultContainer = document.getElementById("result-container");
const alertInstance = twe.Alert.getInstance(resultContainer);
const resultsForm = document.getElementById("form-results");
const resultValidation = new twe.Validation(resultsForm);
resultsForm.addEventListener("valid.twe.validation", (e) => {
const results = [];
resultsForm.querySelectorAll("input").forEach((input) => {
results.push({ [input.name]: input.value });
});
resultContainer.innerHTML = `
<div>
<h3 class="mb-3">Validation passed! Here is the result:</h3>
<div>${JSON.stringify(results, null, 2)}</div>
</div>
`; alertInstance.show(); });
Custom feedback messages
You can set the feedback messages to have the content you want. Simply add
data-twe-invalid-feedback
and
data-twe-valid-feedback
attributes with your custom message.
<div>
<!-- Left column container with background-->
<div
class="flex h-full flex-wrap items-center justify-center lg:justify-between">
<div
class="shrink-1 mb-12 grow-0 basis-auto md:mb-0 md:w-9/12 md:shrink-0 lg:w-6/12 xl:w-6/12">
<img
src="https://tecdn.b-cdn.net/img/Photos/new-templates/bootstrap-login-form/draw2.webp"
class="w-full"
alt="Sample image" />
</div>
<!-- Right column container -->
<div class="mb-12 md:mb-0 md:w-8/12 lg:w-5/12 xl:w-5/12">
<form data-twe-validation-init data-twe-active-validation="true">
<!--Sign in section-->
<div
class="flex flex-row items-center justify-center lg:justify-start">
<p class="mb-0 me-4 text-lg">Sign in with</p>
<!-- Facebook -->
<button
type="button"
data-twe-ripple-init
data-twe-ripple-color="light"
class="mx-1 inline-block h-9 w-9 rounded-full bg-primary fill-white p-2 uppercase leading-normal shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong">
<!-- Facebook -->
<span class="[&>svg]:mx-auto [&>svg]:h-3.5 [&>svg]:w-3.5">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 320 512">
<!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc. -->
<path
d="M80 299.3V512H196V299.3h86.5l18-97.8H196V166.9c0-51.7 20.3-71.5 72.7-71.5c16.3 0 29.4 .4 37 1.2V7.9C291.4 4 256.4 0 236.2 0C129.3 0 80 50.5 80 159.4v42.1H14v97.8H80z" />
</svg>
</span>
</button>
<!-- X -->
<button
type="button"
data-twe-ripple-init
data-twe-ripple-color="light"
class=" mx-1 inline-block h-9 w-9 rounded-full bg-primary fill-white p-2 uppercase leading-normal shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong">
<!-- X -->
<span class="[&>svg]:mx-auto [&>svg]:h-3.5 [&>svg]:w-3.5">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512">
<!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc. -->
<path
d="M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z" />
</svg>
</span>
</button>
<!-- Linkedin -->
<button
type="button"
data-twe-ripple-init
data-twe-ripple-color="light"
class=" mx-1 inline-block h-9 w-9 rounded-full bg-primary fill-white p-2 uppercase leading-normal shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong">
<!-- Linkedin -->
<span class="[&>svg]:mx-auto [&>svg]:h-3.5 [&>svg]:w-3.5">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512">
<!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc. -->
<path
d="M100.3 448H7.4V148.9h92.9zM53.8 108.1C24.1 108.1 0 83.5 0 53.8a53.8 53.8 0 0 1 107.6 0c0 29.7-24.1 54.3-53.8 54.3zM447.9 448h-92.7V302.4c0-34.7-.7-79.2-48.3-79.2-48.3 0-55.7 37.7-55.7 76.7V448h-92.8V148.9h89.1v40.8h1.3c12.4-23.5 42.7-48.3 87.9-48.3 94 0 111.3 61.9 111.3 142.3V448z" />
</svg>
</span>
</button>
</div>
<!-- Separator between social media sign in and email/password sign in -->
<div
class="my-4 flex items-center before:mt-0.5 before:flex-1 before:border-t before:border-neutral-300 after:mt-0.5 after:flex-1 after:border-t after:border-neutral-300 dark:before:border-neutral-500 dark:after:border-neutral-500">
<p
class="mx-4 mb-0 text-center font-semibold dark:text-neutral-200">
Or
</p>
</div>
<!-- Email input -->
<div
class="relative mb-6"
data-twe-input-wrapper-init
data-twe-validate="input"
data-twe-validation-ruleset="isRequired|isEmail"
data-twe-invalid-feedback="The email address is invalid"
data-twe-valid-feedback="The email address is valid">
<input
type="text"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[2.15] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:autofill:shadow-autofill dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0"
id="exampleFormControlLogin1"
placeholder="Email address" />
<label
for="exampleFormControlLogin1"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[2.15] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[1.15rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[1.15rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Email address
</label>
</div>
<!-- Password input -->
<div
class="relative mb-6"
data-twe-input-wrapper-init
data-twe-validate="input"
data-twe-validation-ruleset="isRequired|isLongerThan(6)"
data-twe-invalid-feedback="Please provide a password longer than 6 characters"
data-twe-valid-feedback="Your password is longer than 6 characters!">
<input
type="password"
class="peer block min-h-[auto] w-full rounded border-0 bg-transparent px-3 py-[0.32rem] leading-[2.15] outline-none transition-all duration-200 ease-linear focus:placeholder:opacity-100 peer-focus:text-primary data-[twe-input-state-active]:placeholder:opacity-100 motion-reduce:transition-none dark:text-white dark:placeholder:text-neutral-300 dark:autofill:shadow-autofill dark:peer-focus:text-primary [&:not([data-twe-input-placeholder-active])]:placeholder:opacity-0"
id="exampleFormControlLogin2"
placeholder="Password" />
<label
for="exampleFormControlLogin2"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[90%] origin-[0_0] truncate pt-[0.37rem] leading-[2.15] text-neutral-500 transition-all duration-200 ease-out peer-focus:-translate-y-[1.15rem] peer-focus:scale-[0.8] peer-focus:text-primary peer-data-[twe-input-state-active]:-translate-y-[1.15rem] peer-data-[twe-input-state-active]:scale-[0.8] motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Password
</label>
</div>
<div class="mb-6 flex items-center justify-between">
<!-- Remember me checkbox -->
<div
class="relative mb-[0.125rem] mt-3 block min-h-[1.5rem] ps-[1.5rem]"
data-twe-validate="checkbox"
data-twe-validation-ruleset="isChecked">
<input
class="relative float-left -ms-[1.5rem] me-[6px] mt-[0.15rem] h-[1.125rem] w-[1.125rem] appearance-none rounded-[0.25rem] border-[0.125rem] border-solid border-secondary-500 outline-none before:pointer-events-none before:absolute before:h-[0.875rem] before:w-[0.875rem] before:scale-0 before:rounded-full before:bg-transparent before:opacity-0 before:shadow-checkbox before:shadow-transparent before:content-[''] checked:border-primary checked:bg-primary checked:before:opacity-[0.16] checked:after:absolute checked:after:-mt-px checked:after:ms-[0.25rem] checked:after:block checked:after:h-[0.8125rem] checked:after:w-[0.375rem] checked:after:rotate-45 checked:after:border-[0.125rem] checked:after:border-l-0 checked:after:border-t-0 checked:after:border-solid checked:after:border-white checked:after:bg-transparent checked:after:content-[''] hover:cursor-pointer hover:before:opacity-[0.04] hover:before:shadow-black/60 focus:shadow-none focus:transition-[border-color_0.2s] focus:before:scale-100 focus:before:opacity-[0.12] focus:before:shadow-black/60 focus:before:transition-[box-shadow_0.2s,transform_0.2s] focus:after:absolute focus:after:z-[1] focus:after:block focus:after:h-[0.875rem] focus:after:w-[0.875rem] focus:after:rounded-[0.125rem] focus:after:content-[''] checked:focus:before:scale-100 checked:focus:before:shadow-checkbox checked:focus:before:transition-[box-shadow_0.2s,transform_0.2s] checked:focus:after:-mt-px checked:focus:after:ms-[0.25rem] checked:focus:after:h-[0.8125rem] checked:focus:after:w-[0.375rem] checked:focus:after:rotate-45 checked:focus:after:rounded-none checked:focus:after:border-[0.125rem] checked:focus:after:border-l-0 checked:focus:after:border-t-0 checked:focus:after:border-solid checked:focus:after:border-white checked:focus:after:bg-transparent rtl:float-right dark:border-neutral-400 dark:checked:border-primary dark:checked:bg-primary"
type="checkbox"
value=""
id="exampleFormControlLogin3" />
<label
class="inline-block ps-[0.15rem] hover:cursor-pointer"
for="exampleFormControlLogin3">
Remember me
</label>
</div>
<!--Forgot password link-->
<a class="mt-3" href="#!">Forgot password?</a>
</div>
<!-- Login button -->
<div class="text-center lg:text-left">
<button
type="button"
class="inline-block w-full rounded bg-primary px-7 pb-2 pt-3 text-sm font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
data-twe-ripple-init
data-twe-ripple-color="light"
data-twe-submit-btn-ref>
Login
</button>
<!-- Register link -->
<p class="mb-0 mt-2 pt-1 text-sm font-semibold">
Don't have an account?
<a
href="#!"
class="text-danger transition duration-150 ease-in-out hover:text-danger-600 focus:text-danger-600 active:text-danger-700"
>Register</a
>
</p>
</div>
</form>
</div>
</div>
</div>
// Initialization for ES Users
import {
Validation,
Input,
Ripple,
initTWE,
} from "tw-elements";
initTWE({ Validation, Input, Ripple });