Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Search Bar in React Native

Search Bar

~9 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

A search bar is at its core a TextInput with a magnifying-glass icon, live filtering of a list on every keystroke, and a "clear" button – not its own React Native API, but a composition of building blocks you already know.

1. Description

The filtering itself is plain JavaScript: on every change of the search text, the original data list is checked against the (lowercased) search text with Array.prototype.filter(), and the result is stored in state – React Native itself has nothing to do with this part.

2. Short example

const [query, setQuery] = useState('');
const filtered = cities.filter((c) =>
  c.toLowerCase().includes(query.toLowerCase())
);

3. Complete project: a city search

npx create-expo-app searchbar-demo
cd searchbar-demo
App.js
import { useState, useMemo } from 'react';
import { View, TextInput, FlatList, Text, TouchableOpacity, StyleSheet } from 'react-native';

const CITIES = [
  'Berlin', 'Hamburg', 'Munich', 'Cologne', 'Frankfurt', 'Stuttgart',
  'Dusseldorf', 'Leipzig', 'Dortmund', 'Essen', 'Bremen', 'Dresden',
];

export default function App() {
  const [query, setQuery] = useState('');

  const filtered = useMemo(
    () => CITIES.filter((city) => city.toLowerCase().includes(query.toLowerCase())),
    [query]
  );

  return (
    <View style={styles.container}>
      <View style={styles.searchBar}>
        <Text style={styles.icon}>????</Text>
        <TextInput
          style={styles.input}
          placeholder="Search a city…"
          value={query}
          onChangeText={setQuery}
          autoCapitalize="none"
          clearButtonMode="while-editing"
        />
        {query.length > 0 && (
          <TouchableOpacity onPress={() => setQuery('')}>
            <Text style={styles.clear}>✕</Text>
          </TouchableOpacity>
        )}
      </View>
      <FlatList
        data={filtered}
        keyExtractor={(item) => item}
        renderItem={({ item }) => <Text style={styles.row}>{item}</Text>}
        ListEmptyComponent={<Text style={styles.empty}>No city found.</Text>}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, paddingTop: 60, paddingHorizontal: 16 },
  searchBar: { flexDirection: 'row', alignItems: 'center', backgroundColor: '#f3f4f6', borderRadius: 10, paddingHorizontal: 12, marginBottom: 12 },
  icon: { marginRight: 8 },
  input: { flex: 1, height: 44, fontSize: 16 },
  clear: { color: '#9ca3af', fontSize: 16, paddingHorizontal: 6 },
  row: { fontSize: 16, paddingVertical: 12, borderBottomWidth: 1, borderBottomColor: '#e5e7eb' },
  empty: { textAlign: 'center', marginTop: 24, color: '#9ca3af' },
});

4. Explanation

  • useMemo(() => ..., [query]) – only recomputes the filtered list when query actually changes, not on every re-render of the component for other reasons.
  • toLowerCase() on BOTH sides of the comparison – without it, "munich" (lowercase) would not match "Munich".
  • clearButtonMode="while-editing" is iOS-specific (a native "×" button inside the field); the additional custom TouchableOpacity clear button provides consistent behavior on Android too.
  • ListEmptyComponent from the FlatList chapter is reused here for the "no results" message.

5. Outputs

Ausgabe
A gray search bar with a magnifying-glass icon and placeholder text "Search a city…", below it all 12 cities as a list. Typing "m" live-filters to "Munich" and "Dortmund" and "Bremen" (cities containing "m"); an "✕" button appears on the right once text has been entered and clears the field when tapped.