String.prototype.search()
search(regexp) The search() method searches a string for a specified pattern and returns the index of the first match. If no match is found, it returns -1. Unlike indexOf(), search() accepts regular expressions, enabling complex pattern matching including wildcards, character classes, and quantifiers.
Syntax
string.search(regexp)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
regexp | RegExp | string | — | The pattern to search for. If a string is passed, it’s converted to a RegExp internally. |
Unlike indexOf(), which only searches for literal substrings, search() converts its argument through the RegExp constructor. A plain string becomes a regex that matches that exact substring, but you can also pass a full regex with flags for case-insensitive or word-boundary matching.
Examples
Basic usage with a string
const text = "Hello, world! Welcome to JavaScript.";
const index = text.search("world");
console.log(index);
// 7
A plain string argument is converted to a regex internally, so search("world") and search(/world/) behave identically for literal substrings. When the pattern includes characters that are special in regex syntax — like periods, parentheses, or dollar signs — you need the escaping that a regex literal or RegExp constructor provides.
Using a regular expression
const text = "The price is $19.99 and the discount is $5.00";
const index = text.search(/\$\d+\.\d{2}/);
console.log(index);
// 12
The regex \$\d+\.\d{2} finds a dollar sign followed by digits, a decimal point, and two more digits — a common currency pattern. Because search() only needs the position, not the matched text, it returns a single number. If you also need to extract the dollar amount, use match() instead.
Case-insensitive search
const text = "JavaScript is FUN";
const index = text.search(/javascript/i);
console.log(index);
// 0
The /i flag makes the pattern case-insensitive, so search() finds “JavaScript” even when the string contains “javascript”. This is one of the main reasons to use search() over indexOf() — indexOf() is always case-sensitive and cannot be configured otherwise.
Finding the position of a word boundary
const text = "The cat sat on the mat";
const index = text.search(/\bcat\b/);
console.log(index);
// 4
The \b anchor matches a word boundary — the position between a word character and a non-word character. This ensures search() finds “cat” as a whole word, not as part of “category” or “concatenate”. Word-boundary patterns are a common regex technique that indexOf() cannot replicate.
When pattern is not found
const text = "Hello, world!";
const index = text.search("python");
console.log(index);
// -1
When search() returns -1, the pattern was not found anywhere in the string. This makes it a natural fit for existence checks — test the result against -1 to branch on whether a pattern appears. For simple substring checks, includes() is more readable, but search() adds regex power.
Common Patterns
Validate input with search()
A common use case is validating whether a string contains a certain pattern before processing:
function containsEmail(text) {
const emailPattern = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/;
return text.search(emailPattern) !== -1;
}
console.log(containsEmail("Contact me at john@example.com"));
// true
console.log(containsEmail("No email here"));
// false
search() with an email regex gives you a quick presence check, but it does not validate that the entire string is an email — only that an email-like pattern appears somewhere. For full-string validation, anchor the regex with ^ and $, or use test() on a standalone regex.
Combine with other string methods
You can use search() to check if a pattern exists, then use other methods like replace() or slice():
const text = "Product ID: ABC-12345";
const prefix = "Product ID: ";
if (text.search(prefix) !== -1) {
const id = text.slice(text.search(prefix) + prefix.length);
console.log(id);
// ABC-12345
}
Using search() to locate a known prefix and then slice() to extract what follows is a lightweight parsing pattern. It works well for structured strings with fixed delimiters, though for more complex extractions with capture groups, match() is usually cleaner.
How search() works
search() converts its argument to a RegExp if it is not already one (via new RegExp(regexp)), then tests the string against that pattern. It returns the index of the start of the first match, or -1 if no match is found. The method always searches from the beginning of the string and ignores any lastIndex on the regex. It is essentially equivalent to string.match(regexp)?.index ?? -1.
search() vs match()
search() returns only the index of the first match; match() returns the matched substrings and capture groups. Use search() when you only need to know where a pattern starts. Use match() when you need the matched text or captured values.
const text = 'Price: $19.99';
text.search(/\$\d+\.\d+/); // 7 — just the position
text.match(/\$(\d+)\.(\d+)/); // ['$19.99', '19', '99']
The g flag has no effect
search() always finds only the first match and ignores the global (g) flag on a regex. If you pass a regex with g, the lastIndex property is not used, and search() always scans from the beginning of the string. Use matchAll() to iterate over all matches.
String argument conversion
If a non-RegExp value is passed, it is converted to a RegExp using new RegExp(value). This means special regex characters in the string (., *, +, etc.) are treated as metacharacters. To search for a literal string containing such characters, use indexOf() instead, which always performs a plain string search.
'a.b'.search('.'); // 0 — '.' becomes a regex that matches any character
'a.b'.indexOf('.'); // 1 — plain string search
When search() is the better tool
search() is the better tool when the pattern matters more than the raw substring. Unlike indexOf(), it can handle regular expressions, so you can look for word boundaries, character classes, or other flexible matching rules without writing extra parsing code. That makes it useful for validation and lightweight pattern checks.
It is also a good fit when you only need the first match position. If you do not care about the full matched text or capture groups, search() keeps the result simple: either an index or -1. That compact return value is easy to plug into branching logic.
See Also
- String.prototype.match() — Returns captured groups
- String.prototype.replace() — Replace matched patterns