Add a search bar

Adding a Search Bar

This example demonstrates how to add a search bar to your application using the Search component. Search provides autocomplete location suggestions through the Places API (opens in a new tab), keyboard navigation, customizable styling and more.

Key Features

  • Autocomplete location search
  • Keyboard navigation support
  • Accessible combobox pattern
  • Customizable styling
  • Loading and clear states

Implementation

  1. Create a formatter function for search results:
const formatResult = (result: WeatherPlaceSearchResult) => {
    if ('place' in result) {
        const { place } = result;
        const parts = [
            place.name,
            place.state ? place.state.toUpperCase() : null,
            place.country === 'US' ? null : place.countryFull
        ].filter(Boolean);
 
        return parts.join(', ');
    }
    return '';
};
  1. Create the search bar component with an input field, loading spinner, and clear button:
import { Search } from '@xweather/maps-ui-sdk';
 
const SearchBar = () => (
    <Search.Bar className="bg-white rounded-lg shadow-lg px-2 py-1 gap-2">
        <Search.SearchIcon className="text-slate-500" />
        <Search.Input
            placeholder="Search locations"
            className="px-1 py-0.5 bg-white selection:bg-[#AAF0E4]"
        />
        <Search.LoadingSpinner />
        <Search.Clear />
    </Search.Bar>
);
  1. Create the search results component:
import { Search } from '@xweather/maps-ui-sdk';
 
const SearchResults = () => (
    <Search.ResultsFetcher>
        <Search.ResultsData>
            {({ hasResults }) => (
                hasResults ? (
                    <Search.List>
                        <Search.ScrollableArea className="py-4 mt-2 bg-white rounded-lg shadow-lg">
                            <SearchItems />
                        </Search.ScrollableArea>
                    </Search.List>
                ) : null
            )}
        </Search.ResultsData>
    </Search.ResultsFetcher>
);
  1. Create the search items component to render individual results:
import { Search, useSearchContext } from '@xweather/maps-ui-sdk';
 
const SearchItems = () => {
    const { currentResults, activeDescendantId } = useSearchContext();
 
    return currentResults.map((result, index) => (
        <>
            {index > 0 && (
                <Search.Divider className="border-slate-300" />
            )}
            <Search.Item item={result}>
                <Search.ItemButton 
                    className={`px-4 py-1.5 text-sm ${
                        activeDescendantId === result.trackingId
                            ? 'text-white bg-[#3ABBA3]'
                            : 'text-black'
                    }`} 
                />
            </Search.Item>
        </>
    ));
};

The activeDescendantId matches the trackingId of the currently active/focused result, allowing you to style items based on keyboard navigation or hover state. This implements the ARIA combobox pattern (opens in a new tab) for accessibility.

  1. Finally, combine everything into a LocationSearch component:
import { Search } from '@xweather/maps-ui-sdk';
import { type WeatherPlaceSearchResult } from '@xweather/maps-ui-sdk/dist/types/search';
 
const handleSelectResult = (result: WeatherPlaceSearchResult) => {
    const { lat, long } = result.loc;
    // You can use these coordinates to update your map view
    // See the 'Add a map controller with controls' example for setting up the map
};
 
export const LocationSearch = () => (
    <Search
        onSelectResult={handleSelectResult}
        searchGroups={['places']} // Can also include 'stations' and 'recent'
        resultFormatter={formatResult}
    >
        <Search.FocusArea className="w-80">
            <SearchBar />
            <SearchResults />
        </Search.FocusArea>
    </Search>
);

The searchGroups prop can accept an array of different search types:

  • 'places': Location search results
  • 'stations': Weather station results
  • 'recent': Recently viewed locations

Combine this with the Map Controller example to see a complete example of integrating this search component with a map.