Source Code

<div class="container py-5 d-flex justify-content-center">
  <div class="card bstz-card">
    <div class="card-body p-3 position-relative">
      <label class="form-label small fw-semibold">Timezone</label>
      <input type="text" class="form-control" id="bstzInput" placeholder="Search city or UTC offset..." autocomplete="off">
      <div class="bstz-dropdown d-none" id="bstzDropdown"></div>
      <p class="small text-muted mt-2 mb-0" id="bstzSelected">No timezone selected.</p>
    </div>
  </div>
</div>

Bootstrap Timezone Selector — Free HTML CSS JS Snippet

Bootstrap Timezone Selector · Forms · Plain HTML, CSS & JS · Live preview

What's included

Features

Search matches both city name and the formatted UTC offset string at once
Correctly formats fractional-hour offsets like UTC+05:30, not just whole-hour zones
Full arrow-key navigation and Enter-to-select, staying in sync with the currently filtered list
A document-level outside-click listener closes the dropdown without needing a backdrop element
An explicit "no matches" state instead of an empty, confusing dropdown

About this UI Snippet

Bootstrap Timezone Selector — HTML, CSS & JavaScript

Screenshot of the Bootstrap Timezone Selector snippet rendered live

The search matches against two different things at once inside render()z.city.toLowerCase().includes(q) for a name search, and formatOffset(z.offset).toLowerCase().includes(q) for searching by the offset string itself, so typing "+5:30" finds Mumbai just as reliably as typing "mumbai" does, without the user needing to know which search mode they're supposedly in.

formatOffset() is the detail that trips up a naive implementation: not every timezone sits on a whole-hour boundary — India's is UTC+5:30, exactly the kind of case that breaks a formatter written assuming offset is always an integer. Splitting the absolute offset into a whole-hour part via Math.floor and a remainder minutes part via (abs - h) * 60 handles both whole-hour zones and half-hour (or, in principle, 45-minute) zones with the same one function, rather than needing a special case for the unusual ones.

Keyboard navigation reuses the exact same render() call the typing handler uses, which is what keeps the highlighted row and the currently filtered list from ever disagreeing — arrowing down after typing a fresh query is filtering against the list that query actually produced, not a stale one from before the last keystroke.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Hand this snippet to an AI coding assistant like Claude and ask it to replace the small ZONES array with the browser's real Intl.supportedValuesOf('timeZone') list combined with Intl.DateTimeFormat to compute each zone's current offset (correctly accounting for daylight saving time), or to show each zone's current local time live next to its offset.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a Bootstrap 5.3 searchable timezone selector, using the real Bootstrap CDN framework (bootstrap.min.css and bootstrap.bundle.min.js), not custom CSS made to resemble it.

Requirements:
- A text input that shows a dropdown of timezones (city name plus UTC offset) on focus, filtering live as the user types.
- The search must match against both the city name and the formatted offset string (e.g. typing "+9" should find a UTC+9 zone the same way typing its city name would).
- Correctly format offsets that include a fractional hour (e.g. +5:30), not just whole-hour offsets — compute the hour and minute parts separately rather than assuming every offset is a whole number.
- Support ArrowUp/ArrowDown to move a highlighted selection through the filtered list and Enter to select the highlighted item, filling the input and showing a confirmation below it.
- Close the dropdown when a click happens anywhere outside the component, and show an explicit "no matches" message when a search returns nothing.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Click the inputEvery timezone appears in a dropdown, each with its city name and UTC offset.
  2. 2
    Type "mumbai"The list narrows to just Mumbai, showing its correctly formatted UTC+05:30 offset.
  3. 3
    Clear the input and type "+9"Tokyo appears, found by matching its offset string rather than its city name.
  4. 4
    Use the arrow keys to move through the list, then press EnterThe highlighted timezone fills the input and a confirmation line appears below.
  5. 5
    Click anywhere outside the cardThe dropdown closes automatically.

Real-world uses

Common Use Cases

Scheduling, calendar, and meeting-planning tools
Pairs with bootstrap-calendar-event-widget for a complete event-creation flow.
Account settings and localization preferences
Let a user set their timezone directly by search instead of scrolling a long native <select> of every IANA zone.
Dashboards showing data across multiple regions
A timezone picker for filtering or displaying timestamps relative to a chosen region.

Got questions?

Frequently Asked Questions

Yes — formatOffset() computes the whole-hour and remainder-minute parts of any offset separately, so a value like 5.5 correctly renders as UTC+05:30 rather than being truncated or mis-formatted the way a naive whole-hours-only formatter would handle it.

Yes — the filter checks the formatted offset string in addition to the city name, so a query like "+9" or "utc+9" matches Tokyo the same way typing "tokyo" would.

This demo uses a small illustrative list for clarity; a production version should use a real timezone database (via Intl.supportedValuesOf with "timeZone", or a library) that also correctly accounts for daylight saving time changes, which fixed numeric offsets alone cannot represent.

Yes. Keep the query and active index in component state, derive the filtered list in the render function, and bind the same keydown handling to your framework's event system — the offset-formatting logic needs no changes.