javascript

How to Get the Current Page URL in React

We use the window.location.href property to get the current page URL in React.

For example:

JavaScript
import { useRef } from 'react'; export default function App() { const url = window.location.href; return ( <div> You are currently accessing url</b> </div> ); }
Displaying the current URL in React.

The window.location.href property returns a string that contains the entire page URL.

window.location contains other properties that give more information on the URL. Some of them are:

  • pathname: the path of the URL after the domain name and any optional port number.
  • protocol: the protocol scheme of the URL.
  • hostname: the hostname portion of the URL.

Here are some examples of using these properties to get various URL properties in addition to the full URL.

JavaScript
export default function App() { const url = window.location.href; const pathname = window.location.pathname; const protocol = window.location.protocol; const hostname = window.location.hostname; return ( <div> You are currently accessing <b>{url}</b><br /> Pathname: <b>{pathname}</b><br /> Protocol: <b>{protocol}</b><br /> Hostname: <b>{hostname}</b> </div> ); }
Displaying various URL properties.

Get current route in React Router

To get the current route in React Router, we use the useLocation() route.

For example:

JavaScript
import React from 'react'; import { Route, Link, Routes, useLocation } from 'react-router-dom'; function Home() { return <h2>Home</h2>; } function Products() { return <h2>About</h2>; } function Pricing() { return <h2>Pricing</h2>; } function Posts() { return <h2>Posts</h2>; } export default function App() { const location = useLocation(); const { hash, pathname, search } = location; return ( <div> <div> <Routes> <Route path="/products" element={<Products />} /> <Route path="/" element={<Home />} /> <Route path="/posts" element={<Posts />} /> <Route path="/#pricing" element={<Pricing />} /> </Routes> Pathname: <b>{pathname}</b><br /> Search params: <b>{search}</b><br /> Hash: <b>{hash}</b> <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/products">Products</Link> </li> <li> <Link to="/posts?id=5">Posts</Link> </li> <li> <Link to="/#pricing">Pricing</Link> </li> </ul> </nav> </div> </div> ); }

useLocation() returns an object that contains information on the current page URL. Some of these properties are:

  • pathname: the part that comes after the domain name, e.g., /products.
  • search: the query string, e.g., ?id=5.
  • hash: the hash, e.g., #pricing.

Note

To get the full URL, we use location.href instead of useLocation().

JavaScript
const url = window.location.href;

Get dynamic route variable in React Router

To access the variables of a dynamic route directly in React Router, we use the useParams() hook.

For example:

JavaScript
import React from 'react'; import { Route, Routes, useParams } from 'react-router-dom'; function Posts() { const { id } = useParams(); return <h2>Settings for post {id} </h2>; } export default function App() { return ( <div> <div> <Routes> <Route path="/posts/:id" element={<Posts />} /> </Routes> </div> </div> ); }
Displaying the dynamic route variable.
Displaying the dynamic route variable.

The id variable corresponds to its placeholder value in the /posts/:id path. So as you saw in the example, the path /posts/5 will result in the id having a value of 5.

Get current route in Next.js app

To get the current route in a Next.js React app, we use the useRouter() hook:

The object useRouter() returns has a route property that is the current route in the Next.js app.

pages/posts.tsx
import Head from 'next/head'; import { useRouter } from 'next/router'; export default function Posts() { const posts = ['Post 1', 'Post 2', 'Post 3']; // 👇 Get route data const { route } = useRouter(); return ( <> <Head> <title>Next.js - Coding Beauty</title> <meta name="description" content="Generated by create next app" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="icon" href="/favicon.ico" /> </Head> <main> Route: <b>{router}</b> <br /> {posts.map((post) => ( <p>{post}</p> ))} </main> </> ); }
Displaying the current route in Next.js

We use useRouter() to get data and take actions related to the current app route.

Get current dynamic route data in Next.js

To get data passed to a dynamic route, we use the query property from the useRouter() object:

For instance, we could have a route /posts/5 corresponding to a dynamic route, /posts/:id where 5 is the passed value for id.

Here’s how we’ll access it in the Next.js file that handles requests to the dynamic route:

pages/posts/[id].tsx
import Head from 'next/head'; import { useRouter } from 'next/router'; export default function Posts() { const { query } = useRouter(); // 👇 Get id value from dynamic route const { id } = query; return ( <> <Head> <title>Next.js - Coding Beauty</title> <meta name="description" content="Generated by create next app" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="icon" href="/favicon.ico" /> </Head> <main> <h2> Post <b>{id}</b> </h2> </main> </> ); }
Displaying the data passed with the dynamic route in Next.js

For the dynamic route to work, the file structure in the pages folder has to be like this: /pages/[id].tsx. We name the file according to what property we’ll use to access the data from the query, and we wrap the name in square brackets.

We use useRouter() to get data and take actions related to the current app route.

Get query parameter data in Next.js

We can also access URL query parameters (i.e., ?key1=value1) using the query object:

JavaScript
import Head from 'next/head'; import { useRouter } from 'next/router'; export default function Posts() { const { query } = useRouter(); // 👇 Get source from query params const { id, source } = query; return ( <> <Head> <title>Next.js - Coding Beauty</title> <meta name="description" content="Generated by create next app" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="icon" href="/favicon.ico" /> </Head> <main> <h2> Post <b>{id}</b> </h2> <h3>You came from {source}!</h3> </main> </> ); }
Display data passed with URL query parameters in Next.js

Key takeaways

In React, we can use window.location.href to get the current page URL, and useLocation() to get information on the current route in React Router. For dynamic routes, useParams() accesses the values of a dynamic route directly.

For Next.js, we use the useRouter() hook to get info on the current route. From the object, it returns, route has the current route, and query gives us info on data passed to the app with the URL, like dynamic route and query parameter data.

How to Fix the “require() of ES modules is not supported” Error in Node.js

Are you experiencing the “require() of ES modules is not supported” error (ERR_REQUIRE_ESM) in Node.js? This error happens when you try to import a package that is an ES-only module with the CommonJS require() syntax:

The "require() of ES modules is not supported (ERR_REQUIRE_ESM)" error happening.
The “require() of ES modules is not supported” error occurred.

To fix it, use the ES module import syntax for the module, or install a previous version of the package that supports require().

Use ES module import syntax

The ES module system is now the standard method for bundling JavaScript code for sharing and reusing. An ES module can only be used by other ES modules.

So to import ES modules into our project, we first have to define the project as an ES module too. We do this by setting the type field in our package.json file to "module".

JSON
{ "type": "module", // other fields... }

Once we do this, we can use the ES import syntax for the module, like this:

JavaScript
import chalk from 'chalk';

Note

If we don’t make our project an ES module, you’ll get another error:

The "Cannot use import statement outside a module" error occurred.

So this step is required.

Use async import() function

Another way you can fix the “require() of ES modules is not supported” error is to use the async import function that allows you to dynamically load modules:

For example, here’s how we can do it for chalk:

JavaScript
(async () => { const chalk = (await import('chalk')).default; console.log(chalk.blue('Coding Beauty')); })();

And this works:

Install previous version of package

It’s possible that the package used to support require() but no longer does. Maybe a popular package like chalk or node-fetch. In that case, you can also fix “require() of ES modules is not supported” error in Node.js by installing one of those versions that support require().

As the ES module format become more popular and we saw all the benefits, many popular libraries on NPM started to drop support for CommonJS. Unlike CommonJS, ES modules provide more flexible and powerful module system features like asynchronous loading and tree shaking (removing unused code at build time).

Here are the versions you should install for various well-known NPM packages to use CommonJS and require():

The version of popular packages to install that last supported CommonJS.

node-fetch

Install node-fetch version 2:

JavaScript
npm install [email protected] # Yarn yarn add [email protected]

Note: Specify only the major version (use 2, not 2.x.x) so you can get all the latest important bug fixes published for version 2.

got

Install got version 11:

JavaScript
npm install [email protected] # Yarn yarn add [email protected]

Note: Unlike node-fetch, got v11 is not being maintained anymore.

chalk

Install chalk version 4:

JavaScript
npm install [email protected] # Yarn yarn add [email protected]

nanoid

Install nanoid version 3:

JavaScript
npm install [email protected] # Yarn yarn add [email protected]

Others

If the package isn’t among the ones above, try browsing through its homepage or NPM package page to find any notices of dropped CommonJS support.

Conclusion

The “require() of ES modules is not supported” error occurs in Node.js when we attempt to use CommonJS require() on a package that is now an ES module. To fix it, we can use the ES module import syntax for the module, use the async import() function, or install a previous version of the package that supports require(). The ES module system is better as it provides powerful features like asynchronous loading and tree shaking, making it the preferred method for bundling JavaScript code.

How to Get the Sum of an Array in JavaScript

To get the sum of an array in JavaScript, call the reduce() method on the array, with two arguments: a callback that takes two arguments and returns their sum, and 0.

For example:

JavaScript
const sum = (arr) => arr.reduce((a, b) => a + b, 0); const arr = [1, 2, 3, 4, 5] const result = sum(arr); console.log(arr); // 15

When we call reduce() method on arr, it loops through the array and adds each element to a sum value When the loop is done, this value will hold the total sum of the array, and reduce() will return it.

The callback argument is called on each array element and takes two arguments, a and b. a represents the total sum value so far and b represents the current element in the iteration. The callback simply adds the current element to the total sum value so far and returns it.

The second argument reduce() takes is an initial value of the total sum. We set it to 0 in this case, but this is the default value anyway, so we can leave it out:

JavaScript
// No need for second argument when it's zero const sum = (arr) => arr.reduce((a, b) => a + b); const arr = [1, 2, 3, 4, 5] const result = sum(arr); console.log(arr); // 15

Get sum of array with for..of loop

Alternatively, we can get the sum of an array in JavaScript using a for..of loop and taking these steps:

  1. Create a variable to store the sum.
  2. Loop over the array.
  3. Add each element to the sum.

For example:

JavaScript
function sum(arr) { let result = 0; for (const item of arr) { result += item; } return result; } const arr = [1, 2, 3, 4, 5] const result = sum(arr); console.log(arr); // 15

Throughout the loop, item will hold the value of each array element, so we add its value to sum in each iteration.

Get sum of numbers with forEach() method

Of course, wherever we can use for..of we can use forEach():

JavaScript
function sum(arr) { let result = 0; arr.forEach(item => { result += item; }); return result; } const arr = [1, 2, 3, 4, 5] const result = sum(arr); console.log(result); // 15

The forEach() loops over each element in the arr array. It takes a callback function as its argument that is called on each element of the array. Like we did with for..of, the callback function simply adds the current element to the result variable.

Get sum of numbers with for loop

And forEach() or for...of can equally be replaced with the traditional for loop:

JavaScript
function sum(arr) { let result = 0; for (let i = 0; i < arr.length; i++) { result += arr[i]; } return result; } const arr = [1, 2, 3, 4, 5] const result = sum(arr); console.log(result); // 15

How do they compare in speed?

We performed a test to compare the running times of the four different methods above for summing an array in JavaScript: the for loop, forEach(), for...of loop, and reduce() methods.

We tested each method three times and noted how long it took to complete each test. Then we averaged the results to get a more accurate representation of the execution times.

Each test case involved summing an array of the first 1 million positive integers.

Speed comparison of the different methods of getting the sum an array in JavaScript.
Speed comparison of the different methods.

The for loop method was the fastest, taking only an average of 4.530 ms to complete. The forEach() method was the slowest, with an average execution time of 31.123 ms. The for...of loop and reduce() methods were relatively close in execution time, with average execution times of 22.940 ms and 21.463 ms, respectively.

Overall, the for loop method was the most efficient for summing an array in JavaScript, while the forEach() method was the least efficient. Still, the best method to use depends on your specific use case and the array’s size.

When dealing with small arrays, the difference in performance between different methods for summing the array may not be noticeable. But as the size of the array increases, this difference can become more significant and can affect the code’s overall running time.

So for very large arrays, it’s important that we choose the most efficient method for computing the sum to avoid slow execution times. By choosing the most efficient method, we’ll make sure that our code runs as quickly and efficiently as possible, even when dealing with huge amounts of data.

structuredClone(): The Easiest Way to Copy Objects in JavaScript

Cloning objects is a regular programming task for storing or passing data. Until recently, developers have had to rely on third-party libraries to perform this operation because of advanced needs like deep-copying or keeping circular references.

Fortunately, that’s no longer necessary, thanks to the new built-in method called structuredClone(). This feature provides an easy and efficient way to deep-clone objects without external libraries. It works in most modern browsers (as of 2022) and Node.js (as of v17).

In this article, we will explore the benefits and downsides of using structuredClone() function to clone objects in JavaScript.

How to use structuredClone()

structuredClone() works very intuitively; pass the original object to the function, and it will return a deep copy with a different reference and object property references.

JavaScript
const obj = { name: 'Mike', friends: [{ name: 'Sam' }] }; const clonedObj = structuredClone(obj); console.log(obj.name === clonedObj); // false console.log(obj.friends === clonedObj.friends); // false

Unlike the well-known JSON stringify/parse “hack”, structuredClone() lets you clone circular references.

JavaScript
const car = { make: 'Toyota', }; car.basedOn = car; const cloned = structuredClone(car); console.log(car.basedOn === cloned.basedOn); // false // 👇 Circular reference is cloned console.log(car === car.basedOn); // true

Advantages of structuredClone()

So, what makes structuredClone() so great? Well, we’ve been saying it right from the intro; it allows you to make deep copies of objects without difficulty. You don’t need to install any third-party libraries or use JSON.stringify/parse to do so.

With structuredClone(), you can clone objects that have circular references, which is something that’s not possible with the JSON approach. You can clone complex objects and data structures with ease.

structuredClone() can deep copy for as many levels as you need; it creates a completely new copy of the original object with no shared references or properties. This means that any changes made to the cloned object won’t affect the original, and vice versa.

Limitations of structuredClone()

While structuredClone() is a powerful function for cloning objects and data structures, it does have some limitations that are worth noting.

Can’t clone functions or methods

Yes, structuredClone() cannot clone functions or methods. This is because of the structured clone algorithm that the function uses. The algorithm can’t duplicate function objects and throws a DataCloneError exception.

JavaScript
function func() {} // Error: func could not be cloned const funcClone = structuredClone(func);
JavaScript
const car = { make: 'BMW', move() { console.log('vroom vroom..'); }, }; car.basedOn = car; // ❌ Error: move() could not be cloned const cloned = structuredClone(car);

As you can see from the above example, trying to use structuredClone() on a function or an object with a method will cause an error.

Can’t clone DOM elements

Similarly, the structured clone algorithm used by structuredClone() can’t clone DOM elements. Passing an HTMLElement object to structuredClone() will cause an error like the one above.

JavaScript
const input = document.querySelector('#text-field'); // ❌ Failed: HTMLInputElement object could not be cloned. const clone = structuredClone(input);

Doesn’t preserve RegExp lastIndex property

When you clone a RegExp object with structuredClone() the lastIndex property of a RegExp is not preserved in the clone:

JavaScript
const regex = /beauty/g; const str = 'Coding Beauty: JS problems are solved at Coding Beauty'; console.log(regex.index); console.log(regex.lastIndex); // 7 const regexClone = structuredClone(regex); console.log(regexClone.lastIndex); // 0

Other limitations of structuredClone()

  • It doesn’t preserve property metadata or descriptors. For example, If a property descriptor marks an object as readonly, the clone of the object will be read/write by default.
  • It doesn’t preserve non-enumerable properties in the clone.

These limitations shouldn’t be much of a drawback for most use cases, but still, it’s important to be aware of them to avoid unexpected behavior when using the function.

Transfer value with structuredClone()

When you clone an object, you can transfer particular objects instead of making copies by using the transfer property in the second options parameter that structuredClone() has. This means you can move objects between the original and cloned objects without creating duplicates. The original object can’t be used after the transfer.

Let’s say you have some data in a buffer that you need to validate before saving. By cloning the buffer and validating the cloned data instead, you can avoid any unwanted changes to the original buffer. Plus, if you transfer the validated data back to the original buffer, it will become immutable, and any accidental attempts to change it will be blocked. This can give you extra peace of mind when working with important data.

Let’s look at an example:

JavaScript
const uInt8Array = Uint8Array.from({ length: 1024 * 1024 * 16 }, (v, i) => i); const transferred = structuredClone(uInt8Array, { transfer: [uInt8Array.buffer], }); console.log(uInt8Array.byteLength); // 0

In this example, we created a UInt8Array buffer and fill it with data. Then, we clone it using structuredClone() and transfer the original buffer to the cloned object. This makes the original array unusable, ensuring it will be kept from being accidentally modified.

Key takeaways

structuredClone() is a useful built-in feature in JavaScript for creating deep copies of objects without external libraries. It has some limitations, like not being able to clone functions, methods, or DOM elements and not preserving some type of properties in the clone. You can use the transfer option to move objects between the original and cloned objects without creating duplicates, which can be helpful for validating data or ensuring immutability. Overall, structuredClone() is a valuable addition to a developer’s toolkit and makes object cloning in JavaScript easier than ever.

How to Fix the “structuredClone is not defined” Error in Node.js

The “structuredClone is not defined” error occurs when you try to use the structuredClone()/ method in JavaScript, but it’s not defined.

The "structuredClone is not defined" error occuring in a terminal.
The “structuredClone is not defined” error occuring in a terminal.

To fix it, install Node.js 17 or a newer version. Once you’ve updated Node.js, you can use structuredClone() to clone objects with all their properties and methods.

What causes the “structuredClone is not defined” error?

If you try to use the structuredClone() method in a script that’s running with a Node.js version lower than 17, you will encounter this error.

The structuredClone() method is used to create a deep copy of an object. It’s a built-in function in JavaScript and is used to clone an object with all its properties and methods.

But when the structuredClone() method is not defined, it means that the server environment doesn’t recognize the function and cannot perform the action.

Fix: update Node.js

To fix the “structuredClone is not defined” error in JavaScript, you need to install Node.js 17 or a newer version. If you’re using an older version of Node.js, it will throw an error when you try to use structuredClone().

Install from website

To download Node.js, visit the official website and opt for the LTS version, as it offers superior stability. As of the time of writing this article, the most recent LTS release of Node.js is v18.15.0.

The Node.js download page on the official website.
The Node.js download page on the official website.

Install with Chocolatey

If you’re using Chocolatey, Node.js is available as the nodejs package, meaning you can easily install it in a terminal using the following command.

Shell
# Use current LTS version choco install nodejs --version=18.5.0

After installing, you can use the structuredClone method to clone an object:

JavaScript
const obj = { name: 'Mike', friends: [{ name: 'Sam' }] }; const clonedObj = structuredClone(obj); console.log(obj.name === clonedObj); // false console.log(obj.friends === clonedObj.friends); // false

Key takeaways

If you get the “structuredClone is not defined” error when using the structuredClone() method in JavaScript, it means that the method is unavailable. To fix the problem, update your Node.js to a version newer than 17. You can get the latest version from the official Node.js website or install the nodejs package using Chocholatey.

How to Simulate a KeyPress in JavaScript

To simulate a keypress in JavaScript:

  1. Get the text field element with a method like document.querySelector().
  2. Create a new KeyboardEvent object.
  3. Call the dispatchEvent() method on the text field, with the KeyboardEvent object.

i.e.:

JavaScript
function simulateKeyPress(key) { const event = new KeyboardEvent('keydown', { key }); textField.dispatchEvent(event); }

“Text field” here might be an input element, textarea element, or even a content editable div.

A KeyboardEvent object describes a user’s interaction with the keyboard. Its constructor takes two arguments:

  • type – a string with the name of the event. We pass 'keydown' to indicate that it’s the event of a key press.
  • options – an object used to set various properties of the event. We used the object’s key to set the keyboard key name associated with our key press.

For example:

HTML
<input type="text" name="text-field" id="text-field" placeholder="Text field" /> <br /> Key presses: <span id="key-presses">0</span> <br /><br /> <button id="simulate">Simulate</button>
JavaScript
const textField = document.querySelector('#text-field'); const keyPresses = document.getElementById('key-presses'); const keyPressed = document.getElementById('key-pressed'); const simulate = document.getElementById('simulate'); // Set 'keydown' event listener, for testing purposes let keyPressCount = 0; textField.addEventListener('keydown', (event) => { keyPressCount++; keyPresses.textContent = keyPressCount; keyPressed.textContent = event.key; }); simulate.addEventListener('click', () => { simulateKeyPress('a'); }); function simulateKeyPress(key) { const event = new KeyboardEvent('keydown', { key }); textField.dispatchEvent(event); }

First, we use selector methods like document.querySelector() and document.getElementById() to get an object representing the various elements to be used in the JavaScript code.

Then, we call the addEventListener() method on the text field object to set an event listener for the keydown event. When the user types a key or input is simulated from a script, the event listener will be fired, incrementing the key press count and displaying the most recently pressed key.

We also call the addEventListener() method on the simulate button object for the click event to simulate the key press when the user clicks the button.

Simulating a keypress fires the key event.
Simulating a keypress fires the key event.

Notice that the key is not entered in the text field. This is because of the isTrusted property, which indicates whether a user action or script generated an event. When isTrusted is false, the event is not considered trusted and does not reflect visually in the text field. Browsers do this for security reasons.

JavaScript
const event = new KeyboardEvent('keydown', { key, ctrlKey: true }); console.log(event.isTrusted); // false

isTrusted is a readonly property and will only be true when an actual user’s action caused the event; in this case: typing on the keyboard.

Insert value into input field or textarea

If you want to enter a key into the text field programmatically, you’ll have to use other approaches. For input and textarea elements, here’s a method you can use:

JavaScript
function insertTextAtCursor(element, text) { element.focus(); const startPos = element.selectionStart; const endPos = element.selectionEnd; element.value = element.value.substring(0, startPos) + text + element.value.substring(endPos, element.value.length); element.selectionStart = element.selectionEnd = startPos + text.length; }

This function takes the text field element and some text as arguments and inserts the text into the text field, replacing any highlighted text before the insertion.

You can also use the insert-text-at-cursor NPM package to insert text into an input field or textarea. Its default export function works like the one above.

JavaScript
import insertTextAtCursor from 'insert-text-at-cursor';

Either function can be called like this:

JavaScript
insertTextAtCursor(textField, 'Coding Beauty');

Simulate keypress in input field with key modifier

Sometimes, you might want to simulate a key combination that includes the modifier keys, e.g., Ctrl + A, Ctrl + Shift + C, etc. There are option properties you can set to do this.

For instance, setting the ctrlKey property to true simulates the Ctrl + {key} combination, where {key} is the value assigned to the key property.

JavaScript
// Ctrl + c, Ctrl + o, Ctrl + d, Ctrl + e const keysToSend = 'code'; let keyIndex = 0; simulate.addEventListener('click', () => { simulateKeyPress(keysToSend.at(keyIndex++) || keysToSend.at(-1)); }); function simulateKeyPress(key) { const event = new KeyboardEvent('keydown', { key, ctrlKey: true }); textField.dispatchEvent(event); }
Simulating various keys with the Ctrl modifier.
Simulating various key combinations with the Ctrl modifier.

Some other important key modifier option properties are:

  • altKey: adds the Alt key to the key combination, e.g., Alt + Z, Ctrl + Alt + N, etc.
  • ctrlKey: adds the Ctrl key to the key combination, e.g., Ctrl + A, Ctrl + Shift + T, etc.
  • shiftKey: adds the Shift key to the key combination.
  • metaKey: adds the ⌘ key on MacOS and the Windows key on Windows to the key combination.

Key takeaways

We can easily simulate keypresses in JavaScript on a text field by calling the dispatchEvent() method on the element object, passing a custom-created KeyboardEvent object as an argument. While this will trigger the appropriate key events set on the element, it would not visually reflect on the text field since programmatically created events are not trusted for security reasons.

JavaScript: ?? and || Are Not the Same

Have you ever wondered about the differences between the ?? and || operators in JavaScript? These two operators may seem similar, but they have one key difference that set them apart, and that’s what we’ll be talking about in this article.

How ?? and || differ

The || operator returns the first truthy value it encounters, or the last value in the expression if all values are falsy. For example:

JavaScript
const x = undefined || null || '' || 'hello'; console.log(x); // Output: 'hello'

In this example, the || operator returns 'hello' because it is the first truthy value in the expression.

On the other hand, the ?? operator only returns the second operand if the first operand is null or undefined. For example:

JavaScript
const x = undefined ?? null ?? '' ?? 'hello'; console.log(x); // Output: ''

In this example, the ?? operator returns "" because it is the first defined value in the expression.

Tip: Falsy values in JavaScript are null, undefined, false, 0, NaN, and '' (empty string). Every other value is truthy, and will be coerced to true in a Boolean() constructor.

In this example, the ?? operator returns '' because it is the first value that is not null/undefined in the expression.

When to use the null coalescing (??) operator

One common use case for ?? is when you want to treat certain values, such as 0 or empty strings (''), as literal values instead of the absence of a value. In these cases, ?? can be used to provide a fallback value only when a value is strictly null or undefined.

For example, let’s say we have a function paginate that takes an options object as an argument, and returns an array of numbers up to a certain limit. We want to provide a default limit of 3 if no limit is provided, and return an empty array if the limit is set to 0. We can use the ?? operator to achieve this:

JavaScript
function paginate(options = {}) { return ['a', 'b', 'c', 'd', 'e'].splice(0, options.limit ?? 3); } paginate(1); // Output: ['a'] paginate(); // Output: ['a', 'b', 'c'] paginate(0); // Output: []

In this example, if options.limit is null or undefined, the ?? operator falls back to the default value of 3. However, if options.limit is 0, the ?? operator returns 0 instead of the default value. This is because 0 is a literal value, meant to indicate that no pages should be returned in the result. In constrast, if we had used the || operator, paginate would have used the default value of 3 for the pagination.

When to use the logical OR (||) operator

Now that we’ve covered the use cases for the ?? operator, let’s take a look at when to use the || operator instead.

The || operator is useful when we want to provide a default value for a variable or function parameter that is falsy. For example, let’s say we have a function called getUsername that takes in a userInput parameter. If userInput is falsy, we want to return a default value of “Guest”. We can use the || operator to achieve this in a concise way, like so:

JavaScript
function getUsername(userInput) { return userInput || 'Guest'; }

Key takeways

Both the ?? and || operators are useful in providing default values and handling falsy values in JavaScript. However, the ?? operator is better suited for cases where values like 0 and empty strings should be treated literally instead of being treated as an indication of an absent value. On the other hand, the || operator is useful for providing fallback values when a value is missing or falsy. By understanding the differences and appropriate use cases of each operator, you can avoid unexpected bugs in your code.

How to Set Focus on the Next Form Input With JavaScript

To move focus from one input to the next one in a form:

  1. Get a list of all the input elements in the form.
  2. Get the index of the input element in the list that has focus.
  3. Get the index of the next input element in the list.
  4. Focus on it.
JavaScript
function focusNext() { const currInput = document.activeElement; const currInputIndex = inputs.indexOf(currInput); const nextinputIndex = (currInputIndex + 1) % inputs.length; const input = inputs[nextinputIndex]; input.focus(); }

For example:

HTML
<form class="form"> <input type="number" name="num1" id="num1" placeholder="1st Number" maxlength="2" /> <input type="number" name="num2" id="num2" placeholder="2nd Number" maxlength="3" /> <input type="number" name="num3" placeholder="3rd Number" id="num3" maxlength="4" /> <button type="submit" id="submit-btn">Submit</button> </form>
CSS
.form { display: flex; flex-direction: column; width: 200px; } .form input:not(:first-of-type) { margin-top: 10px; } .form #submit-btn { margin-top: 20px; }
JavaScript
// Convert NodeList to Array with slice() const inputs = Array.prototype.slice.call( document.querySelectorAll('.form input') ); inputs.forEach((input) => { input.addEventListener('keydown', (event) => { const num = Number(event.key); if (num && num >= 0 && num <= 9) { // Only allow numbers if (input.value.length >= input.maxLength) { event.preventDefault(); focusNext(); } } }); }); function focusNext() { const currInput = document.activeElement; const currInputIndex = inputs.indexOf(currInput); const nextinputIndex = (currInputIndex + 1) % inputs.length; const input = inputs[nextinputIndex]; input.focus(); }
The next input gains focus when the input limit is reached.
The next input gains focus when the input limit is reached.

We use the document.querySelectorAll() method to obtain a collection of all the input elements in the form. This method in JavaScript allows you to find all the elements on a web page that match a certain pattern or characteristic, such as all elements with a particular class name or tag name.

We use the forEach() method to iterate over the array of input elements we obtained using document.querySelectorAll(). For each input element, we add an event listener to listen for the keydown event.

When a key is pressed down, we check if the key pressed is a number between 0 and 9. If it is, we check if the length of the input’s value is equal to its maxLength attribute. If it is, we prevent the default action of the event and call the focusNext() function to move the focus to the next input element.

The forEach() method is a higher-order function in JavaScript that allows you to run a function on each element of an array.

Tip: A higher-order function is a function that can take in functions as arguments and/or return a function.

In the focusNext() function, we first get the currently focused input element using document.activeElement. We then get the index of this input element in the inputs array we created earlier using inputs.indexOf(currInput).

We then calculate the index of the next input element in the array using (currInputIndex + 1) % inputs.length, where % is the modulo operator. This ensures that if the currently focused input element is the last one in the array, we wrap around to the first input element.

Finally, we get a reference to the next input element using inputs[nextinputIndex] and call the focus() method on it to move the focus to the next input element.

Set focus on next input on enter

Sometimes, we want to move the focus to the next input element when the user presses the Enter key instead of waiting for the input’s maxLength to be reached. To do this, we can add an event listener to listen for the keydown event on each input element. When the Enter key is pressed, we prevent the default action of the event and call the focusNext() function to move the focus to the next input element.

JavaScript
inputs.forEach((input) => { input.addEventListener('keydown', (event) => { if (event.key === 'Enter') { event.preventDefault(); focusNext(); } }); });

Now, when the user presses the Enter key, the focus will move to the next input element. This can be especially useful in forms where the user needs to quickly move through a series of inputs without having to manually click on each one.

Get Started with MutationObserver: Everything You Need to Know

The MutationObserver API allows tracking changes to the DOM tree, including when elements are added, removed, modified, or have an attribute changed. It can also track changes to an element’s contents or styles, such as the addition or deletion of text or when a style property is modified.

We’ll look at how to use the Mutation API in this article and real-world use cases to see its importance.

Mutation Observer in action

Let’s look at the Mutation Observer API in action right away:

JavaScript
// Usage const observer = new MutationObserver((mutations) => { for (const mutation of mutations) { const el = mutation.target; if (el.textContent === 'Hello!') { el.textContent = 'Welcome!'; } } }); const textEl = document.getElementById('info'); observer.observe(textEl, { childList: true }); // Test const changeText = document.getElementById('change-text'); changeText.addEventListener('click', () => { textEl.textContent = 'Hello!'; });
The displayed text is changed by Mutation Observer.
The displayed text is changed by Mutation Observer.

Create a Mutation Observer

We create a Mutation Observer using the MutationObserver() constructor. The constructor accepts a callback that will be called when a mutation is detected on an element.

The callback is passed an array of MutationRecord objects, each containing information about the particular mutation that just occurred.

JavaScript
const observer = new MutationObserver((mutations) => { for (const mutation of mutations) { // Process mutations... } });

Two essential properties that a MutationRecord object has are the target and type property.

The target property holds the element that was mutated and type contains the type of mutation that just occurred. We can use these two properties to identify what kind of mutation happened and take the appropriate action.

For instance, we can check if the mutation was an attribute change, a child node change, or a text node change and then act accordingly. type can take the following values:

  • attributes: attribute change
  • characterData: text node change
  • childList: child node change

We can then use this data to take the appropriate action in our callback. For example, if a change to an element’s child nodes is detected, we can update the UI to reflect the new changes.

JavaScript
const observer = new MutationObserver((mutations) => { for (const mutation of mutations) { const type = mutation.type; const element = mutation.target; console.log(`${mutation.type} mutation on element #${element.id}`); } });

Observe changes with Mutation Observer

Once we have created a Mutation Observer, we can use the observe() method to start observing changes in an element. The observe() method takes two arguments: the element to observe and the configuration object. The configuration object can contain options to configure what kind of mutations to watch for. These options include childList, attributes, and characterData.

For example, if we want to watch for changes in an element’s child nodes, we can set the childList option to true. Similarly, if we’re going to watch for changes to attributes and text nodes, we can set the attributes and characterData option to true respectively.

Once we have configured our Mutation Observer and started observing changes, we can react to any changes.

Stop watching for changes in element

Once we have started observing changes, we can stop watching for changes at any time by calling the disconnect() method on the Mutation Observer. This will immediately stop watching for changes in the element, and the observe() method will no longer be called. This can be useful when you no longer need to watch for changes in an element and want to free up memory and resources.

JavaScript
observer.disconnect();

Use MutationObserver in the real-world

In many cases, you may encounter an external script that brings a range of valuable features and capabilities but brings about unwanted visual effects, like displaying text with content you’d like to customize but can’t. In this type of scenario, Mutation Observer can be used as a workaround. This tool can detect when the text content is changed in the DOM and automatically replace it with something more suitable for the task.

Get all pending mutations with takeRecords()

Mutation Observer is a powerful JavaScript API that detects changes to DOM tree elements, such as added/removed components, changed attributes, altered text content, and changed styles. A practical use is to detect and customize content set by external scripts. Create a Mutation Observer with a callback function and use observe() it to start monitoring and disconnect() to end it. takeRecords() retrieves all pending Mutation Records.

How to Get the Current Mouse Position in JavaScript

To get the current position of the mouse in JavaScript, add a mousemove event listener to the window object and access the clientX and clientY properties of the MouseEvent object in the listener to get the X and Y coordinates of the mouse respectively.

For example:

HTML
<p> Mouse pos: <b><span id="mouse-pos"></span></b> </p>
JavaScript
const mousePosText = document.getElementById('mouse-pos'); let mousePos = { x: undefined, y: undefined }; window.addEventListener('mousemove', (event) => { mousePos = { x: event.clientX, y: event.clientY }; mousePosText.textContent = `(${mousePos.x}, ${mousePos.y})`; });
The current mouse position is shown.
The current mouse position is shown.

The mousemove event is triggered on an element when the mouse hovers it. To be more precise, it is fired when the mouse is moved and the cursor’s hotspot is within the element’s bounds.

We attach the event listener to the window object to trigger the event whenever the mouse has moved anywhere on the page.

The mousemove event listener receives a MouseEvent object used to access information and perform actions related to the event. We use the clientX and clientY properties of this object to get the position of the mouse on the X-coordinate and Y-coordinate respectively in the application’s viewport.

Get current mouse position relative to element in React

In the first example, we get the current mouse position in global coordinates. In global coordinates, position (0, 0) is at the top-left of the webpage and position (Xmax, Ymin) is at the bottom right.

We might instead want to get the mouse position within the region of an element.

To get the current mouse position relative to an element, set a mousemove event handler on the element, then calculate the local X and Y positions using properties of the MouseEvent object passed to the event handler.

For example:

HTML
<div> <div class="local"> Local <br /> <b><span id="local-mouse-pos"></span></b> </div> <p> Global <br /> <b><span id="global-mouse-pos"></span></b> </p> </div>
CSS
.local { border: 1px solid #c0c0c0; padding: 75px; text-align: center; display: inline-block; margin-left: 100px; margin-top: 100px; }
JavaScript
const globalMousePosText = document.getElementById('global-mouse-pos'); const localMousePosText = document.getElementById('local-mouse-pos'); let localMousePos = { x: undefined, y: undefined }; let globalMousePos = { x: undefined, y: undefined }; window.addEventListener('mousemove', (event) => { const localX = event.clientX - event.target.offsetLeft; const localY = event.clientY - event.target.offsetTop; localMousePos = { x: localX, y: localY }; globalMousePos = { x: event.clientX, y: event.clientY }; globalMousePosText.textContent = `(${globalMousePos.x}, ${globalMousePos.y})`; localMousePosText.textContent = `(${localMousePos.x}, ${localMousePos.y})`; });

Now the resulting X and Y coordinates will be relative to the element. For example, position (0, 0) will be at the top left of the element, not the viewport:

The current mouse position relative to the element in shown.
The current mouse position relative to the element is shown.

We subtract the offsetLeft property of the element from the clientX property of the MouseEvent object to get the position on the X-axis relative to the element.

Similarly, to get the position on the Y-axis, we subtract the offsetTop property from the clientY property of the MouseEvent object.

JavaScript
window.addEventListener('mousemove', (event) => { const localX = event.clientX - event.target.offsetLeft; const localY = event.clientY - event.target.offsetTop; localMousePos = { x: localX, y: localY }; // ... });

The offsetLeft property returns the number of pixels between the left position of an element and its parent.

Likewise, the offsetTop property returns the number of pixels between the top position of an element and its parent.