Datalist & Combobox Patterns
Use <datalist> to add native autocomplete suggestions to text inputs, range sliders, and color pickers without JavaScript.
Overview
Key Points
- •Connect input to datalist with `list="datalist-id"` on the input and matching `id` on the datalist
- •Users can still type anything datalist suggestions are non-binding hints, not validation constraints
- •Filter suggestions by adding a `value` attribute to each `<option>`; display text differs from submitted value using both `value` and text content
- •Works with type="text", "email", "url", "tel", "search", "number", "range", "color"
- •Combine with `pattern` attribute to both suggest and validate format
- •Dynamic datalists: update `<option>` children with JS for server-driven autocomplete
- •The `<option>` label attribute shows display text while the value attribute is what gets filled into the input
Examples
Text input with static autocomplete suggestions
<label for="browser">Favourite browser:</label>
<input
id="browser"
type="text"
list="browsers"
placeholder="Start typing..."
autocomplete="off"
/>
<datalist id="browsers">
<option value="Chrome">
<option value="Firefox">
<option value="Safari">
<option value="Edge">
<option value="Opera">
<option value="Brave">
</datalist>The browser shows matching options as the user types. They can still submit a value not in the list.
Datalist with label vs value (display text differs from submitted value)
<label for="country">Country:</label>
<input id="country" type="text" list="countries" name="country">
<datalist id="countries">
<!-- value = what goes into the input; text content = display label -->
<option value="US">United States</option>
<option value="GB">United Kingdom</option>
<option value="DE">Germany</option>
<option value="FR">France</option>
<option value="JP">Japan</option>
</datalist>When both value and text content are present, browsers show "United States (US)" or just the value behavior varies by browser.
Dynamic datalist populated from a fetch call
<label for="city">City:</label>
<input
id="city"
type="text"
list="city-options"
oninput="fetchCities(this.value)"
/>
<datalist id="city-options"></datalist>
<script>
let debounceTimer;
async function fetchCities(query) {
clearTimeout(debounceTimer);
if (query.length < 2) return;
debounceTimer = setTimeout(async () => {
const res = await fetch(`/api/cities?q=${encodeURIComponent(query)}`);
const cities = await res.json();
const datalist = document.getElementById('city-options');
datalist.innerHTML = cities
.map(c => `<option value="${c.name}">${c.country}</option>`)
.join('');
}, 200);
}
</script>Debounced fetch populates the datalist dynamically for server-side autocomplete.
Common Mistakes
- Confusing <datalist> with <select> datalist allows free text entry; select restricts to listed options only
- Using the same value for both `id` of datalist and `name` of the input the `list` attribute connects them, not `name`
- Forgetting that datalist suggestions are case-insensitive partial matches in most browsers by default
Note
For a range input, add a datalist with option values matching tick positions on the slider. The browser renders visual tick marks at those values a built-in way to show significant intervals without any CSS.
Exercises
Write HTML to solve each exercise. Use Preview to see it render in a live iframe, then mark as done.
Completed: 0 / 5 exercises
Knowledge Check
Question 1 of 4