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.
quran-search-engineBefore 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 search function 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
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 search call 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 FlatList and 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.
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 page
PAGE_SIZE: a constant, for example 50
FlatList.onEndReached: to detect when the user scrolls near the end and then increment page
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.
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-engine handles 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
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.
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 pageResults and counts in React state
exposes a getPositiveTokens helper to classify matched tokens
a screen that:
debounces the query
manages page, results, hasMore, and isLoadingMore
wires up a FlatList with onEndReached
a result item component that:
receives a verse and matched tokens
passes them to a HighlightText component 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.
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.
Open Mushaf Native repo: https://github.com/adelpro/open-mushaf-native
Quran Search Engine repo: https://github.com/adelpro/quran-search-engine
0
2
0