How I Successfully Implemented quran-search-engine in open-mushaf-native
Clean, paginated Quran search with rich highlighting in a React Native Mushaf

When I started building advanced search for open-mushaf-native, I wanted three things:
- powerful search (text, lemma, root, fuzzy)
- good performance, with pagination and infinite scroll
- code that stays simple and maintainable, not a mess of custom search logic
The quran-search-engine package is what made that possible. Instead of reinventing search from scratch, I delegated the heavy logic to a dedicated library and focused my app code on UI and UX.
This article explains how I integrated quran-search-engine into my app, what new features it unlocked (like pagination), and how it helped me shorten the codebase, reduce files, and still add more features and highlights.
Why I Chose quran-search-engine
Before using the package, implementing Quran search meant handling all of this myself:
- parsing and normalizing Arabic text
- wiring in morphology and root/lemma data
- writing custom matching logic for different search modes
- trying to keep it fast and memory friendly
That approach quickly becomes complex and hard to maintain.
quran-search-engine solved that by providing:
- a single
searchfunction that takes the Quran text, morphology data, and a word map - support for multiple modes: exact text, lemma, root, and fuzzy
- pagination built in, so I can fetch search results page by page
- metadata such as matched tokens and token types that I can use for highlighting in the UI
So instead of spreading search logic across multiple files, I only need to:
- prepare the data
- call
search(...)with the right parameters - render the results
Was It Easy to Implement?
Yes – the integration was straightforward because the package has a clean, focused API.
At a high level, my implementation was:
- Install and import the package:
import { search, type QuranText, type MorphologyAya, type WordMap } from 'quran-search-engine';
- Load the data I already had:
- Quran text (array of verses)
- morphology JSON
- word map JSON
- Wrap the
searchcall in a custom React hook (useQuranSearch) that:- accepts the current query, options, and pagination info
- calls
search - exposes
results,counts, and helper methods for highlighting
- Connect that hook to a search screen with a
FlatListand infinite scroll.
Because the package does the heavy lifting, the React Native side stays relatively small:
- one hook for search logic
- one screen for UI and infinite scroll
- one result item component for highlighting and navigation
The hard parts (morphology, token-level matching, fuzzy search) all live inside quran-search-engine, not scattered across the app.
Pagination: The New Feature That Changed the UX
One of the biggest wins from the package is native support for pagination.
The search function accepts page and limit options. Instead of loading all matches at once, I can ask only for:
- page 1, 50 items
- page 2, 50 items
- and so on
In the app, I use:
page: React state that tracks the current pagePAGE_SIZE: a constant, for example 50FlatList.onEndReached: to detect when the user scrolls near the end and then incrementpage
Every time page changes, my useQuranSearch hook calls:
search(
normalizedQuery,
quranData,
morphologyMap,
wordMap,
{
lemma: advancedOptions.lemma,
root: advancedOptions.root,
fuzzy: advancedOptions.fuzzy,
},
{
page,
limit: PAGE_SIZE,
},
);
This gave me infinite scroll through FlatList:
- the package handles skipping and limiting results
- the app just renders and appends each page
- I don’t need to manually calculate offsets or slice arrays
From a user perspective, it feels like a smooth endless list of search results. From a developer perspective, it’s just a page number and a FlatList.
Code Shorter, Cleaner, and With Less Files
Before leaning on quran-search-engine, a search feature tends to produce:
- multiple utility files for normalization and matching
- custom indexing logic spread across the project
- a mix of UI and search logic inside the same components
With the package, I was able to centralize and simplify:
- I keep search logic in a single hook (
useQuranSearch). - The search screen handles UI, state, and infinite scroll.
- The result item handles only presentation and highlighting.
That means:
- fewer files: no separate search engine implementation in my own codebase
- shorter files: each file has a clear responsibility (hook vs screen vs item)
- clear boundaries:
quran-search-enginehandles how to search the Quran- my app handles how to display the results nicely
The result is a much cleaner architecture:
- easier to read
- easier to debug
- easier to extend later
More Features and Better Highlighting
The package doesn’t just return verses; it returns rich metadata.
For each verse, it includes:
- a list of matched tokens
- a mapping of token to type (
exact,lemma,root,fuzzy)
I use that data to build:
- color‑coded highlighting:
- one color for exact text matches
- another for lemma/root matches
- another for fuzzy matches
- a legend component that explains the colors to the user
Because the engine already tells me which tokens matched and how, adding more features is straightforward:
- I can tweak colors without touching search logic
- I can show counts like:
- “X exact matches”
- “Y lemma matches”
- “Z root matches”
- “W fuzzy matches”
- I can experiment with different UI layouts (cards, compact list, etc.) without changing how the search works
In other words, quran-search-engine lets me focus on UX, not parsing and matching.
How Much Code Did I Really Need?
If you look at the actual integration, the core parts are surprisingly small:
- a single hook that:
- sanitizes the query (Arabic only, trimming, etc.)
- calls
search(...)with options and pagination - holds
pageResultsandcountsin React state - exposes a
getPositiveTokenshelper to classify matched tokens
- a screen that:
- debounces the query
- manages
page,results,hasMore, andisLoadingMore - wires up a
FlatListwithonEndReached
- a result item component that:
- receives a verse and matched tokens
- passes them to a
HighlightTextcomponent with colors - handles navigation to the specific page and aya
Compared to building a full search engine from scratch, the amount of app code is very reasonable. Most of my time went into UI design and UX details, not low‑level search algorithms.
Final Thoughts
Using quran-search-engine in open-mushaf-native gave me:
- a powerful, production‑ready Quran search engine
- built‑in support for pagination (enabling infinite scroll)
- cleaner and shorter code in my own app (fewer files, clearer responsibilities)
- richer features like lemma/root/fuzzy modes and color‑coded highlighting
Instead of being “the search engine project”, my app stays what it should be: a beautiful, focused Quran reading experience, powered under the hood by a dedicated search package.
If you are building your own Quran app, my advice is simple: let quran-search-engine do the heavy lifting and spend your energy on the user experience.
Links
- Open Mushaf Native repo: https://github.com/adelpro/open-mushaf-native
- Quran Search Engine repo: https://github.com/adelpro/quran-search-engine



