Search inputs in Arabic interfaces
Build Arabic search fields that handle mixed queries, stable controls, suggestions, safe highlighting and result states without losing input.
By Omran Khleifat, Founder of Ritla
Guide14 min read
A search field can accept Arabic characters and still fail its Arabic interface. The placeholder starts at an unexpected edge, the clear button moves when the query changes script, or the results heading displays a copied reference in the wrong order. A translated placeholder does not establish that search works.
Separate the field's direction, its surrounding controls and the search system's matching policy. dir="auto" can choose a base direction for a mixed-language query. It does not translate suggestions, normalize Arabic spelling or make highlighted results safe to render.
This guide uses a sound-effects catalogue. People search with an Arabic phrase such as أصوات المطر, an English collection name such as RainDock, or a recording reference such as 208-RAIN. Those queries exercise different parts of the same search component, including editing, submission and showing the query back inside Arabic text.
Choose direction for the query the field accepts#
A fixed LTR reset is a defect when the field expects Arabic queries. A fixed RTL direction can be a reasonable choice for a search limited to Arabic titles. For a catalogue that explicitly accepts Arabic, English and mixed queries, automatic direction is a useful default.
Compare the same field in an Arabic search form:
<!-- Problem: the field is forced LTR despite accepting Arabic titles. --><input type="search" name="q" dir="ltr" aria-label="البحث في المؤثرات الصوتية"><!-- Alternative for the catalogue's mixed-language query policy. --><input type="search" name="q" dir="auto" aria-label="البحث في المؤثرات الصوتية">Automatic direction follows the first strong directional character, not a vote across the query. Arabic-first and English-first versions of a mixed query can therefore choose different base directions. Leading digits or punctuation do not choose that direction by themselves. MDN's dir reference explains automatic direction and inherited direction.
Do not claim that this makes every mixed query visually unambiguous. A query can contain several directional runs, references or punctuation. Test the actual query shapes that the catalogue accepts, including moving the caret into the middle of them. How dir="auto" works explains the boundary in more detail.
There is an empty-state tradeoff. In the supplied measurements, an empty automatic-direction input resolved LTR, and its Arabic placeholder appeared at the left edge. The measurements used Chromium 151 on September 24, 2026; Firefox and Safari were not measured. Decide how the empty field should align rather than treating a translated placeholder as proof of RTL direction.
Start with a labelled search form#
Keep a working submit path before adding live results or suggestions. This form submits the query as q with GET to its current route; that route must implement the catalogue search.
<form id="sound-search" role="search" method="get" lang="ar" dir="rtl" aria-label="مكتبة المؤثرات الصوتية"> <label for="sound-query">البحث في المؤثرات الصوتية</label> <div class="sound-search__row"> <input id="sound-query" type="search" name="q" dir="auto" placeholder="اسم الصوت أو مرجع التسجيل" aria-describedby="sound-search-help"> <button type="submit">بحث</button> </div> <p id="sound-search-help">يمكن البحث بالعربية أو باسم المجموعة.</p></form>The label remains after typing replaces the placeholder. The button makes submission explicit. The search landmark identifies the region, as described in MDN's search role guidance. If the page contains several search regions, give them names that distinguish their scope.
type="search" identifies the input's purpose; it does not implement catalogue matching or an accessible suggestions popup. MDN's search input reference also documents browser-specific features. Check the native appearance on supported platforms instead of assuming every field provides the same cancel control or keyboard presentation.
Do not make a placeholder the only place that explains accepted query types. In the example, a recording reference is a supported query, so the implementation and help must agree about that support. If search covers only titles, do not advertise reference lookup because the API happens to accept arbitrary text.
Keep the interface stable when query direction changes#
The query can change direction while the surrounding form stays Arabic. Put layout direction on a stable wrapper and automatic direction on the editable input, rather than applying the query's direction to the whole component.
.sound-search__row { display: flex; align-items: center; gap: 0.7rem; max-inline-size: 42rem;} .sound-search__row input { flex: 1; min-inline-size: 0; font: inherit; padding-block: 0.8rem; padding-inline: 0.9rem;} .sound-search__row button { flex: none;}Here the row inherits RTL from the form. The input's changing base direction does not move the submit button to a new side. MDN's flex-direction reference explains the container's control over row direction. A decorative search icon and any custom clear button should also belong to the stable interface layout, rather than moving with the query's first letter.
Keep decorations out of the editable text and allocate them real space. An icon overlaid inside the input needs a matching space reservation. That becomes harder when the icon's wrapper remains RTL while padding on an automatic-direction input changes its physical mapping. Inspect both elements before adding more padding. Padding-inline for RTL layouts covers that spacing problem.
Do not mirror a magnifying glass merely because the interface is Arabic. It identifies search, not horizontal progression. Check the actual icon and its meaning; a back arrow in the same toolbar has a different responsibility.
At narrow widths, verify that the input still has enough room to edit a reference and the Arabic submit button remains readable. A shrinkable input prevents one cause of overflow, but it does not prove the complete header or search region fits.
Let people edit the query they entered#
Changing the input value during every keystroke can disturb the caret, selection or an unfinished input-method composition. Keep the raw editable query separate from the representation used for matching.
For example, a catalogue may ignore Arabic diacritics when searching titles. That does not require removing diacritics from the visible query as someone types. Derive a search key for the request or index while preserving what the person entered in the field.
Test edits in the middle of أصوات المطر, selecting one word and replacing it, and pasting a mixed query. Appending characters at the end exercises only one editing path. Recreating the input after each results update can lose state even when its displayed value is restored.
Handle composition through the component's supported input lifecycle. KeyboardEvent.isComposing indicates keyboard events within a composition session. An Enter handler that submits or accepts a suggestion without considering composition can interrupt text entry. Arabic keyboards do not all produce one event sequence, so test the input methods in your support scope.
Avoid taking over Left and Right to move between suggestions in a vertical list. People need those keys for query editing. Also check Home, End, selection shortcuts and Backspace with mixed text. Do not rewrite the string to make the caret appear to move in an imagined visual order.
Define Arabic matching separately from text direction#
Direction controls rendering. Search recall depends on the catalogue's data, tokenizer, normalization and matching rules. A query that looks correct but returns no expected recording needs investigation beyond CSS.
Write down which transformations the product intends. Canonically equivalent Unicode sequences, optional diacritics, letter variants, spacing and digit styles are separate decisions. String.prototype.normalize() supplies Unicode normalization forms; calling it does not implement a complete Arabic search policy.
Use different rules where the data requires them. A forgiving title search can accept variants that an exact recording-reference lookup must distinguish. Stripping punctuation from 208-RAIN because it helps natural-language matching can change the reference being requested.
Make the policy symmetric. If a query is transformed but the indexed title is not, the change can still miss the intended recording. Agree on the request and indexing contract with the service that performs matching, rather than adding unrelated normalizers in each frontend view.
Create a small set of expected query-to-result fixtures using real catalogue entries. Include a diacritized title, its accepted unvowelled query, an English collection name and an exact reference. Record which matches are intentional. Do not invent additional equivalences solely to make a test return something.
When a request fails, preserve that distinction too. A network error is not evidence that the Arabic query has no matches. Show an appropriate failure state and keep the query available for retry.
Follow one failed search across the boundaries#
When a known recording is missing, capture one reproducible query and its expected recording ID. Inspect the raw field value, the submitted query parameter and the response IDs before changing direction or normalization. This separates a display defect from a request defect and a matching defect.
If the raw value is right but the request differs, inspect the query-building path, including trimming and URL encoding. If the request is right but the expected ID is absent, investigate matching rules, filters and the indexed fields. An English collection name will not match an Arabic-only title index unless the search contract includes collection metadata or another relevant field.
If the response includes the expected ID but the row is missing, examine frontend filtering and rendering. A client-side second filter can discard a server-approved match because it uses a different normalization rule. Avoid fixing that by changing the user's query until the layers happen to agree; establish which layer owns the intended matching policy.
Keep this fixture in regression coverage. Assert the expected ID and preserved query text, then review the display separately. A test that only checks that some results exist can pass while the intended Arabic recording remains impossible to find.
Clear the whole search state deliberately#
A native search field may offer a browser-provided cancel control. If the product adds its own clear button, inspect whether both appear and remain usable on supported browsers. Do not assume a platform-specific pseudo-element is a portable foundation for the control.
A custom clear action needs an Arabic accessible name and type="button" if it sits inside the form. It should clear the intended query state, preserve a usable focus position and follow the product's rule for the resulting screen: all recordings, recent searches or an empty search view.
Clearing the visible input alone is incomplete when a suggestion request is pending. Cancel or invalidate the pending operation, clear the active suggestion and prevent its eventual response from repopulating the popup. Reset result headings and announcements consistently with the chosen empty state.
Use the normal application state-update path. Programmatic value assignment is not a substitute for updating a controlled component's model. Verify clearing with keyboard activation and touch, then type an Arabic query again. That sequence catches stale direction, old suggestions and focus lost after the button removes itself.
Treat suggestions as an interaction, not a floating list#
If suggestions are selectable values associated with the editable query, implement the appropriate WAI-ARIA combobox pattern. The popup needs more than Arabic text and a border. Its expanded state, controlled popup and active item must correspond to the visible interaction.
Keep the popup's interface language and direction independent of the query's first letter. Arabic category labels and help do not become English interface content because someone searched for RainDock. Individual recording titles or references can have their own directional boundaries.
Specify what Enter does with and without an active suggestion. A highlighted row must not silently replace the query merely because the user intended to submit a search. Escape should follow the documented dismissal policy, and Tab should let people continue through the interface.
When results change, remove or update any active-option reference pointing to a row that no longer exists. If the component keeps DOM focus in the input, it must also keep the visually active option in view. Test filtering after moving several rows into the list, not just opening the first suggestion.
If the popup is rendered outside the search form, inspect its actual ancestors and direction. A portalled popup can inherit from an English shell even though its trigger sits inside Arabic content. Check its alignment and clipping in the real page, especially with the on-screen keyboard open. These need direct interaction tests; a translated closed field does not establish them.
Prevent older responses from describing a newer query#
Debouncing reduces the number of requests. It does not establish which response is allowed to update the interface.
Suppose an Arabic title query starts a slow request, then the person enters RainDock and gets a faster response. If the earlier response arrives last, the results can disagree with the field while every word remains correctly translated.
Associate each request with a generation and the search state it represents, including filters or locale when they affect results. Before applying a response, establish that it still belongs to the current operation. Checking query text alone can miss a repeated query with changed filters.
AbortController can cancel an outstanding fetch operation. Use cancellation alongside a current-request check, including the paths for clearing, leaving the page and selecting a suggestion. Do not let a late error replace a successful newer result set either.
While a new query is pending, decide whether the old results remain visible. If they do, make clear which completed search they describe and prevent stale suggestions from acting as matches for the new text. Keep a committed search value separate from the query currently being edited when the product uses submit-to-search behavior.
Isolate the query when showing it inside Arabic text#
The search field and the results heading are separate bidi contexts. A reference that looks right in the input can reorder when inserted after an Arabic phrase.
For the reference query, use a boundary around the query alone:
<p lang="ar" dir="rtl"> نتائج البحث عن <bdi id="displayed-sound-query">208-RAIN</bdi></p>The digits-then-Latin reference matches the supplied reordering case. Without isolation after Arabic text, its groups can appear as RAIN-208. This is an identifier with a defined sequence, so that rearrangement does not describe an alternative reading direction for the same reference.
Populate the isolated node as text, using the completed search value that the results actually describe:
const queryNode = document.querySelector("#displayed-sound-query"); function showCompletedQuery(completedQuery) { queryNode.textContent = completedQuery;}The caller supplies the query associated with the rendered response. Reading the input's latest value instead can label older displayed results with a newer, unfinished query. textContent inserts text without interpreting it as HTML; bidi isolation addresses a different problem from HTML interpretation.
Keep the translated phrase outside the query boundary. Wrapping both together allows the Arabic label to determine the whole boundary's direction. For the underlying behavior, see bidi isolation.
Highlight matches in the original text safely#
Do not build a result row by interpolating query or title strings into innerHTML. A search string is text, including any characters that resemble markup. A regular expression constructed directly from the query can also treat punctuation as operators instead of literal search text.
For a deliberately limited exact, case-sensitive first-match highlighter, use text nodes and a real mark element:
function highlightFirstExact(label, query) { const fragment = document.createDocumentFragment(); const start = query === "" ? -1 : label.indexOf(query); if (start === -1) { fragment.append(document.createTextNode(label)); return fragment; } const end = start + query.length; const mark = document.createElement("mark"); mark.textContent = label.slice(start, end); fragment.append( document.createTextNode(label.slice(0, start)), mark, document.createTextNode(label.slice(end)) ); return fragment;}The result renderer can append the returned fragment to its text container. The helper neither parses user text as HTML nor interprets the query as a regular expression. An empty or unmatched query leaves the complete label as plain text. It highlights one literal match, not every semantic match produced by a search service.
That limitation matters for Arabic normalization. If matching removes diacritics or changes the string's length, offsets in the normalized search key are not automatically offsets in the original title. Applying them directly can mark the wrong characters or split a combining sequence.
For a simplified rule that removes the vowel marks in this short title, the offset difference is visible:
Original title: مَطَرSearch key: مطرMatched query: طرKey range: [1, 3)Original range: [2, 5)The ranges use zero-based UTF-16 offsets with an exclusive end. Both strings represent the same letters under this rule, but the original contains two extra marks. Using the key's range to slice the original starts on a vowel mark and misses part of the intended match. The exact helper above avoids this mismatch by searching the original text directly; it consequently does not claim to highlight a match found only after removing marks.
For normalized highlighting, obtain ranges mapped back to the original displayed string, or retain an explicit mapping through your transformation. Validate range boundaries before rendering. Intl.Segmenter can help identify grapheme boundaries, but it does not reconstruct a normalization mapping for you. When reliable original ranges are unavailable, showing an unhighlighted correct title is preferable to corrupting it.
Inspect Arabic joining and combining marks around highlight boundaries in the actual font. Avoid adding tracking or separate layout boxes to individual matched letters. Also compare the row's complete text with the source title; highlighting should preserve content, not rewrite it.
Translate and announce search states as states#
Keep loading, no results, request failure and successful updates distinct. For the catalogue, a no-match message can say لا توجد مؤثرات مطابقة. جرّب عبارة أخرى. A request failure needs wording that explains the inability to complete the search, rather than blaming the query.
For live updates that leave focus in the search field, provide a concise status announcement through the chosen accessible status mechanism. W3C's Status Messages guidance includes search results as an example. Avoid announcing an entire refreshed result list on every keystroke or moving focus into it automatically.
If the product displays a count, translate its complete Arabic plural messages rather than borrowing English singular-versus-plural rules. A reviewed uncounted update such as تم تحديث نتائج البحث. can be enough when the count adds no useful information. The visible results must still correspond to the announced operation.
Include hidden interaction text in translation review: the search region name, custom clear-button name, suggestion instructions and retry action. A page that translates only titles and the placeholder still leaves part of the search task in another language.
Restore searches without rewriting them#
A results page should preserve the query through refresh, shared links and back navigation according to the product's navigation model. Use the same query parameter contract for the form and any JavaScript enhancement.
When constructing query strings in code, use URLSearchParams rather than concatenating the typed text into a URL. Test literal plus signs, ampersands, spaces and Arabic text as data, then verify the query restored into the field. Do not manually decode a value that the URL parser has already decoded.
Restore the raw display query and the filters associated with the results. A normalized search key may be useful internally but should not replace the person's wording merely because it is easier to store. Reapply the field's direction policy after restoration and check that history navigation does not leave old suggestions open over a different result set.
Test the transitions between query types#
Begin with an empty field, enter أصوات المطر, replace it with RainDock, then paste 208-RAIN. Check the field, controls, suggestions, result heading and submitted query at each step. This sequence exposes state left behind when direction or query type changes.
Also test a mixed phrase, a leading punctuation character, an edit in the middle of a query and a query that deliberately has no match. Compare visual order with the expected reference sequence, then inspect the actual string sent to the service. Copying text alone does not prove its displayed order is right.
Slow requests to verify that clearing or replacing a query prevents older responses from restoring stale content. Trigger a request failure and retry it. Check the empty-result message separately. For highlights, include diacritics, unmatched text and literal punctuation, and assert that assembling the rendered text reproduces the original title.
Use keyboard and touch interaction at narrow widths, with the search keyboard open where applicable. Confirm that the clear control, submit button and active suggestion remain reachable. Inspect accessible names and status announcements as well as the visible Arabic text.
A free Ritla scan can report : Text inputs rendered LTR where Arabic input is expected, and : Untranslated attribute text (placeholder, alt, title, aria-label, button value). Matching quality and suggestion interaction still need direct tests; Arabic localization testing helps organize those search states for review.