BibleReader.Toolbar includes search by default. Use this guide when you need a different layout or your own search interface.
Choose the customization that fits your application:
- Unified search: Use
useUnifiedSearchfor top results across content kinds, such as verse references and related topics, in one request without pagination. - Move the search button: Place the SDK's search control outside the toolbar.
- Custom search interface: Use
useBibleSearchfrom@youversion/platform-react-hooksand render your own controls. - Host-owned reader search: Use your application's search interface in place of the reader's popover through
onSearchPress.
Requirements
- Get an App Key from YouVersion Platform.
- Render search components and hooks inside
YouVersionProvider. See the React quick start.
Install the UI package for reader search:
Code
If you import the search hook directly, install the hooks package:
Code
Search verses and topics together
For a general search box, use useUnifiedSearch to retrieve top results in one request. This example selects verse references and related topics with fields.
You must supply both a Bible version ID and language preferences. The Bible version selects the text and language for verse results; the preferences select the language for topic results.
Use languageRanges: ["*"] to match all languages for topic results.
Render this component inside YouVersionProvider:
Code
Typing in this example does not send a request. Submitting the form updates the query; enabled prevents an empty query from loading. The hook does not manage a search field.
Other features you might want to add include input debouncing, search suggestions, and trending queries.
Omit fields to request all available result kinds; do not pass an empty array. See the core searchUnified parameters for currently supported kinds.
Use useBibleSearch for the paginated verse-search workflow. Unified search returns only top results, with no Load more action. It does not change the reader's built-in search. Verse hits contain passage IDs, not passage text; display a selected passage with BibleCard.
For options and return fields, see the useUnifiedSearch reference. For language selection, see Language ranges.
Move the search button
BibleReaderSearch renders a search icon button that opens a popover with a search field and results. Use it when your layout needs the search button outside the toolbar, such as above the passage while chapter controls remain below it.
Render BibleReaderSearch inside BibleReader.Root. Set search="none" on the toolbar to avoid showing two search buttons:
Code
BibleReaderSearch must remain inside BibleReader.Root, and the reader must remain inside YouVersionProvider.
To control the popover's visibility, use these optional props:
open: The current open state when your application controls visibility.onOpenChange: A callback that receives changes to the open state.defaultOpen: The initial open state when the component controls visibility.
Build a custom search interface
Import useBibleSearch from @youversion/platform-react-hooks. The hook takes a versionId and an optional bookIds filter.
Save this component as VerseSearch.tsx. It lists passage identifiers and calls onSelect when the user chooses one.
Render the component inside YouVersionProvider, and use onSelect to display the passage or navigate to it. The host-owned search example connects this component to reader navigation.
VerseSearch.tsx
Query lifecycle
setQuery(raw)updates the input and truncates it to 100 grapheme clusters. The hook trims the text used for requests.- If the query is empty, the hook requests trending queries. For nonempty input, the hook waits 300 ms for typing to pause before requesting suggestions. This delay is called a debounce.
submit()orselectSuggestion(text)starts verse search. Typing alone does not request verse results.- Changing the normalized query (the trimmed input) returns to suggestions or trending queries. Changing
versionIdrestarts the submitted search in the new Bible version. - Suggestions and trending queries use the Bible version's language tag. If the tag is missing or invalid, the hook uses
*to match all languages. See Language ranges.
A grapheme cluster is a user-perceived character, which can contain multiple Unicode code points.
Search phases
The hook returns a phase object. Read phase.kind before accessing that phase's fields:
trendingandsuggestingexposequeries,loading, and an optionalerror.searchingmeans the hook is waiting for the first visible results.resultsexposesversesandnextPage.nextPageis"none","available","loading", or"failed".emptymeans no results match the current search and filter.failedexposes the initial search error.
The suggesting phase also exposes debouncing. This field describes pending input, not a network request. Use loading, not debouncing, for a network-loading indicator.
If a later page fails, the hook keeps the existing results and sets nextPage to "failed". retry() retries failed query suggestions, the initial search, or the failed results page.
Results and book filters
Each result contains a passage id in Unified Standard Format Markers (USFM) reference format, a book, a chapter, and an array of verse numbers. The hook removes duplicate passage IDs and omits chapter-only hits.
The hook does not return passage text. Fetch text with usePassage, or display a selected result with BibleCard, which includes attribution.
The hook requests pages of 20 hits and accumulates results when you call loadMore().
Pass bookIds, such as ["JHN"], to filter by book. Filtering happens in the client, not in the search request.
If no matching results are visible and bookIds contains at least one book, the hook automatically requests more pages until it finds a match or reaches the end.
Once matching results are visible, a loadMore() call can add no visible results if the next page contains no matches. If nextPage is "available", call loadMore() again to request another page.
- To include all books, omit
bookIds. - To include no books, pass
[].
useBibleSearch does not expose topic search, search intent, or query-correction metadata; use useUnifiedSearch for those. For direct requests, use useSearchClient() inside the provider and call the methods in the TypeScript search guide. Manage loading, results, and errors in your interface for these direct calls.
Connect host-owned search to the reader
If your application owns the search interface, pass onSearchPress to BibleReader.Root. This callback replaces the built-in popover and receives the reader's current versionId, book, and chapter. Returning a value from the callback does not navigate the reader.
Connect your interface to reader navigation:
- Create one
BibleReaderNavigationinstance and retain it across renders. - Pass that instance to
BibleReader.Rootthrough itsnavigationprop. - When the user selects a result, call
focusReference({ versionId, passageId })on the navigation instance.
The example below reuses VerseSearch.tsx from the custom search section. Replace YOUR_APP_KEY with your App Key:
App.tsx
focusReference({ versionId, passageId }) opens the full chapter, scrolls to the passage, and temporarily emphasizes its verses. It does not create a saved highlight. If you request navigation before the reader mounts, the connection retains the newest pending request for mounting.
Pass the original result id as passageId to preserve a verse range. For example, JHN.3.16-18 focuses verses 16 through 18, not only verse 16. You do not need to parse the identifier before calling focusReference.
To check this integration:
- Open Search from the reader toolbar. Your application's search interface should appear instead of the built-in popover.
- Submit a query.
- Select a result. Your search interface should close, and the reader should show the selected passage in its chapter.