Conditionally set an HTML attribute

By

Learn how to conditionally set an HTML attribute like selected in Astro using object spread, so the attribute only appears when your condition is true.

~~~

To conditionally set an HTML attribute, build an object with the attribute only when your condition is true, then spread that object onto the element. When the condition is false, you spread an empty object, and the attribute never appears in the HTML.

I ran into this while building the HTML of a page in Astro.

In particular I wanted to add the selected attribute to an option in a select, based on the URL.

Why not just set the attribute to false?

selected is a boolean attribute. The browser only checks if it exists, not what value it holds.

I couldn’t say selected={true}, where true is determined with JavaScript, because the mere existence of selected= in the markup makes the browser consider the option as selected. So the end result was the last option always being selected by default.

I needed the attribute to be completely absent when the condition was false.

The object spread trick

The pattern looks like this:

const attributes = {
  ...(isCurrentTeam && { selected: 'selected' })
}

If isCurrentTeam is true, the expression evaluates to { selected: 'selected' } and the spread copies it in.

If it’s false, the expression evaluates to false. Spreading a boolean into an object literal is a no-op, so attributes stays {}. No attribute gets rendered.

Here’s what I ended up doing in my Astro component:

<select>
  {teams.map((team) => {
    const attributes = {
      ...(Astro.url.pathname.includes('/team/') &&
        Astro.params.id === team.id && { selected: 'selected' }),
    }

    return (
      <option {...attributes} value={`/team/${team.id}`}>
        {team.name}
      </option>
    )
  })}
</select>

Only the option matching the current URL gets selected="selected" in the output. All the others render clean, with no attribute at all.

Where else does this work?

The trick is plain JavaScript, so you can use the same pattern in JSX or anywhere you build attributes as an object and spread them.

It’s also safe with sloppy data. Spreading false, null or undefined into an object literal adds nothing, so even if part of your condition chain returns undefined, you still get an empty object instead of an error.

Tagged: Astro, HTML · All topics
~~~

Related posts about astro: