Development

A tabbed search interface with clear scope

Use separate search scopes only when they change the results meaningfully, and keep each control's state understandable.

A search interface becomes confusing when a decorative tab silently changes what is being searched. Make the scope visible: projects, guides, or another concrete collection. If there is only one result type, a single search field is usually better.

This is a new implementation guide for the subject of the original CSS and JavaScript tutorial. It does not depend on the historical download.

Prefer a normal form first

Give the search field a visible label, a descriptive placeholder if useful, and a real submit button. Scope can be a select field when switching it simply changes a query parameter. A URL such as ?q=icons&type=guides is easier to share and debug than state stored only inside a widget.

<form action="/search/" method="get">
  <label for="query">Search the library</label>
  <input id="query" name="q" type="search">
  <label for="scope">Search in</label>
  <select id="scope" name="type">
    <option value="projects">Projects</option>
    <option value="guides">Guides</option>
  </select>
  <button type="submit">Search</button>
</form>

This example assumes you implement the /search/ destination. A static site can instead filter an already-rendered collection, as the OpenSourceHunter directory does.

Use real tabs only for tab panels

If the control switches between distinct visible panels, follow the WAI tabs pattern, including selected state and keyboard behavior. Do not add role="tab" to ordinary navigation links merely to make them look like tabs.

Keep results understandable

Show the active scope, result count, and an empty state that suggests a next action. Preserve the query while switching scope. Avoid stealing focus after every update, and announce changes through a short polite live region instead of rereading the entire result list.