Basic example
The filter
option is required in order for component to work
properly. The option accepts a function that is expected to return an array
of results or a Promise
that resolves to an array of results.
<div class="relative" data-twe-input-wrapper-init id="basic">
<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" />
<label
for="exampleFormControlInput1"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[80%] 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-focused]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-focused]:scale-[0.8] peer-data-[twe-input-state-active]:scale-[0.8] peer-data-[twe-input-focused]:text-primary motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Example label
</label>
</div>
import { Autocomplete, Input, initTWE } from "tw-elements";
initTWE({ Input });
const data = ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight'];
const dataFilter = (value) => {
return data.filter((item) => {
return item.toLowerCase().startsWith(value.toLowerCase());
});
};
const basicAutocomplete = document.querySelector('#basic');
new Autocomplete(basicAutocomplete, {
filter: dataFilter,
});
const data = ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight'];
const dataFilter = (value) => {
return data.filter((item) => {
return item.toLowerCase().startsWith(value.toLowerCase());
});
};
const basicAutocomplete = document.querySelector('#basic');
new twe.Autocomplete(basicAutocomplete, {
filter: dataFilter,
});
Display value
The displayValue
option allow to separate oryginal result value
from the value that will be displayed in the result list or input (after
selection). Its useful when the data returned by the
filter
function is an array of objects. You can specify which
parameter of the object should be displayed.
<div class="relative" data-twe-input-wrapper-init id="displayValue">
<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="exampleFormControlInput2" />
<label
for="exampleFormControlInput2"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[80%] 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-focused]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-focused]:scale-[0.8] peer-data-[twe-input-state-active]:scale-[0.8] peer-data-[twe-input-focused]:text-primary motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Example label
</label>
</div>
import { Autocomplete, Input, initTWE } from "tw-elements";
initTWE({ Input });
const customData = [
{ title: 'One', subtitle: 'Secondary text' },
{ title: 'Two', subtitle: 'Secondary text' },
{ title: 'Three', subtitle: 'Secondary text' },
{ title: 'Four', subtitle: 'Secondary text' },
{ title: 'Five', subtitle: 'Secondary text' },
{ title: 'Six', subtitle: 'Secondary text' },
];
const customFilter = (value) => {
return customData.filter((item) => {
return item.title.toLowerCase().startsWith(value.toLowerCase());
});
};
const displayValueAutocomplete = document.querySelector('#displayValue');
new Autocomplete(displayValueAutocomplete, {
filter: customFilter,
displayValue: (value) => value.title,
});
const customData = [
{ title: 'One', subtitle: 'Secondary text' },
{ title: 'Two', subtitle: 'Secondary text' },
{ title: 'Three', subtitle: 'Secondary text' },
{ title: 'Four', subtitle: 'Secondary text' },
{ title: 'Five', subtitle: 'Secondary text' },
{ title: 'Six', subtitle: 'Secondary text' },
];
const customFilter = (value) => {
return customData.filter((item) => {
return item.title.toLowerCase().startsWith(value.toLowerCase());
});
};
const displayValueAutocomplete = document.querySelector('#displayValue');
new twe.Autocomplete(displayValueAutocomplete, {
filter: customFilter,
displayValue: (value) => value.title,
});
Asynchronous search
The function passed to the filter
option can return a
Promise
that resolves to an array of results. By default the
component expects to receive data as an array of strings. If you want to
return an array of objects instead, you can use
displayValue
option to specify which parameter should be used
as a display value of the specific result.
<div class="relative" data-twe-input-wrapper-init id="async">
<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="exampleFormControlInput3" />
<label
for="exampleFormControlInput3"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[80%] 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-focused]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-focused]:scale-[0.8] peer-data-[twe-input-state-active]:scale-[0.8] peer-data-[twe-input-focused]:text-primary motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Example label
</label>
</div>
import { Autocomplete, Input, initTWE } from "tw-elements";
initTWE({ Input });
const asyncAutocomplete = document.querySelector('#async');
const asyncFilter = async (query) => {
const url = `https://swapi.py4e.com/api/people/?search=${encodeURI(query)}`;
const response = await fetch(url);
const data = await response.json();
return data.results;
};
new Autocomplete(asyncAutocomplete, {
filter: asyncFilter,
displayValue: (value) => value.name
});
const asyncAutocomplete = document.querySelector('#async');
const asyncFilter = async (query) => {
const url = `https://swapi.py4e.com/api/people/?search=${encodeURI(query)}`;
const response = await fetch(url);
const data = await response.json();
return data.results;
};
new twe.Autocomplete(asyncAutocomplete, {
filter: asyncFilter,
displayValue: (value) => value.name
});
Threshold
Use threshold
option to specify a minimum number of the
characters in the input field needed to perform a search operation.
<div class="relative" data-twe-input-wrapper-init id="threshold">
<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="exampleFormControlInput4"
placeholder="Type 2 characters to search" />
<label
for="exampleFormControlInput4"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[80%] 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-focused]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-focused]:scale-[0.8] peer-data-[twe-input-state-active]:scale-[0.8] peer-data-[twe-input-focused]:text-primary motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Example label
</label>
</div>
import { Autocomplete, Input, initTWE } from "tw-elements";
initTWE({ Input });
const data = ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight'];
const dataFilter = (value) => {
return data.filter((item) => {
return item.toLowerCase().startsWith(value.toLowerCase());
});
};
const thresholdAutocomplete = document.querySelector('#threshold');
new Autocomplete(thresholdAutocomplete, {
filter: dataFilter,
threshold: 2
});
const data = ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight'];
const dataFilter = (value) => {
return data.filter((item) => {
return item.toLowerCase().startsWith(value.toLowerCase());
});
};
const thresholdAutocomplete = document.querySelector('#threshold');
new twe.Autocomplete(thresholdAutocomplete, {
filter: dataFilter,
threshold: 2
});
Custom item template
The itemContent
option allow to display custom HTML in the
result list. You can use the listHeight
option to modify the
result list height when you want to display more content in the component
dropdown.
<div
class="relative"
data-twe-input-wrapper-init
id="customItem"
data-twe-list-height="295">
<input
type="text"
class="peer block min-h-[auto] dark:autofill:shadow-autofill 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="exampleFormControlInput5" />
<label
for="exampleFormControlInput5"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[80%] 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-focused]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-focused]:scale-[0.8] peer-data-[twe-input-focused]:text-primary 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>
import { Autocomplete, Input, initTWE } from "tw-elements";
initTWE({ Input });
const customData = [
{ title: 'One', subtitle: 'Secondary text' },
{ title: 'Two', subtitle: 'Secondary text' },
{ title: 'Three', subtitle: 'Secondary text' },
{ title: 'Four', subtitle: 'Secondary text' },
{ title: 'Five', subtitle: 'Secondary text' },
{ title: 'Six', subtitle: 'Secondary text' },
];
const customFilter = (value) => {
return customData.filter((item) => {
return item.title.toLowerCase().startsWith(value.toLowerCase());
});
};
const customItem = document.querySelector('#customItem');
new Autocomplete(customItem, {
filter: customFilter,
displayValue: (value) => value.title,
itemContent: (result) => {
return `
<div class="flex flex-col">
<div class="font-medium">${result.title}</div>
<div class="text-[0.9rem]">${result.subtitle}</div>
</div>
`;
},
});
const customData = [
{ title: 'One', subtitle: 'Secondary text' },
{ title: 'Two', subtitle: 'Secondary text' },
{ title: 'Three', subtitle: 'Secondary text' },
{ title: 'Four', subtitle: 'Secondary text' },
{ title: 'Five', subtitle: 'Secondary text' },
{ title: 'Six', subtitle: 'Secondary text' },
];
const customFilter = (value) => {
return customData.filter((item) => {
return item.title.toLowerCase().startsWith(value.toLowerCase());
});
};
const customItem = document.querySelector('#customItem');
new twe.Autocomplete(customItem, {
filter: customFilter,
displayValue: (value) => value.title,
itemContent: (result) => {
return `
<div class="flex flex-col">
<div class="font-medium">${result.title}</div>
<div class="text-[0.9rem]">${result.subtitle}</div>
</div>
`;
},
});
Custom content
A custom content container with a
data-twe-autocomplete-custom-content-ref
attribute will be
displayed at the end of the autocomplete dropdown. You can use it to display
a number of search results.
<div class="relative" data-twe-input-wrapper-init id="customContent">
<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="exampleFormControlInput6" />
<label
for="exampleFormControlInput6"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[80%] 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-focused]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-focused]:scale-[0.8] peer-data-[twe-input-focused]:text-primary 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>
import { Autocomplete, Input, initTWE } from "tw-elements";
initTWE({ Input });
const data = ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight'];
const dataFilter = (value) => {
return data.filter((item) => {
return item.toLowerCase().startsWith(value.toLowerCase());
});
};
const customContent = document.querySelector('#customContent');
new Autocomplete(customContent, {
filter: dataFilter,
customContent: `
<div data-twe-autocomplete-custom-content-ref class="px-4 py-1.5"></div>
`,
});
customContent.addEventListener("update.twe.autocomplete", (event) => {
const resultsLength = event.results.length;
setTimeout(() => {
const customContentContainer = document.querySelector(
"[data-twe-autocomplete-custom-content-ref]"
);
customContentContainer.innerHTML = `Search results: ${resultsLength}`;
}, 0);
});
const data = ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight'];
const dataFilter = (value) => {
return data.filter((item) => {
return item.toLowerCase().startsWith(value.toLowerCase());
});
};
const customContent = document.querySelector('#customContent');
new twe.Autocomplete(customContent, {
filter: dataFilter,
customContent: `
<div data-twe-autocomplete-custom-content-ref class="px-4 py-1.5"></div>
`,
});
customContent.addEventListener("update.twe.autocomplete", (event) => {
const resultsLength = event.results.length;
setTimeout(() => {
const customContentContainer = document.querySelector(
"[data-twe-autocomplete-custom-content-ref]"
);
customContentContainer.innerHTML = `Search results: ${resultsLength}`;
}, 0);
});
Validation
You can use the validation component together with autocomplete.
<form
data-twe-validation-init
data-twe-active-validation="true"
autocomplete="off">
<div
class="relative"
id="validation"
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="exampleFormControlInput7" />
<label
for="exampleFormControlInput7"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[80%] 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-focused]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-focused]:scale-[0.8] peer-data-[twe-input-state-active]:scale-[0.8] peer-data-[twe-input-focused]:text-primary motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Example label
</label>
</div>
<button
type="button"
class="mt-5 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>
Submit
</button>
</form>
import { Autocomplete, Input, Validation, initTWE } from "tw-elements";
initTWE({ Input, Validation })
const data = ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight'];
const dataFilter = (value) => {
return data.filter((item) => {
return item.toLowerCase().startsWith(value.toLowerCase());
});
};
const validationAutocomplete = document.querySelector('#validation');
new Autocomplete(validationAutocomplete, {
filter: dataFilter
});
const data = ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight'];
const dataFilter = (value) => {
return data.filter((item) => {
return item.toLowerCase().startsWith(value.toLowerCase());
});
};
const validationAutocomplete = document.querySelector('#validation');
new twe.Autocomplete(validationAutocomplete, {
filter: dataFilter
});
Auto select
Set autoSelect
option to true
to enable selecting
on Tab press.
<div class="relative" id="auto-select" data-twe-input-wrapper-init>
<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="exampleFormControlInput8" />
<label
for="exampleFormControlInput8"
class="pointer-events-none absolute left-3 top-0 mb-0 max-w-[80%] 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-focused]:-translate-y-[0.9rem] peer-data-[twe-input-state-active]:-translate-y-[0.9rem] peer-data-[twe-input-focused]:scale-[0.8] peer-data-[twe-input-state-active]:scale-[0.8] peer-data-[twe-input-focused]:text-primary motion-reduce:transition-none dark:text-neutral-400 dark:peer-focus:text-primary"
>Example label
</label>
</div>
import { Autocomplete, Input, initTWE } from "tw-elements";
initTWE({ Input });
const data = ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight'];
const dataFilter = (value) => {
return data.filter((item) => {
return item.toLowerCase().startsWith(value.toLowerCase());
});
};
const autoSelectAutocomplete = document.querySelector('#auto-select');
new Autocomplete(autoSelectAutocomplete, {
filter: dataFilter,
autoSelect: true
});
const data = ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight'];
const dataFilter = (value) => {
return data.filter((item) => {
return item.toLowerCase().startsWith(value.toLowerCase());
});
};
const autoSelectAutocomplete = document.querySelector('#auto-select');
new twe.Autocomplete(autoSelectAutocomplete, {
filter: dataFilter,
autoSelect: true
});