Search
The Search compound component provides a flexible, composable interface for location-based searching.
Features
- Text-based location search
- Geolocation
- Recent search history
- Grouped search results (Cities/Places)
- Loading states
- Custom result formatting
Usage Examples
Basic Search Implementation
import { Search } from '@xweather/maps-ui-sdk';
const SearchExample = () => {
const handleSelectResult = (result) => {
const { lat, long } = result.loc;
// Handle the selected location
};
return (
<Search onSelectResult={handleSelectResult}>
<Search.Bar>
<Search.SearchIcon />
<Search.Input placeholder="Search for a location" />
<Search.LoadingSpinner />
<Search.ClearButton />
<Search.GeolocateButton />
</Search.Bar>
<Search.ResultsFetcher>
<Search.ResultsData>
{({ results, visitedLocations, hasResults }) => (
<Search.ScrollableArea>
{visitedLocations.length > 0 && (
<Search.Group title="Recent">
{visitedLocations.map((item) => (
<Search.Item key={item.id} item={item} />
))}
</Search.Group>
)}
{hasResults && (
<>
<Search.Group title="Cities">
{results
.filter((item) => item.type === 'city')
.map((item) => (
<Search.Item key={item.id} item={item} />
))}
</Search.Group>
<Search.Group title="Places">
{results
.filter((item) => item.type === 'place')
.map((item) => (
<Search.Item key={item.id} item={item} />
))}
</Search.Group>
</>
)}
</Search.ScrollableArea>
)}
</Search.ResultsData>
</Search.ResultsFetcher>
</Search>
);
};Interactive Search with Tabs
Here's an example of integrating the Search component within a tabbed interface:
import { useEffect, useState, useRef } from 'react';
import { Search, Tabs } from '@xweather/maps-ui-sdk';
const TabbedSearch = () => {
const [currentTab, setCurrentTab] = useState<string | null>(null);
const searchInputRef = useRef<HTMLInputElement>(null);
const [coordinates, setCoordinates] = useState<{ lat: number; lon: number } | null>(null);
// Auto-focus search input when tab is selected
useEffect(() => {
if (currentTab === 'search') {
searchInputRef.current?.focus();
}
}, [currentTab]);
const handleSelectResult = (result) => {
const { lat, long } = result.loc;
setCoordinates({ lat, lon: long });
};
return (
<Tabs.Provider value={currentTab} onChange={setCurrentTab}>
<Tabs.List>
<Tabs.Button value="search">Search Tab</Tabs.Button>
<Tabs.Button value="settings">Settings Tab</Tabs.Button>
</Tabs.List>
<Tabs.Content value="search">
<Search
className="sm:w-90"
inputRef={searchInputRef}
onSelectResult={handleSelectResult}
>
<Search.Bar>
<Search.SearchIcon />
<Search.Input />
<Search.LoadingSpinner />
<Search.ClearButton />
<Search.GeolocateButton />
</Search.Bar>
<Search.ResultsFetcher>
<Search.ResultsData>
{/* Results rendering */}
</Search.ResultsData>
</Search.ResultsFetcher>
</Search>
</Tabs.Content>
</Tabs.Provider>
);
};Custom Result Formatting
You can customize how search results are displayed by providing a resultFormatter function:
const customFormatter = (result: SearchResult) => {
if (result.type === 'city') {
return `${result.name}, ${result.admin1}, ${result.country}`;
}
return `${result.name} (${result.type})`;
};
const SearchWithCustomFormat = () => (
<Search resultFormatter={customFormatter}>
{/* Search components */}
</Search>
);API Reference
Search (Root)
The main wrapper component that provides search context to all child components.
| Option | Description | Default |
|---|---|---|
resultFormatter | Type: (result: SearchResult) => string ()Function to format search results for display | |
onSelectResult | Type: (result: SearchResult) => void ()Callback when a search result is selected | |
maxVisitedLocations | Type: number ()Maximum number of visited locations to display in Timeline.Results | |
inputRef | Type: RefObject<HTMLInputElement> ()Reference to the search input element | |
children | Type: ReactNode (required)Search sub-components | |
Search.Bar
Container for search input and control elements.
| Option | Description | Default |
|---|---|---|
className | Type: string ()Additional CSS classes | |
children | Type: ReactNode (required)Search bar elements | |
Search.Input
The search input field.
| Option | Description | Default |
|---|---|---|
className | Type: string ()Additional CSS classes | |
placeholder | Type: string ()Input placeholder text | |
inputRef | Type: RefObject<HTMLInputElement> ()Reference to the search input element | |
Search.ResultsFetcher
A wrapper component that handles data fetching from the XWeather Weather API places endpoint (opens in a new tab).
| Option | Description | Default |
|---|---|---|
children | Type: ReactNode (required)Components that need access to the fetched data | |
Search.ResultsData
A component that processes and provides search results data to its children through a render prop pattern. It manages both API search results and visited (recent) locations, transforming raw API responses into a consumable format.
| Option | Description | Default |
|---|---|---|
children | Type: (props: { results: SearchResult[], visitedLocations: SearchResult[], hasResults: boolean }) => ReactNode (required)Render prop function that receives the processed search results, visited locations, and a boolean indicating if there are any results to display | |
Search.Group
Groups search results with a title.
| Option | Description | Default |
|---|---|---|
title | Type: string (required)Group title | |
className | Type: string ()Additional CSS classes | |
children | Type: ReactNode (required)Group content | |
Search.Item
Individual search result item.
| Option | Description | Default |
|---|---|---|
item | Type: SearchResult (required)Search result data | |
className | Type: string ()Additional CSS classes | |
Search.SearchIcon
Icon component specifically designed for the search interface.
| Option | Description | Default |
|---|---|---|
color | Type: string ()Color of the icon | |
className | Type: string ()Additional CSS classes | |
Search.LoadingSpinner
Loading indicator that appears during search operations.
| Option | Description | Default |
|---|---|---|
className | Type: string ()Additional CSS classes | |
size | Type: number ()Size of the spinner in pixels | |
Search.ClearButton
Button to clear the current search input.
| Option | Description | Default |
|---|---|---|
className | Type: string ()Additional CSS classes | |
onClick | Type: () => void ()Custom click handler | |
Search.GeolocateButton
Button that triggers geolocation-based search.
| Option | Description | Default |
|---|---|---|
id | Type: string ()Button ID | |
className | Type: string ()Additional CSS classes | |
onClick | Type: (event: React.MouseEvent) => void ()Custom click handler | |
icon | Type: IconComponent ()Custom icon component | |
iconProps | Type: IconProps ()Props passed to the icon | |
Search.ItemDivider
Horizontal line separator between search items.
| Option | Description | Default |
|---|---|---|
className | Type: string ()Additional CSS classes | |
Search.GroupDivider
Horizontal line separator between search groups.
| Option | Description | Default |
|---|---|---|
className | Type: string ()Additional CSS classes | |
Search.ScrollableArea
Container component that enables scrolling for search results.
| Option | Description | Default |
|---|---|---|
children | Type: ReactNode (required)Scrollable content | |
className | Type: string ()Additional CSS classes | |
maxHeight | Type: string ()Maximum height of scrollable area | |