Is [\s\s] Valid With JavaScript’s v Flag?

Sep 28, 2026·18 min read

A one-letter case change turns a whitespace test into an any-character test. With v enabled, both patterns compile, so syntax alone cannot tell you which one you meant.

[\s\s] is valid with JavaScript’s v flag, but it is redundant: it matches one whitespace character, while [\s\S] matches any one character.

The Short Answer: Yes, but It Is Redundant

Inside a character class, adjacent members are combined into one set. The pattern [\s\s] contains the set represented by \s twice:

whitespace ∪ whitespace = whitespace

Repeating the same set does not add another possibility. /[\s\s]/v therefore behaves like /\s/v.

Capitalization changes the second escape completely. Lowercase \s means whitespace, while uppercase \S means every character outside that whitespace set. Combining them covers both sides:

whitespace ∪ non-whitespace = every character

Start with anchored tests so that each pattern must match the entire one-character input:

const whitespaceTwice = /^[\s\s](?![\s\S])/v;
const everyCharacter = /^[\s\S](?![\s\S])/v;

console.log(whitespaceTwice.test(" "));
console.log(whitespaceTwice.test("A"));
console.log(everyCharacter.test(" "));
console.log(everyCharacter.test("A"));
console.log(everyCharacter.test("\n"));
console.log(whitespaceTwice.test(" \n"));
console.log(everyCharacter.test("A\n"));
true
false
true
true
true
false
false

The lowercase pattern accepts the space and rejects A. The mixed-case pattern accepts the space, A, and the newline.

That is the whole distinction. [\s\s] is valid but says the same thing twice; [\s\S] is valid and covers every character.

What each union covers[\s\s]\s\swhitespaceonlysame set twice[\s\S]\sspace\Sotherthe whole universe
Repeating whitespace changes nothing; combining whitespace with non-whitespace covers every character.

What \s, \S, and Square Brackets Mean

In the ordinary character-only classes used here, a character class describes a set of characters that may occupy one position in a match. Square brackets create the class, and members such as \s and \S add character sets. In v mode, some classes can also contain finite strings.

This class accepts either a, b, or c:

const letter = /^[abc]$/v;

console.log(letter.test("a"));
console.log(letter.test("c"));
console.log(letter.test("d"));
true
true
false

The members do not describe a three-character sequence. [abc] consumes one character chosen from the set, while abc outside brackets consumes the three-character sequence.

Choice versus sequence[abc]abcONEpositionabcabcTHREE positions in order
A character class offers choices for one position; text outside the class forms a sequence.

Character class escapes add predefined sets instead of individual characters:

  • \s denotes the characters covered by ECMAScript’s WhiteSpace and LineTerminator definitions.
  • \S denotes the complement of \s, meaning every character not in that set.
  • [\s\S] combines both sets by union.
  • [\s\s] combines the whitespace set with the same whitespace set.

The capitalization is part of the syntax. s and S are not interchangeable labels.

The same union rule applies when literal characters and escapes appear together. [A\s] accepts either uppercase A or one whitespace character. It does not require A followed by whitespace.

The broad Character classes guide covers predefined escapes, negated classes, and other class forms. Sets and ranges takes the range syntax further. Here, the important point is smaller: adjacent class operands are alternatives, and duplicate alternatives remain legal.

One more boundary matters. [\s\S] consumes one character. It does not consume an arbitrary amount of text until you add a quantifier:

const oneCharacter = /^[\s\S](?![\s\S])/v;
const anyNumberOfCharacters = /^[\s\S]*$/v;

console.log(oneCharacter.test("A\nB"));
console.log(oneCharacter.test("A\n"));
console.log(anyNumberOfCharacters.test("A\nB"));
console.log(anyNumberOfCharacters.test(""));
false
false
true
true

* allows zero or more repetitions of the class. Use + when at least one character is required.

The quantifier controls the count[\s\S]one kind→Aexactly one slot[\s\S]*→empty0A↵B…[\s\S]+→Aone required, then more
The class chooses the kind of character; the quantifier chooses the allowed count.

Why Both Patterns Remain Valid With v

The v flag enables Unicode sets mode. It is a Unicode-aware regular expression mode with richer character class syntax, including nested classes, intersection, subtraction, and string alternatives written with \q{...}.

These features extend the ordinary class rules. They do not make duplicate operands illegal.

Plain adjacency still forms a union:

[AB]       A or B
[\s\S]     whitespace or non-whitespace
[\s\s]     whitespace or whitespace

The first two unions expand the accepted set. The third does not, but a redundant set operation is still a valid set operation. The ECMAScript pattern grammar accepts it.

Unicode sets mode also provides two explicit operators:

  • && keeps characters present in both operands. This is intersection.
  • -- removes the right operand from the left operand. This is subtraction.

Say you need an ASCII letter. \p{ASCII} includes ASCII characters, and \p{Letter} includes characters with the Unicode letter property. Their intersection keeps characters belonging to both sets:

const asciiLetter = /^[\p{ASCII}&&\p{Letter}]$/v;

console.log(asciiLetter.test("R"));
console.log(asciiLetter.test("7"));
console.log(asciiLetter.test("é"));
true
false
false

R belongs to both sets. 7 is ASCII but not a letter, and é is a letter but not ASCII.

Subtraction works in the other direction. [\w--_] begins with \w and removes the underscore:

const wordWithoutUnderscore = /^[\w--_]$/v;

console.log(wordWithoutUnderscore.test("K"));
console.log(wordWithoutUnderscore.test("4"));
console.log(wordWithoutUnderscore.test("_"));
true
true
false

These operators matter when one set must be narrowed. [\s\s] needs neither because it is an ordinary union.

What each set operation keepsUnionkeep A or BadjacencyIntersectionkeep overlapA && BSubtractionkeep A, not BA — B
Union expands or preserves a set; intersection and subtraction narrow it.

The u and v flags are alternative Unicode-aware modes. They cannot appear together on one regular expression. Use v when the pattern needs Unicode sets syntax; RegExp v and d Flags covers the flag alongside match indices, while Unicode regular expressions explains Unicode property escapes.

Once regular expressions become named validators rather than isolated tests, Patterns and Architecture shows how to keep matching rules separate from the application decisions that use them.

Valid and Invalid v-Mode Classes

Unicode sets mode gives punctuation inside a class more responsibility. Some characters introduce grouping or set operations, so text that worked as an unescaped class member in another mode may be a syntax error with v.

This table separates the common cases:

Pattern or sourceResultReason
[\s\s]ValidIt unions the whitespace set with itself.
[\s\S]ValidIt unions whitespace with its complement.
[\w--_]ValidIt subtracts _ from \w.
[\p{ASCII}&&\p{Letter}]ValidIt intersects the ASCII and letter sets.
[A-\s]InvalidA character class escape cannot act as that range endpoint.
[(]Invalid( is reserved class syntax in v mode and must be escaped.
[!!]InvalidThe doubled punctuator is reserved inside a v-mode class.
[\p{ASCII}&&\p{Letter}--[A-Z]]InvalidIntersection and subtraction cannot be mixed at the same class level.
new RegExp("[\s\S]", "v")Valid, but wrongJavaScript parses the string first and removes the intended regex backslashes.

The last row is a different kind of failure. The regular expression still compiles, but the constructor receives [sS], not [\s\S]. It matches a lowercase or uppercase s.

In v-mode classes, (, ), [, ], {, }, /, -, \, and | participate in or are reserved for class syntax. Escape one when you intend the literal character rather than its syntactic role. Escaping, special characters covers the two places escaping can happen.

Repeated punctuators can also be reserved. [!!] is not a shortcut for one or two exclamation marks. Escape the literal characters, or move them outside the class when a sequence is what you need.

Mixed set operators need nesting so that the order is explicit. This version first finds ASCII letters, then removes uppercase ASCII letters:

const lowercaseAsciiLetter =
  /^[[\p{ASCII}&&\p{Letter}]--[A-Z]]$/v;

console.log(lowercaseAsciiLetter.test("m"));
console.log(lowercaseAsciiLetter.test("M"));
console.log(lowercaseAsciiLetter.test("é"));
true
false
false

The inner class completes the intersection. The outer class then performs the subtraction.

Nesting makes the order visibleSame levelA&&B—CNestedINNER FIRSTA && B—Cthen subtract from the inner result
Nesting turns two competing operators into an inner result followed by an outer operation.

This stricter grammar catches ambiguous punctuation, but it does not reject repetition merely because the repetition adds nothing. Duplicate operands and malformed operators are different cases.

Regex Literals, Constructors, and HTML pattern

A regex literal goes straight to the regular expression parser. Write the backslashes once:

const fromLiteral = /[\s\S]/v;

console.log(fromLiteral.test("\n"));
true

The RegExp constructor adds a JavaScript string layer. JavaScript parses the string before the regex parser receives it, so each intended regex backslash must be doubled:

const fromLiteral = /[\s\S]/v;
const fromConstructor = new RegExp("[\\s\\S]", "v");

console.log(fromLiteral.source);
console.log(fromConstructor.source);
console.log(fromConstructor.test("\n"));
[\s\S]
[\s\S]
true

Both regular expressions receive the same pattern. Without doubled backslashes, new RegExp("[\s\S]", "v") receives [sS] and tests for either form of the letter s.

HTML’s pattern attribute adds another place where these rules appear. The HTML Standard creates that regular expression using Unicode sets mode.

When a value is present, this pattern accepts one or more characters:

pattern="[\s\S]+"

The pattern attribute does not reject an empty value. When emptiness must also be rejected, use required:

<input required pattern="[\s\S]+">

This is HTML attribute text, not a JavaScript string, so the backslashes appear once. The + belongs outside the class because it repeats the complete [\s\S] operand.

The practical split is short:

  • Regex literal: /[\s\S]/v
  • JavaScript constructor: new RegExp("[\\s\\S]", "v")
  • HTML attribute value: pattern="[\s\S]+"

Same regular expression escape, different surrounding language.

How the pattern reaches the regex parserRegexliteral/[\s\S]/vregex sees[\s\S]Constructorstring layer”[\s\S]“JS removesone slashregex sees[\s\S]HTMLattributepattern=”[\s\S]+“regex sees[\s\S]+
The regex engine receives the same escape through three different source-code layers.

Which Form Should You Use?

Use \s when one whitespace character is the requirement. Writing [\s\s] is valid, but the duplicate operand hides the rule you mean.

Use [\s\S] when you specifically need an any-character class, especially inside a larger class expression. Add *, +, or another quantifier when the pattern must consume more than one character.

For modern dot-all intent, . with the s flag is usually clearer:

const whitespace = /^\s$/v;
const textByClass = /^[\s\S]*$/v;
const textByDot = /^.*$/sv;

console.log(whitespace.test("\n"));
console.log(textByClass.test("draft\nready"));
console.log(textByDot.test("draft\nready"));
true
true
true

The flags do separate jobs. s lets dot match line terminators, v enables Unicode sets mode, and m changes how ^ and $ behave around line boundaries. Multiline mode of anchors covers that last rule.

Three flags, three separate controlsschanges DOT.crosses newlinevchangesCLASS[A&&B]Unicode setsmchangesANCHORS^$^$each line
The s, v, and m flags change different parts of regular-expression behavior.

[\s\S] remains valid. The correction is not to ban it, but to preserve the capital S when every character is the intended set.

Frequently asked questions

Is [\s\s] valid with JavaScript's v flag?
Yes. Both operands denote the same whitespace set, so their union is valid but redundant. The pattern matches one whitespace character.
What is the difference between [\s\s] and [\s\S]?
The lowercase pattern contains the whitespace set twice and matches whitespace only. The mixed-case pattern combines whitespace with its complement, so it matches any one character.
Does [\s\S] match an entire string?
Not by itself. The character class consumes one character, so use a quantifier such as [\s\S]* or [\s\S]+ when the pattern must consume more.
Does the HTML pattern attribute use the v flag?
Yes. HTML parses the pattern attribute using JavaScript's Unicode sets mode. Characters that have special meaning inside a v-mode class must therefore be escaped there too.