Swizec Teller - a geek with a hatswizec.com

    Datalist, the pure HTML typeahead you didn't know about

    If you ever want to build a searchable typeahead field, <datalist> can do that for you. On all browsers. Across devices. Standards compliant. With no JavaScript. 🤯

    Swizec Teller published ServerlessHandbook.dev avatarSwizec Teller published ServerlessHandbook.dev@Swizec
    TIL about <datalist>

    This bit of HTML gives you a full featured accessible typeahead search field 🤯
    Tweet media

    I learned about <datalist> from a candidate in an interview. It was great.

    Let's dig in.

    The <datalist> element

    Searchable dropdown components are a combination of an <input> field and a list of options. Typing filters the options so they're easier to find.

    Datalist in action

    You get fuzzy search, keyboard navigation, mouse navigation, and enter to select. Dropdown appears on focus, hides on blur. The selected value is textual.

    I got the list of dog breeds from the dog.ceo API.

    An iPad with a keyboard attached shows this:

    Datalist on an iPad

    And it even works on a phone 🤩

    Datalist on a phone

    You can try it yourself on CodeSandbox

    How you can use <datalist>

    You start with an input field:

    <input name="dogBreed" list="breeds" />

    The list attribute defines which datalist you want to use. This is a globally unique identifier on the page.

    Add a datalist component with your options:

    <datalist id="breeds">
    <option value="affenpinscher"></option>
    <option value="african"></option>
    <option value="airedale"></option>
    <option value="akita"></option>
    <option value="appenzeller"></option>
    <option value="australian shepherd"></option>
    <option value="basenji"></option>
    <!-- ... -->
    </datalist>

    And that's it. The id identifies your list and the browser handles the rest. You now have a standards compliant full featured typeahead field that works in any browser.

    If you want to package this as a reusable component, you'll have to generate the id and list attributes on render. Needs to be unique on the page.

    <datalist> as a React component

    A reusable React datalist needs to

    1. work as multiple instances on the page
    2. render options from a list
    3. return values with a callback

    No. 3 is optional. You can do that using form machinery like react-hook-form.

    You end up with a component like this:

    const Datalist = ({ name, options, onChange }) => {
    // this is a bad id for example purposes
    // in React 18 you'd use useId()
    const id = new Date().getTime()
    return (
    <>
    <input name={name} list={id} onChange={onChange} />
    <datalist id={id}>
    {options.map((o) => (
    <option value={o} />
    ))}
    </datalist>
    </>
    )
    }

    We use a poor man's unique identifier – the current time in milliseconds. It's okay, but you'll want to use useId when React 18 comes out and find a more robust solution until then.

    We call onChange for every input change. This may be annoying for consumers of our component.

    A nice option would be to check the value against your list of options on every change and call an onSelected callback when there's a match. That way you can catch when the user makes an explicit selection. Probably.

    <datalist> as a dynamic React component

    If you have too many options to list or need richer search behavior, you could expand this component with a dynamic search. Like this:

    const DynamicDatalist = ({ name, api, onChange }) => {
    // this is a bad id for example purposes
    // in React 18 you'd use useId()
    const id = new Date().getTime()
    const [options, setOptions] = useState([])
    async function runSearch(event) {
    const value = event.currentTarget.value
    // you'll want to debounce this
    const data = await fetchFrom(`${api}?search=${value}`)
    setOptions(data.suggestions)
    }
    return (
    <>
    <input name={name} list={id} onChange={runSearch} />
    <datalist id={id}>
    {options.map((o) => (
    <option value={o} />
    ))}
    </datalist>
    </>
    )
    }

    Assume this is pseudocode.

    You watch for changes, run API requests, and use those to populate the options list dynamically. Be careful about blindly running requests on every keystroke.

    Eric Burel avatarEric Burel@ericbureltech
    @Swizec I gave it a shot here: . It seems to work as expected indeed! Thanks for the tip, I was looking for a vanilla HTML typeahead just yesterday.

    What <datalist> can't do

    You can't style a datalist. I think this is strictly better.

    Swizec Teller published ServerlessHandbook.dev avatarSwizec Teller published ServerlessHandbook.dev@Swizec
    @thepanta82 In my experience those custom things always have a worse UX than the default browser component. I wish designers stopped insisting on customizing this stuff 😇

    You also can't use this to build the multiselect combobox thingy that's popular these days. The inputs that show your choices as pills next to your typing.

    A combobox multiselect, not possible with datalist
    A combobox multiselect, not possible with datalist

    You can't use rich option values like objects. It's a text. Unless you build it yourself as part of a <Datalist> component.

    And you'll have to make your own validation that the final value is on the list. A normal <select> might be a better option there.

    Ashley Ryan 👩🏼‍💻 avatarAshley Ryan 👩🏼‍💻@ashleyepryan
    @ericbureltech @Swizec The data list element is a text box with a list of suggestions. If you don’t support open ended text, it’s not useful.

    It’s not a combobox/searchable select, which is something that tripped me up at first.

    Next time you build a typehead, consider the <datalist>. It might serve you better than a 81kb React library.

    Cheers,
    ~Swizec

    PS: <datalist> works with Vue, Svelte, etc. I used React because that's more comfortable for me

    Did you enjoy this article?

    Published on December 14th, 2021 in Frontend, HTML

    Learned something new?
    Want to become an expert?

    Here's how it works 👇

    Leave your email and I'll send you thoughtfully written emails every week about React, JavaScript, and your career. Lessons learned over 20 years in the industry working with companies ranging from tiny startups to Fortune5 behemoths.

    Join Swizec's Newsletter

    And get thoughtful letters 💌 on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.

    "Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. 👌"

    ~ Ashish Kumar

    Join over 14,000 engineers just like you already improving their careers with my letters, workshops, courses, and talks. ✌️

    Have a burning question that you think I can answer? I don't have all of the answers, but I have some! Hit me up on twitter or book a 30min ama for in-depth help.

    Ready to Stop copy pasting D3 examples and create data visualizations of your own?  Learn how to build scalable dataviz components your whole team can understand with React for Data Visualization

    Curious about Serverless and the modern backend? Check out Serverless Handbook, modern backend for the frontend engineer.

    Ready to learn how it all fits together and build a modern webapp from scratch? Learn how to launch a webapp and make your first 💰 on the side with ServerlessReact.Dev

    Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com

    By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️

    Created by Swizec with ❤️