Data input
Combobox
Choose one option from a searchable list: a native select with a selection field and a dropdown search.
| Class name | Type | Description |
|---|---|---|
comboboxplf:combobox | Component | Wraps the native select |
combobox-nativeplf:combobox-native | Part | The native select that keeps the value |
combobox-controlplf:combobox-control | Part | The field the script adds |
combobox-displayplf:combobox-display | Part | The read-only value input the script adds |
combobox-inputplf:combobox-input | Part | The search input the script adds |
combobox-searchplf:combobox-search | Part | The search row the script adds |
combobox-toggleplf:combobox-toggle | Part | The open button the script adds |
combobox-clearplf:combobox-clear | Part | The clear button the script adds |
combobox-indicatorplf:combobox-indicator | Part | An option's check the script adds |
combobox-iconplf:combobox-icon | Part | An icon the script adds or copies from the template |
combobox-chevronplf:combobox-chevron | Part | The open button's chevron the script adds |
combobox-clear-iconplf:combobox-clear-icon | Part | The clear button's icon the script adds |
combobox-search-iconplf:combobox-search-icon | Part | The search row's icon the script adds |
combobox-checkplf:combobox-check | Part | The check mark in an option's indicator |
combobox-popupplf:combobox-popup | Part | The dropdown the script adds |
combobox-listplf:combobox-list | Part | The option list the script adds |
combobox-groupplf:combobox-group | Part | An option group the script adds |
combobox-group-labelplf:combobox-group-label | Part | A group's title the script adds |
combobox-optionplf:combobox-option | Part | An option the script adds |
combobox-labelplf:combobox-label | Part | An option's label the script adds |
combobox-detailplf:combobox-detail | Part | An option's secondary text the script adds |
combobox-emptyplf:combobox-empty | Part | The no-results message the script adds |
combobox-statusplf:combobox-status | Part | The screen-reader status the script adds |
combobox-smplf:combobox-sm | Size | Small |
combobox-lgplf:combobox-lg | Size | Large |
Default
Label the native select and give its options unique values; multiple and a size above 1 are not supported, so use Multi Select for several values.
Open the dropdown to search. Arrow keys browse; Enter chooses; Escape cancels your search.
<div class="field">
<label class="field-label" for="combobox-framework">Framework</label>
<div class="combobox" data-plf-combobox data-plf-clearable>
<select class="combobox-native" id="combobox-framework" name="framework" aria-describedby="combobox-framework-help">
<option value>Select a framework…</option>
<option value="astro">Astro</option>
<option value="next">Next.js</option>
<option value="nuxt">Nuxt</option>
<option value="remix" disabled>Remix (unavailable)</option>
<option value="svelte">SvelteKit</option>
</select>
<template data-plf-combobox-icon><span class="icon icon-search"></span></template>
</div>
<p class="field-help" id="combobox-framework-help">Open the dropdown to search. Arrow keys browse; Enter chooses; Escape cancels your search.</p>
</div><div class="plf:field">
<label class="plf:field-label" for="combobox-framework">Framework</label>
<div class="plf:combobox" data-plf-combobox data-plf-clearable>
<select class="plf:combobox-native" id="combobox-framework" name="framework" aria-describedby="combobox-framework-help">
<option value>Select a framework…</option>
<option value="astro">Astro</option>
<option value="next">Next.js</option>
<option value="nuxt">Nuxt</option>
<option value="remix" disabled>Remix (unavailable)</option>
<option value="svelte">SvelteKit</option>
</select>
<template data-plf-combobox-icon><span class="plf:icon plf:icon-search"></span></template>
</div>
<p class="plf:field-help" id="combobox-framework-help">Open the dropdown to search. Arrow keys browse; Enter chooses; Escape cancels your search.</p>
</div>import { Combobox, Field, Icon } from '@pelatform/react';
export function Example() {
return (
<Field label="Framework" help="Open the dropdown to search. Arrow keys browse; Enter chooses; Escape cancels your search.">
<Combobox name="framework" clearable icon={<Icon name="search" />}>
<option value="">Select a framework…</option>
<option value="astro">Astro</option>
<option value="next">Next.js</option>
<option value="nuxt">Nuxt</option>
<option value="remix" disabled>Remix (unavailable)</option>
<option value="svelte">SvelteKit</option>
</Combobox>
</Field>
);
}import { Combobox, Field, Icon } from '@pelatform/react/prefixed';
export function Example() {
return (
<Field label="Framework" help="Open the dropdown to search. Arrow keys browse; Enter chooses; Escape cancels your search.">
<Combobox name="framework" clearable icon={<Icon name="search" />}>
<option value="">Select a framework…</option>
<option value="astro">Astro</option>
<option value="next">Next.js</option>
<option value="nuxt">Nuxt</option>
<option value="remix" disabled>Remix (unavailable)</option>
<option value="svelte">SvelteKit</option>
</Combobox>
</Field>
);
}Selection is marked independently from the keyboard-active option.
<div class="field">
<label class="field-label" for="combobox-project">Selected project</label>
<div class="combobox" data-plf-combobox>
<select class="combobox-native" id="combobox-project">
<option value="docs">Documentation</option>
<option value="website" selected>Website</option>
<option value="long">Customer support and international onboarding workspace</option>
</select>
</div>
<p class="field-help">Selection is marked independently from the keyboard-active option.</p>
</div><div class="plf:field">
<label class="plf:field-label" for="combobox-project">Selected project</label>
<div class="plf:combobox" data-plf-combobox>
<select class="plf:combobox-native" id="combobox-project">
<option value="docs">Documentation</option>
<option value="website" selected>Website</option>
<option value="long">Customer support and international onboarding workspace</option>
</select>
</div>
<p class="plf:field-help">Selection is marked independently from the keyboard-active option.</p>
</div>import { Combobox, Field } from '@pelatform/react';
export function Example() {
return (
<Field label="Selected project" help="Selection is marked independently from the keyboard-active option.">
<Combobox defaultValue="website">
<option value="docs">Documentation</option>
<option value="website">Website</option>
<option value="long">Customer support and international onboarding workspace</option>
</Combobox>
</Field>
);
}import { Combobox, Field } from '@pelatform/react/prefixed';
export function Example() {
return (
<Field label="Selected project" help="Selection is marked independently from the keyboard-active option.">
<Combobox defaultValue="website">
<option value="docs">Documentation</option>
<option value="website">Website</option>
<option value="long">Customer support and international onboarding workspace</option>
</Combobox>
</Field>
);
}Search across both groups. Group titles organize choices; only tools can be selected.
<div class="field">
<label class="field-label" for="combobox-tool">Grouped tools</label>
<div class="combobox combobox-sm" data-plf-combobox data-plf-clearable data-plf-search-placeholder="Search tools…">
<select class="combobox-native" id="combobox-tool" name="tool" aria-describedby="combobox-tool-help">
<option value>Choose a tool…</option>
<optgroup label="Productivity">
<option value="notes" selected>Notes</option>
<option value="tasks">Tasks</option>
<option value="calendar">Calendar</option>
</optgroup>
<optgroup label="Administration">
<option value="users">Users</option>
<option value="settings">Settings</option>
<option value="billing" disabled>Billing (unavailable)</option>
</optgroup>
</select>
</div>
<p class="field-help" id="combobox-tool-help">Search across both groups. Group titles organize choices; only tools can be selected.</p>
</div><div class="plf:field">
<label class="plf:field-label" for="combobox-tool">Grouped tools</label>
<div class="plf:combobox plf:combobox-sm" data-plf-combobox data-plf-clearable data-plf-search-placeholder="Search tools…">
<select class="plf:combobox-native" id="combobox-tool" name="tool" aria-describedby="combobox-tool-help">
<option value>Choose a tool…</option>
<optgroup label="Productivity">
<option value="notes" selected>Notes</option>
<option value="tasks">Tasks</option>
<option value="calendar">Calendar</option>
</optgroup>
<optgroup label="Administration">
<option value="users">Users</option>
<option value="settings">Settings</option>
<option value="billing" disabled>Billing (unavailable)</option>
</optgroup>
</select>
</div>
<p class="plf:field-help" id="combobox-tool-help">Search across both groups. Group titles organize choices; only tools can be selected.</p>
</div>import { Combobox, Field } from '@pelatform/react';
export function Example() {
return (
<Field label="Grouped tools" help="Search across both groups. Group titles organize choices; only tools can be selected.">
<Combobox size="sm" name="tool" clearable searchPlaceholder="Search tools…" defaultValue="notes">
<option value="">Choose a tool…</option>
<optgroup label="Productivity">
<option value="notes">Notes</option>
<option value="tasks">Tasks</option>
<option value="calendar">Calendar</option>
</optgroup>
<optgroup label="Administration">
<option value="users">Users</option>
<option value="settings">Settings</option>
<option value="billing" disabled>Billing (unavailable)</option>
</optgroup>
</Combobox>
</Field>
);
}import { Combobox, Field } from '@pelatform/react/prefixed';
export function Example() {
return (
<Field label="Grouped tools" help="Search across both groups. Group titles organize choices; only tools can be selected.">
<Combobox size="sm" name="tool" clearable searchPlaceholder="Search tools…" defaultValue="notes">
<option value="">Choose a tool…</option>
<optgroup label="Productivity">
<option value="notes">Notes</option>
<option value="tasks">Tasks</option>
<option value="calendar">Calendar</option>
</optgroup>
<optgroup label="Administration">
<option value="users">Users</option>
<option value="settings">Settings</option>
<option value="billing" disabled>Billing (unavailable)</option>
</optgroup>
</Combobox>
</Field>
);
}<div class="field">
<label class="field-label" for="combobox-size-sm">Small</label>
<div class="combobox combobox-sm" data-plf-combobox>
<select class="combobox-native" id="combobox-size-sm">
<option value="docs">Documentation</option>
<option value="website">Website</option>
</select>
</div>
</div>
<div class="field">
<label class="field-label" for="combobox-size-default">Default</label>
<div class="combobox" data-plf-combobox>
<select class="combobox-native" id="combobox-size-default">
<option value="docs">Documentation</option>
<option value="website">Website</option>
</select>
</div>
</div>
<div class="field">
<label class="field-label" for="combobox-size-lg">Large</label>
<div class="combobox combobox-lg" data-plf-combobox>
<select class="combobox-native" id="combobox-size-lg">
<option value="docs">Documentation</option>
<option value="website">Website</option>
</select>
</div>
</div><div class="plf:field">
<label class="plf:field-label" for="combobox-size-sm">Small</label>
<div class="plf:combobox plf:combobox-sm" data-plf-combobox>
<select class="plf:combobox-native" id="combobox-size-sm">
<option value="docs">Documentation</option>
<option value="website">Website</option>
</select>
</div>
</div>
<div class="plf:field">
<label class="plf:field-label" for="combobox-size-default">Default</label>
<div class="plf:combobox" data-plf-combobox>
<select class="plf:combobox-native" id="combobox-size-default">
<option value="docs">Documentation</option>
<option value="website">Website</option>
</select>
</div>
</div>
<div class="plf:field">
<label class="plf:field-label" for="combobox-size-lg">Large</label>
<div class="plf:combobox plf:combobox-lg" data-plf-combobox>
<select class="plf:combobox-native" id="combobox-size-lg">
<option value="docs">Documentation</option>
<option value="website">Website</option>
</select>
</div>
</div>import { Combobox, Field } from '@pelatform/react';
export function Example() {
return (
<>
<Field label="Small">
<Combobox size="sm">
<option value="docs">Documentation</option>
<option value="website">Website</option>
</Combobox>
</Field>
<Field label="Default">
<Combobox>
<option value="docs">Documentation</option>
<option value="website">Website</option>
</Combobox>
</Field>
<Field label="Large">
<Combobox size="lg">
<option value="docs">Documentation</option>
<option value="website">Website</option>
</Combobox>
</Field>
</>
);
}import { Combobox, Field } from '@pelatform/react/prefixed';
export function Example() {
return (
<>
<Field label="Small">
<Combobox size="sm">
<option value="docs">Documentation</option>
<option value="website">Website</option>
</Combobox>
</Field>
<Field label="Default">
<Combobox>
<option value="docs">Documentation</option>
<option value="website">Website</option>
</Combobox>
</Field>
<Field label="Large">
<Combobox size="lg">
<option value="docs">Documentation</option>
<option value="website">Website</option>
</Combobox>
</Field>
</>
);
}Invalid
Set aria-invalid and aria-describedby on the native select: the script copies them to the field it adds.
Error: choose a workspace before continuing.
<div class="field">
<label class="field-label" for="combobox-workspace">Required workspace</label>
<div class="combobox" data-plf-combobox>
<select class="combobox-native" id="combobox-workspace" required aria-invalid="true" aria-describedby="combobox-workspace-error">
<option value>Choose a workspace…</option>
<option value="personal">Personal</option>
<option value="team">Team</option>
</select>
</div>
<p class="field-error" id="combobox-workspace-error">Error: choose a workspace before continuing.</p>
</div><div class="plf:field">
<label class="plf:field-label" for="combobox-workspace">Required workspace</label>
<div class="plf:combobox" data-plf-combobox>
<select class="plf:combobox-native" id="combobox-workspace" required aria-invalid="true" aria-describedby="combobox-workspace-error">
<option value>Choose a workspace…</option>
<option value="personal">Personal</option>
<option value="team">Team</option>
</select>
</div>
<p class="plf:field-error" id="combobox-workspace-error">Error: choose a workspace before continuing.</p>
</div>import { Combobox, Field } from '@pelatform/react';
export function Example() {
return (
<Field label="Required workspace" error="Error: choose a workspace before continuing.">
<Combobox required>
<option value="">Choose a workspace…</option>
<option value="personal">Personal</option>
<option value="team">Team</option>
</Combobox>
</Field>
);
}import { Combobox, Field } from '@pelatform/react/prefixed';
export function Example() {
return (
<Field label="Required workspace" error="Error: choose a workspace before continuing.">
<Combobox required>
<option value="">Choose a workspace…</option>
<option value="personal">Personal</option>
<option value="team">Team</option>
</Combobox>
</Field>
);
}Disabled
Disable the native select or its <fieldset>; the field the script adds follows it.
<fieldset class="field field-group" disabled>
<legend class="field-legend">Disabled workspace</legend>
<label class="sr-only" for="combobox-disabled">Workspace unavailable</label>
<div class="combobox" data-plf-combobox>
<select class="combobox-native" id="combobox-disabled">
<option value="locked">Managed by your organization</option>
</select>
</div>
<p class="field-help">Native disabled fieldset semantics remain in effect.</p>
</fieldset><fieldset class="plf:field plf:field-group" disabled>
<legend class="plf:field-legend">Disabled workspace</legend>
<label class="plf:sr-only" for="combobox-disabled">Workspace unavailable</label>
<div class="plf:combobox" data-plf-combobox>
<select class="plf:combobox-native" id="combobox-disabled">
<option value="locked">Managed by your organization</option>
</select>
</div>
<p class="plf:field-help">Native disabled fieldset semantics remain in effect.</p>
</fieldset>import { Combobox, FieldGroup } from '@pelatform/react';
export function Example() {
return (
<FieldGroup legend="Disabled workspace" help="Native disabled fieldset semantics remain in effect." disabled>
<label className="sr-only" htmlFor="combobox-disabled">Workspace unavailable</label>
<Combobox id="combobox-disabled">
<option value="locked">Managed by your organization</option>
</Combobox>
</FieldGroup>
);
}import { Combobox, FieldGroup } from '@pelatform/react/prefixed';
export function Example() {
return (
<FieldGroup legend="Disabled workspace" help="Native disabled fieldset semantics remain in effect." disabled>
<label className="plf:sr-only" htmlFor="combobox-disabled">Workspace unavailable</label>
<Combobox id="combobox-disabled">
<option value="locked">Managed by your organization</option>
</Combobox>
</FieldGroup>
);
}Open the list to review its empty state. Unmatched searches also show an empty message.
<div class="field">
<label class="field-label" for="combobox-empty">No available projects</label>
<div class="combobox" data-plf-combobox data-plf-empty="No projects available.">
<select class="combobox-native" id="combobox-empty">
<option value>Choose a project…</option>
</select>
</div>
<p class="field-help">Open the list to review its empty state. Unmatched searches also show an empty message.</p>
</div><div class="plf:field">
<label class="plf:field-label" for="combobox-empty">No available projects</label>
<div class="plf:combobox" data-plf-combobox data-plf-empty="No projects available.">
<select class="plf:combobox-native" id="combobox-empty">
<option value>Choose a project…</option>
</select>
</div>
<p class="plf:field-help">Open the list to review its empty state. Unmatched searches also show an empty message.</p>
</div>import { Combobox, Field } from '@pelatform/react';
export function Example() {
return (
<Field label="No available projects" help="Open the list to review its empty state. Unmatched searches also show an empty message.">
<Combobox emptyText="No projects available.">
<option value="">Choose a project…</option>
</Combobox>
</Field>
);
}import { Combobox, Field } from '@pelatform/react/prefixed';
export function Example() {
return (
<Field label="No available projects" help="Open the list to review its empty state. Unmatched searches also show an empty message.">
<Combobox emptyText="No projects available.">
<option value="">Choose a project…</option>
</Combobox>
</Field>
);
}Options from a request
The list follows the native select, so add the options your request returns to it.
<div class="field">
<label class="field-label" for="combobox-city">City</label>
<div class="combobox" data-plf-combobox>
<select class="combobox-native" id="combobox-city" name="city">
<option value>Loading cities…</option>
</select>
</div>
</div>
<script>
const select = document.getElementById('combobox-city');
async function loadCities() {
// Your request, here a list of { id, name }.
const response = await fetch('/cities');
if (!response.ok) throw new Error(response.statusText);
const cities = await response.json();
select.options[0].text = 'Choose a city…';
select.append(...cities.map(city => new Option(city.name, city.id)));
}
loadCities().catch(() => { select.options[0].text = 'Cities could not be loaded'; });
</script><div class="plf:field">
<label class="plf:field-label" for="combobox-city">City</label>
<div class="plf:combobox" data-plf-combobox>
<select class="plf:combobox-native" id="combobox-city" name="city">
<option value>Loading cities…</option>
</select>
</div>
</div>
<script>
const select = document.getElementById('combobox-city');
async function loadCities() {
// Your request, here a list of { id, name }.
const response = await fetch('/cities');
if (!response.ok) throw new Error(response.statusText);
const cities = await response.json();
select.options[0].text = 'Choose a city…';
select.append(...cities.map(city => new Option(city.name, city.id)));
}
loadCities().catch(() => { select.options[0].text = 'Cities could not be loaded'; });
</script>'use client';
import { useEffect, useState } from 'react';
import { Combobox, Field } from '@pelatform/react';
export function Example() {
const [cities, setCities] = useState<{ id: string; name: string }[]>([]);
const [status, setStatus] = useState('Loading cities…');
useEffect(() => {
async function loadCities() {
// Your request, here a list of { id, name }.
const response = await fetch('/cities');
if (!response.ok) throw new Error(response.statusText);
setCities(await response.json());
setStatus('Choose a city…');
}
loadCities().catch(() => setStatus('Cities could not be loaded'));
}, []);
return (
<Field label="City">
<Combobox name="city">
<option value="">{status}</option>
{cities.map(city => <option key={city.id} value={city.id}>{city.name}</option>)}
</Combobox>
</Field>
);
}'use client';
import { useEffect, useState } from 'react';
import { Combobox, Field } from '@pelatform/react/prefixed';
export function Example() {
const [cities, setCities] = useState<{ id: string; name: string }[]>([]);
const [status, setStatus] = useState('Loading cities…');
useEffect(() => {
async function loadCities() {
// Your request, here a list of { id, name }.
const response = await fetch('/cities');
if (!response.ok) throw new Error(response.statusText);
setCities(await response.json());
setStatus('Choose a city…');
}
loadCities().catch(() => setStatus('Cities could not be loaded'));
}, []);
return (
<Field label="City">
<Combobox name="city">
<option value="">{status}</option>
{cities.map(city => <option key={city.id} value={city.id}>{city.name}</option>)}
</Combobox>
</Field>
);
}Server search
With data-plf-server-search, your plf:combobox:search handler answers the typed text: during the event, pass event.detail.respond() an array of { value, label, detail } or a promise of one. The options join the select, and the chosen one stays there, so the form submits it.
<div class="field">
<label class="field-label" for="combobox-assignee">Assignee</label>
<div class="combobox" id="combobox-assignee-search" data-plf-combobox data-plf-server-search>
<select class="combobox-native" id="combobox-assignee" name="assignee">
<option value>Choose a member…</option>
</select>
</div>
</div>
<script>
document.getElementById('combobox-assignee-search').addEventListener('plf:combobox:search', event => {
const { query, signal } = event.detail;
// Your request, here a list of { value, label, detail }.
event.detail.respond(fetch(`/members?q=${encodeURIComponent(query)}`, { signal }).then(response => {
if (!response.ok) throw new Error(response.statusText);
return response.json();
}));
});
</script><div class="plf:field">
<label class="plf:field-label" for="combobox-assignee">Assignee</label>
<div class="plf:combobox" id="combobox-assignee-search" data-plf-combobox data-plf-server-search>
<select class="plf:combobox-native" id="combobox-assignee" name="assignee">
<option value>Choose a member…</option>
</select>
</div>
</div>
<script>
document.getElementById('combobox-assignee-search').addEventListener('plf:combobox:search', event => {
const { query, signal } = event.detail;
// Your request, here a list of { value, label, detail }.
event.detail.respond(fetch(`/members?q=${encodeURIComponent(query)}`, { signal }).then(response => {
if (!response.ok) throw new Error(response.statusText);
return response.json();
}));
});
</script>'use client';
import { Combobox, Field } from '@pelatform/react';
// Your request, here a list of { value, label, detail }.
const searchMembers = (query: string, signal: AbortSignal) =>
fetch(`/members?q=${encodeURIComponent(query)}`, { signal }).then(response => {
if (!response.ok) throw new Error(response.statusText);
return response.json();
});
export function Example() {
return (
<Field label="Assignee">
<Combobox name="assignee" onSearch={searchMembers}>
<option value="">Choose a member…</option>
</Combobox>
</Field>
);
}'use client';
import { Combobox, Field } from '@pelatform/react/prefixed';
// Your request, here a list of { value, label, detail }.
const searchMembers = (query: string, signal: AbortSignal) =>
fetch(`/members?q=${encodeURIComponent(query)}`, { signal }).then(response => {
if (!response.ok) throw new Error(response.statusText);
return response.json();
});
export function Example() {
return (
<Field label="Assignee">
<Combobox name="assignee" onSearch={searchMembers}>
<option value="">Choose a member…</option>
</Combobox>
</Field>
);
}Search a country, ISO code or dial code. Enter the national number without the country code.
<div class="field">
<label class="field-label" for="phone-national">Phone number</label>
<div class="input-group" role="group" aria-label="Phone number" data-plf-phone-input>
<div class="combobox input-group-combobox" data-plf-combobox data-plf-placeholder="Search countries…">
<select class="combobox-native" name="country" required aria-label="Country" aria-describedby="phone-help">
<option value>Choose a country</option>
<option value="ID" data-plf-detail="+62" data-plf-trunk-prefix="0" data-plf-display="🇮🇩 +62" selected>🇮🇩 Indonesia</option>
<option value="SG" data-plf-detail="+65" data-plf-display="🇸🇬 +65">🇸🇬 Singapore</option>
<option value="MY" data-plf-detail="+60" data-plf-trunk-prefix="0" data-plf-display="🇲🇾 +60">🇲🇾 Malaysia</option>
<option value="JP" data-plf-detail="+81" data-plf-trunk-prefix="0" data-plf-display="🇯🇵 +81">🇯🇵 Japan</option>
<option value="AU" data-plf-detail="+61" data-plf-trunk-prefix="0" data-plf-display="🇦🇺 +61">🇦🇺 Australia</option>
<option value="GB" data-plf-detail="+44" data-plf-trunk-prefix="0" data-plf-display="🇬🇧 +44" data-plf-keywords="UK Britain">🇬🇧 United Kingdom</option>
<option value="US" data-plf-detail="+1" data-plf-display="🇺🇸 +1" data-plf-keywords="USA America">🇺🇸 United States</option>
<option value="CA" data-plf-detail="+1" data-plf-display="🇨🇦 +1">🇨🇦 Canada</option>
</select>
</div>
<input class="input-group-control" id="phone-national" name="phone" type="tel" dir="ltr" autocomplete="tel-national" placeholder="201-555-5555" aria-describedby="phone-help">
</div>
<p class="field-help" id="phone-help">Search a country, ISO code or dial code. Enter the national number without the country code.</p>
</div><div class="plf:field">
<label class="plf:field-label" for="phone-national">Phone number</label>
<div class="plf:input-group" role="group" aria-label="Phone number" data-plf-phone-input>
<div class="plf:combobox plf:input-group-combobox" data-plf-combobox data-plf-placeholder="Search countries…">
<select class="plf:combobox-native" name="country" required aria-label="Country" aria-describedby="phone-help">
<option value>Choose a country</option>
<option value="ID" data-plf-detail="+62" data-plf-trunk-prefix="0" data-plf-display="🇮🇩 +62" selected>🇮🇩 Indonesia</option>
<option value="SG" data-plf-detail="+65" data-plf-display="🇸🇬 +65">🇸🇬 Singapore</option>
<option value="MY" data-plf-detail="+60" data-plf-trunk-prefix="0" data-plf-display="🇲🇾 +60">🇲🇾 Malaysia</option>
<option value="JP" data-plf-detail="+81" data-plf-trunk-prefix="0" data-plf-display="🇯🇵 +81">🇯🇵 Japan</option>
<option value="AU" data-plf-detail="+61" data-plf-trunk-prefix="0" data-plf-display="🇦🇺 +61">🇦🇺 Australia</option>
<option value="GB" data-plf-detail="+44" data-plf-trunk-prefix="0" data-plf-display="🇬🇧 +44" data-plf-keywords="UK Britain">🇬🇧 United Kingdom</option>
<option value="US" data-plf-detail="+1" data-plf-display="🇺🇸 +1" data-plf-keywords="USA America">🇺🇸 United States</option>
<option value="CA" data-plf-detail="+1" data-plf-display="🇨🇦 +1">🇨🇦 Canada</option>
</select>
</div>
<input class="plf:input-group-control" id="phone-national" name="phone" type="tel" dir="ltr" autocomplete="tel-national" placeholder="201-555-5555" aria-describedby="phone-help">
</div>
<p class="plf:field-help" id="phone-help">Search a country, ISO code or dial code. Enter the national number without the country code.</p>
</div>import { Combobox, Field, InputGroup, InputGroupControl } from '@pelatform/react';
export function Example() {
return (
<Field label="Phone number" help="Search a country, ISO code or dial code. Enter the national number without the country code.">
<InputGroup role="group" aria-label="Phone number">
<Combobox className="input-group-combobox" placeholder="Search countries…" name="country" required aria-label="Country" defaultValue="ID">
<option value="">Choose a country</option>
<option value="ID" data-plf-detail="+62" data-plf-display="🇮🇩 +62">🇮🇩 Indonesia</option>
<option value="SG" data-plf-detail="+65" data-plf-display="🇸🇬 +65">🇸🇬 Singapore</option>
<option value="MY" data-plf-detail="+60" data-plf-display="🇲🇾 +60">🇲🇾 Malaysia</option>
<option value="JP" data-plf-detail="+81" data-plf-display="🇯🇵 +81">🇯🇵 Japan</option>
<option value="AU" data-plf-detail="+61" data-plf-display="🇦🇺 +61">🇦🇺 Australia</option>
<option value="GB" data-plf-detail="+44" data-plf-display="🇬🇧 +44" data-plf-keywords="UK Britain">🇬🇧 United Kingdom</option>
<option value="US" data-plf-detail="+1" data-plf-display="🇺🇸 +1" data-plf-keywords="USA America">🇺🇸 United States</option>
<option value="CA" data-plf-detail="+1" data-plf-display="🇨🇦 +1">🇨🇦 Canada</option>
</Combobox>
<InputGroupControl name="phone" type="tel" dir="ltr" autoComplete="tel-national" placeholder="201-555-5555" />
</InputGroup>
</Field>
);
}import { Combobox, Field, InputGroup, InputGroupControl } from '@pelatform/react/prefixed';
export function Example() {
return (
<Field label="Phone number" help="Search a country, ISO code or dial code. Enter the national number without the country code.">
<InputGroup role="group" aria-label="Phone number">
<Combobox className="plf:input-group-combobox" placeholder="Search countries…" name="country" required aria-label="Country" defaultValue="ID">
<option value="">Choose a country</option>
<option value="ID" data-plf-detail="+62" data-plf-display="🇮🇩 +62">🇮🇩 Indonesia</option>
<option value="SG" data-plf-detail="+65" data-plf-display="🇸🇬 +65">🇸🇬 Singapore</option>
<option value="MY" data-plf-detail="+60" data-plf-display="🇲🇾 +60">🇲🇾 Malaysia</option>
<option value="JP" data-plf-detail="+81" data-plf-display="🇯🇵 +81">🇯🇵 Japan</option>
<option value="AU" data-plf-detail="+61" data-plf-display="🇦🇺 +61">🇦🇺 Australia</option>
<option value="GB" data-plf-detail="+44" data-plf-display="🇬🇧 +44" data-plf-keywords="UK Britain">🇬🇧 United Kingdom</option>
<option value="US" data-plf-detail="+1" data-plf-display="🇺🇸 +1" data-plf-keywords="USA America">🇺🇸 United States</option>
<option value="CA" data-plf-detail="+1" data-plf-display="🇨🇦 +1">🇨🇦 Canada</option>
</Combobox>
<InputGroupControl name="phone" type="tel" dir="ltr" autoComplete="tel-national" placeholder="201-555-5555" />
</InputGroup>
</Field>
);
}data-plf-phone-input removes a typed dial code and the country’s data-plf-trunk-prefix, so 0857… is sent as 857…. Leave the prefix out where the 0 belongs to the number, as in Italy, and validate on the server.
JavaScript
Combobox needs JavaScript. The Full script (pelatform-ui.min.js) starts every component on page load, with no code of your own; with ESM imports, call init() yourself, as in Installation. For markup you add later, see Dynamic content.
<link rel="stylesheet" href="pelatform-ui.min.css">
<link rel="stylesheet" href="icons/icons.min.css">
<script src="pelatform-ui.min.js" defer></script><link rel="stylesheet" href="core/pelatform-ui-core.min.css">
<link rel="stylesheet" href="components/form.min.css">
<link rel="stylesheet" href="components/combobox.min.css">
<link rel="stylesheet" href="icons/icons.min.css">
<script src="core/pelatform-ui-core.min.js" defer></script>
<script src="components/combobox.min.js" defer></script>
<script src="components/phone-input.min.js" defer></script>
<script>document.addEventListener('DOMContentLoaded', () => PLF.init());</script><link rel="stylesheet" href="pelatform-ui.prefixed.min.css">
<link rel="stylesheet" href="icons/icons.prefixed.min.css">
<script src="pelatform-ui.min.js" defer></script><link rel="stylesheet" href="core/pelatform-ui-core.prefixed.min.css">
<link rel="stylesheet" href="components/form.prefixed.min.css">
<link rel="stylesheet" href="components/combobox.prefixed.min.css">
<link rel="stylesheet" href="icons/icons.prefixed.min.css">
<script src="core/pelatform-ui-core.min.js" defer></script>
<script src="components/combobox.min.js" defer></script>
<script src="components/phone-input.min.js" defer></script>
<script>document.addEventListener('DOMContentLoaded', () => PLF.init());</script>| Attribute | Purpose |
|---|---|
data-plf-combobox |
Marks the combobox wrapper |
data-plf-placeholder |
On the wrapper: text shown while no value is chosen; the empty option’s text by default, else Select an option… |
data-plf-search-placeholder |
On the wrapper: text in the empty search field; Search options… by default |
data-plf-empty |
On the wrapper: message when nothing matches; No options found. by default |
data-plf-clearable |
On the wrapper: adds a clear button that chooses the empty option |
data-plf-server-search |
On the wrapper: typing asks your plf: handler for options instead of filtering the select’s own |
data-plf-min-length |
On the wrapper: characters typed before a server search; 1 by default, and 0 searches as the dropdown opens |
data-plf-searching, data-plf-search-error |
On the wrapper: messages while a server search waits and when it fails; Searching… and Options could not be loaded. by default |
<template data-plf-combobox-icon> |
In the wrapper: the icon shown before the value, an icon class or an SVG; a template without the hook holds an SVG |
data-plf-label |
On an option: the label shown in the field and list |
data-plf-display |
On an option: shorter text for the closed field, such as a flag and dial code; the label by default |
data-plf-detail |
On an option: secondary text, such as a code, that is also searched |
data-plf-keywords |
On an option: extra words that match the search |
| Method | Behavior |
|---|---|
PLF. |
Returns the instance, creating it for valid markup |
PLF. |
Returns the instance or null |
instance., instance. |
Open or close the dropdown; return false when nothing changes or the event is canceled |
instance. |
Chooses an option and closes the dropdown; returns false for an unknown, disabled or current value |
instance. |
Restores the native select; the value stays |
The list follows the native select: options you add, remove or rename update it while their values stay unique.
Events
| Event | When |
|---|---|
plf:, plf: |
Before and after the dropdown opens; the first is cancelable |
plf:, plf: |
Before and after the dropdown closes; the first is cancelable |
plf:, plf: |
Before and after a new value; the first is cancelable |
plf: |
With data-plf-server-search, 300 ms after typing stops |
Each event’s detail:
| Property | Events | Value |
|---|---|---|
instance |
All | The Combobox instance |
reason |
All | api, trigger or keyboard |
trigger |
All | The element used, such as the field, an option or the clear button, otherwise null |
previousValue |
before-change, change |
The value before the change |
value |
before-change, change |
The new value |
query |
search |
The typed text |
signal |
search |
An AbortSignal that aborts when a newer search starts or the dropdown closes |
respond |
search |
Answers the search during the event, with an array of options or a promise of one |
A choice also fires native input and change on the select; a native input or change your code dispatches fires only plf:combobox:change.
Keyboard
| Key | Action |
|---|---|
| Enter, Space, Arrow Down, Arrow Up | On the field: open the dropdown and focus its search |
| Letters | In the search: filter the list |
| Arrow Down, Arrow Up | Move through enabled options, wrapping at the ends |
| Enter | Chooses the active option and closes the dropdown |
| Escape | Closes the dropdown without choosing |
| Tab | Closes the dropdown without choosing; from the field, moves to the clear button when shown |
Phone input
PhoneInput cleans the number as it changes, on paste and when the country changes.
| Hook or method | Purpose |
|---|---|
data-plf-phone-input |
On the input-group: one country select and one type="tel" input |
data-plf-detail |
On an option: the dial code, such as +62, removed when typed as +62 or 0062 |
data-plf-trunk-prefix |
On an option: the prefix to remove for that country, such as 0 |
PLF., PLF. |
Return the instance |
instance. |
Cleans a number your code set; returns whether it changed |
instance. |
Stops cleaning; the number stays |
React
Combobox from @pelatform/react renders the native select and what the script adds from its option and optgroup children, which take the option attributes above; inside a Field its field takes the label, help and error.
| Prop | Values | Default |
|---|---|---|
size |
sm, lg |
The default size |
value |
The chosen option’s value, which the application changes in onValueChange |
Its own state |
defaultValue |
The value it starts with when the application does not set value |
The first enabled option |
onValueChange |
(value), called when an option, Clear or a native change chooses a value |
None |
open |
true or false, which the application changes in onOpenChange |
Its own state |
defaultOpen |
true starts with the dropdown open |
false |
onOpenChange |
(open, reason), with trigger or keyboard |
None |
clearable |
true adds the clear button |
false |
icon |
An Icon before the value |
None |
placeholder |
Text while no value is chosen | The empty option’s text, else Select an option… |
searchPlaceholder |
Text in the empty search field | Search options… |
emptyText |
Message when nothing matches | No options found. |
onSearch |
(query, signal), called 300 ms after typing stops, returning { value, label, detail } options or a promise of them, which take the children’s place in the list |
None |
showLabel, hideLabel |
The open button’s name while the dropdown is closed and open | Show options, Hide options |
clearLabel |
The clear button’s name | Clear selection |
listLabel |
The list’s name | Options |
The other props are the native select’s, ref included; className adds classes to the combobox wrapper, such as input-group-combobox, and with aria-label the field leaves a Field’s label to its other control, as in the phone number.
| Variable | Default |
|---|---|
--plf-combobox-height |
Minimum height: 2. (36px); 2rem (32px) with combobox-sm, 2. (40px) with combobox-lg; the list’s rows take it too |
--plf-combobox-radius |
--plf-radius-lg, 0. (8px) |
--plf-combobox-border |
--plf-color-input |
--plf-combobox-hover-border |
--plf-combobox-border, otherwise --plf-color-border |
--plf-combobox-invalid-border |
--plf-color-danger |
--plf-combobox-bg, --plf-combobox-color |
--plf-color-field, --plf-color-text |
--plf-combobox-icon-size |
--plf-control-icon-size (16px); 1em (14px) with combobox-sm, 18px with combobox-lg |
--plf-combobox-focus-width, --plf-combobox-focus-color |
--plf-focus-width (2px), --plf-focus-color |
--plf-combobox-focus-offset |
0px, so the ring sits just outside the border |
--plf-combobox-popup-width |
The field’s width, at least 16rem (256px) |
--plf-combobox-popup-max-height |
18rem (288px) |
--plf-combobox-popup-bg, --plf-combobox-popup-border |
--plf-color-surface-elevated, --plf-color-border-subtle |
--plf-combobox-search-bg, --plf-combobox-group-bg |
--plf-color-surface-raised |
--plf-combobox-group-color |
--plf-color-text-muted |
--plf-combobox-active-bg, --plf-combobox-active-color |
--plf-color-surface-muted, --plf-color-text |
--plf-combobox-active-border |
--plf-color-input |
--plf-input-group-combobox-width |
7. (116px), the width of an input-group-combobox segment |