Introduction
Regular expressions in JavaScript have evolved significantly. ES2024 introduces the v flag — a superset of the u flag that unlocks powerful set notation, character class subtraction, intersection, and proper Unicode emoji matching. If you’ve struggled with complex character class logic or emoji regex patterns, the v flag is a game-changer.
What Is the v Flag?
The v flag replaces and extends the u (unicode) flag. Enable it by appending v to your regex:
const re = /[\p{Letter}]/v;
When the v flag is set, the pattern operates in unicode mode with additional syntax for set operations. Unlike the u flag, v mode treats character classes as sets that can be combined with boolean operations.
Set Notation: Character Class Subtraction
One of the most requested regex features is the ability to subtract one character class from another. The v flag introduces the -- operator:
// Match any letter except vowels
const re = /[\p{Letter}--[aeiouAEIOU]]/v;
console.log(re.test('b')); // true
console.log(re.test('a')); // false
This reads as: “the set of all Unicode letters, minus the set of ASCII vowels.” The subtraction operator works with any nested character class.
Character Class Intersection
The && operator computes the intersection of two sets:
// Match Greek letters only
const re = /[\p{Letter}&&\p{Script=Greek}]/v;
console.log(re.test('α')); // true
console.log(re.test('a')); // false
Combining intersection with subtraction enables precise patterns:
// Match Greek letters except 'α'
const re = /[[\p{Letter}&&\p{Script=Greek}]--[α]]/v;
Nested Character Classes
The v flag allows nesting character classes with brackets, eliminating the need for confusing escape sequences:
// Without v flag — awkward
const re1 = /[a-z&&[^aeiou]]/u;
// With v flag — clean and readable
const re2 = /[[a-z]--[aeiou]]/v;
Nested classes make complex patterns far more maintainable.
Improved Unicode Property Escapes for Emoji
Matching emoji was notoriously tricky with the u flag. The v flag adds the \p{RGI_Emoji} and related properties:
// Match a single emoji (including multi-codepoint sequences)
const re = /\p{RGI_Emoji}/v;
console.log(re.test('😀')); // true
console.log(re.test('👨👩👧👦')); // true (family emoji)
console.log(re.test('a')); // false
Other new properties include:
| Property | Description |
|---|---|
\p{Basic_Emoji} | Simple single-codepoint emoji |
\p{Emoji_Keycap_Sequence} | Keycap sequences like #️⃣ |
\p{RGI_Emoji_Flag_Sequence} | Flag emoji like 🇯🇵 |
\p{RGI_Emoji_Modifier_Sequence} | Skin-tone variants |
Migration from the u Flag
The v flag is a strict superset, but there are breaking changes to be aware of:
| Feature | u flag | v flag |
|---|---|---|
\d inside a class | Matches \d literal | Not allowed (use \\d for literal) |
Nested [ in class | Literal bracket | Starts nested class |
-- in class | Two literal hyphen-minus | Subtraction operator |
&& in class | Two literal ampersands | Intersection operator |
To safely migrate, use a codemod or audit patterns that contain - and & inside character classes:
// u flag — literal hyphen
const old = /[\d\-x]/u;
// v flag — must escape or restructure
const new_ = /[\[\d\-x]/v;
Browser and Runtime Support
The v flag is supported in Chrome 125+, Firefox 127+, Safari 17.5+, and Node.js 22+. Polyfilling is not possible for the parsing extensions, but you can use a two-regex fallback strategy:
const supportsVFlag = (() => {
try { return new RegExp('', 'v') !== null; } catch { return false; }
})();
Conclusion
The v flag transforms JavaScript regex from a pattern-matching tool into a set-processing language. Character class subtraction (--), intersection (&&), nested classes, and proper emoji matching make complex patterns readable and maintainable. If you’re targeting modern runtimes, adopt v — your future self will thank you.
