Regex Fundamental

Used in this guide:
Next.js 15.3.3
Tailwind CSS 4

Introduction

Regex (short for Regular Expressions) is a powerful tool used to match and extract patterns from strings—commonly applied in tasks like validating input, filtering data, and parsing content. In this tutorial, we’ll walk through three beginner-friendly examples inside a real React/Next.js app to help you understand how regex works and how you can use it effectively in your own projects.

Why Regex?

  • Pattern matching in strings
  • Substring extraction
  • Validation
  • Replacement
  • Filtering

Example 1: Validation

What if you want to make sure users only enter English letters as their username? Let’s say you’re building a signup form and want to enforce a simple rule to only allow alphabet characters (a–z) with no numbers, no spaces, no symbols.


This is a perfect use case for Regular Expressions (Regex). In this example, we use the regex pattern /^[a-z]+$/i to validate the input:


  • The pattern is wrapped inside forward slashes (/.../), this is JavaScript’s way of defining a regular expression.
  • Think of ^ and $ as boundary markers that wrap your validation logic. Without them, the pattern can match anywhere in the string — but with them, the entire string must follow the rules exactly.
  • [a-z] means allow one English letters. [a-z]+ means allow one or more English characters.
  • The i flag makes the match case-insensitive, so both uppercase and lowercase letters are accepted.

So the whole pattern matches strings made entirely of English letters (like John, Jane, or Awesome), and rejects anything else (like john_doe, 123Jane, or awesome!).


app/(pages)/username-validator/page.tsx
'use client'
import { useState } from "react"
 
export default function UsernameValidatorPage() {
 
    const [username, setUsername] = useState('');
    const isValid = /^[a-z]+$/i.test(username);
 
    return (
        <main className="flex flex-col gap-[16px] items-center justify-center h-[60vh] px-4 bg-gray-600 text-gray-200">
            <h1 className="font-semibold text-2xl">Username Validator</h1>
            <input
                type="text"
                placeholder="Enter username (a-z only)"
                value={username}
                onChange={(e) => setUsername(e.target.value)}
                className="w-[300px] py-2 px-4 bg-slate-400 text-slate-800 text-center"
            />
            {username && (
                <p className={isValid ? 'text-teal-300' : 'text-rose-300'}>
                    {username && isValid ? 'Valid Username' : 'Invalid Username'}
                </p>
            )}
        </main>
    )
}

Note:

In JavaScript, regex is commonly used with the .test() method to check whether a string matches a specific pattern. The .test() method returns a boolean, true if the pattern is found, and false if it’s not.



Example 2: Category Filtering

In this example, we introduce RegExp(). It works like /.../ but allows you to build regular expressions dynamically using variables — perfect for cases like category filters or user input.


This example demonstrates how to filter items based on a selected category using RegExp() which is handy when you need dynamic matching logic. It also introduces two helpful JavaScript methods: .flatMap() and .filter().


app/(pages)/filter-books/page.tsx
'use client'
import { useState } from "react";
 
const AllBooks = [
    {
        category: "fiction",
        books: ["fiction-01", "fiction-02", "fiction-03"],
    },
    {
        category: "crime",
        books: ["crime-01", "crime-02", "crime-03"],
    },
];
 
export default function FilterBooksPage() {
 
    const [selectedCategory, setSelectedCategory] = useState<string>("all");
 
    const getFilteredBooks = () => {
        const allBooks = AllBooks.flatMap(item => item.books);
 
        if (selectedCategory == "all") return allBooks;
 
        const pattern = new RegExp(`^${selectedCategory}-`, 'i'); // matches e.g. "fiction-"
        return allBooks.filter(title => pattern.test(title));
    }
 
    const filteredBooks = getFilteredBooks();
 
    return (
        <main className="flex flex-col gap-[16px] items-center justify-center h-[60vh] px-4 bg-gray-600 text-gray-200">
            <h1 className="font-semibold text-lg">Filter Books</h1>
            <div className="flex justify-center gap-4 mb-8">
                <button
                    onClick={() => setSelectedCategory("fiction")}
                    className="py-2 px-4 bg-teal-300 text-slate-700 hover:bg-teal-500"
                    >Fiction</button>
                <button
                    onClick={() => setSelectedCategory("crime")}
                    className="py-2 px-4 bg-teal-300 text-slate-700 hover:bg-teal-500"
                    >Crime</button>
                <button
                    onClick={() => setSelectedCategory("all")}
                    className="py-2 px-4 bg-teal-300 text-slate-700 hover:bg-teal-500"
                    >All</button>
            </div>
            <div className="flex gap-4 flex-wrap w-[400px] justify-center">
                {filteredBooks.map((book, index) => (
                    <span key={index} className="py-2 px-4 border-slate-400 border-1">{book}</span>
                ))}
            </div>
        </main>
    )
}

What This Does

Imagine you have a list of book categories, each with its own array of book titles. You want users to click on a category (e.g. Fiction or Crime), and instantly see only the books in that category.

To accomplish this:

  • We flatten all books from all categories using .flatMap().
  • We dynamically build a regex pattern with new RegExp() to match books that belong to the selected category.
  • We filter the list of all books using .filter() and the regex pattern.

const allBooks = AllBooks.flatMap(item => item.books); It goes through each item, accesses the books array (hence item.books), and flattens all of them into a single array. So when we map through allBooks, we can display all books.


We use RegExp() instead of /.../ so we can insert the selectedCategory variable into the pattern dynamically.


allBooks.filter(book => pattern.test(book)); loops through each item inside allBooks variable and returns only the ones that match the pattern effectively filtering the array based on the selected category.




Example 3: Extract Hashtags from Input

In this example, we use regex to extract hashtags in real time as the user types. The extracted hashtags are displayed as pill-style tags below the input field.


app/(pages)/filter-input/page.tsx
'use client'
import { useState } from "react"
 
export default function FilterInputPage() {
 
    const [userInput, setUserInput] = useState("");
    const hashtags = userInput.match(/#\w+/g);
 
    return (
        <div className="flex flex-col w-full max-w-[600px] h-[60vh] items-center justify-center gap-4 mx-auto bg-slate-700">
            <h1 className="font-semibold text-lg">Filter Input</h1>
            <p className="opacity-70">When you type a hashtag (like #example), it will appear as a pill below.</p>
            <input
                type="text"
                onChange={(e) => setUserInput(e.target.value)}
                className="w-[400px] py-2 px-4 bg-slate-400 text-slate-800"
                placeholder="Type hastags here..."
            />
            { hashtags && (
                <div className="flex gap-2 justify-center w-full p-4">
                    {hashtags.map((item, index) => (
                        <span key={index} className="py-1 px-2 bg-teal-400 text-slate-700 text-[14px] rounded-lg">{item}</span>
                    ))}
                </div>
            )}
        </div>
    )
}

We use the .match() method with the pattern /#\w+/g which breaks down as:


  • # = the literal hash symbol
  • \w+ = matches one or more word characters (a-z, A-Z, 0-9, and _)
  • The g flag means global, so it finds all matches in the string

JKT

Stay focused, and the rest will follow

©Jakkrit Turner. All rights reserved