Skip to content
Native Animation
Expanding Search animation preview

This preview uses fictional demo content. See the props below for the customization options available in this component.

npx nativeanimation add expanding-search
Glass

Expanding Search

A library search control that expands into an input and highlights results, with configurable books, results, accent color, and fonts.

$9 for this animation

Add to your project

Copy the component and its assets into your app with the Native Animation CLI, or paste the agent prompt into Claude Code, Codex or Cursor once the MCP server is connected.

About this animation

A library search control that expands into an input and highlights results, with configurable books, results, accent color, and fonts.

Why this one

Typical expanding search bars stop at the control. This one carries the transition through a credible reading product: two curated shelves and a reading-goal card recede, recent searches and useful suggestions arrive in a 35 ms cascade, typed results crossfade in, and each matching phrase receives a left-to-right accent underline. The input remains a real TextInput, and the same continuous progress drives the field shape, title exit, background focus, Cancel action, search icon, and discovery panel.

How it works

  1. onLayout derives the closed trigger position, expanded field width, and responsive book-cover sizing from the component itself.
  2. One continuous openProgress shared value springs from 0 to 1 and drives the field width and position, title lift, shelf dimming, Cancel reveal, and staggered discovery content.
  3. A real TextInput owns normal React text state while result and highlight transitions stay on the UI thread.
  4. Result titles are split around the live query; a rounded underline at 30% of the line height scales beneath the matching letters without covering them.
  5. expo-blur targets the library layer on Android SDK 31+ and falls back to its translucent surface treatment elsewhere.
  6. The forwarded ref lets demos and product flows open, close, focus, clear, or type programmatically without adding demo-only props.

Install

npx expo install expo-blur expo-linear-gradient @shopify/react-native-skia react-native-reanimated react-native-worklets

Icons are from Lucide (ISC) and are included as local paths in icons.ts. Skia web projects need CanvasKit initialized before this component is loaded.

Usage

import ExpandingSearch from './ExpandingSearch';

export function ReadingLibrary() {
  return <ExpandingSearch />;
}

Customize the content, palette, and imperative flow:

import { useRef } from 'react';
import ExpandingSearch, { type ExpandingSearchRef } from './ExpandingSearch';

export function ReadingLibrary() {
  const searchRef = useRef<ExpandingSearchRef>(null);

  return (
    <ExpandingSearch
      ref={searchRef}
      brandName="Lumen"
      accentColor="#E58A45"
      completedBooks={18}
      targetBooks={24}
      recentSearches={['Poetry', 'Design history', 'Ocean essays']}
      onQueryChange={(query) => updateSearchAnalytics(query)}
      onItemPress={(book) => openBook(book)}
    />
  );
}

The ref exposes open(focus?), close(), setQuery(query), clear(), and focus().

Props

PropTypeDefaultDescription
brandNamestring'Lumen'Product name shown above the library title.
titlestring'Library'Screen title.
firstShelfLabelstring'Continue reading'Label for the first shelf.
secondShelfLabelstring'Saved for later'Label for the second shelf.
readingGoalLabelstring'Reading goal'Label for the annual reading progress card.
completedBooksnumber18Books completed toward the reading goal.
targetBooksnumber24Target number of books for the reading goal.
booksExpandingSearchBook[]DEFAULT_BOOKSSix books used to build the two shelves.
recentSearchesstring[]DEFAULT_RECENTSRecent search chip labels.
suggestionsExpandingSearchItem[]DEFAULT_SUGGESTIONSSuggested books shown before typing.
resultsExpandingSearchItem[]DEFAULT_RESULTSBooks shown after the user types.
placeholderstring'Search your library'Input placeholder.
backgroundColorstring'#FAF7F2'Warm screen background.
textColorstring'#211D18'Primary ink color.
mutedColorstring'#7E756B'Muted ink color.
accentColorstring'#E58A45'Accent used by focus and result highlights.
fontFamilystringundefinedInterface font family.
mediumFontFamilystringundefinedMedium interface font family.
monoFontFamilystringundefinedMonospaced font family used for changing figures.
serifFontFamilystringundefinedSerif font family used for titles and book covers.
onOpenChange(open: boolean) => voidundefinedCalled when the open state changes.
onQueryChange(query: string) => voidundefinedCalled when the query changes.
onRecentPress(query: string) => voidundefinedCalled when a recent search is selected.
onItemPress(item: ExpandingSearchItem) => voidundefinedCalled when a suggestion or result is selected.
accessibilityLabelstring'Open library search'Screen-reader label for the search trigger.
styleStyleProp<ViewStyle>undefinedOptional style for the outer container.
testIDstringundefinedTest identifier applied to the outer container.

Compatibility

  • Expo SDK 58
  • React Native 0.88.0
  • Reanimated 4.7.1
  • React Native Skia 2.14.0
  • iOS and Android: supported
  • Web: supported
  • Expo Go: supported by the SDK 58 bundled modules; use a development build after adding native dependencies to another Expo project

Accessibility

The trigger, Cancel action, recent chips, suggestions, and results expose button roles and descriptive labels. The input is a native TextInput. Reduced Motion keeps the content crossfade and immediate state clarity while removing field travel, title lift, stagger movement, and press scaling.

Customization notes

Movement follows gestures, scroll position, or interruptible spring physics. A global duration is not exposed; reduced-motion fades retain their short fixed timing.