tutorial

Incredible infinite scroll with JavaScript

Infinite scroll: Loading more and more content as the user scrolls down to the end.

No need for pagination + increases time spent on the site

With simple JavaScript we can recreate this easily:

We start with the basic HTML:

HTML
<div id="load-trigger-wrapper"> <!-- Grid of images> <div id="image-container"></div> <!-- Intersection Observer observes this --> < <div id="load-trigger"></div> </div> <!-- Number of loading images --> <div id="bottom-panel"> Images: &nbsp;<b><span id="image-count"></span> &nbsp;</b>/ &nbsp;<b><span id="image-total"></span></b> </div>

Now it’s time to detect scrolling to the end with the Intersection Observer API:

JavaScript
const loadTrigger = document.getElementById('load-trigger'); // ... const observer = detectScroll(); // ... // Detect when function detectScroll() { const observer = new IntersectionObserver( // Callback also runs after observe() (entries) => { for (const entry of entries) { // ... loadMoreImages(); // ... } }, // Set "rootMargin" because of #bottom-panel height // 30px upwards from the bottom { rootMargin: '-30px' } ); // Start watching #load-trigger div observer.observe(loadTrigger); return observer; }

Now let’s show the initial skeleton images:

JavaScript
const imageClass = 'image'; const skeletonImageClass = 'skeleton-image'; // ... // This function would make requests to an image server function loadMoreImages() { const newImageElements = []; // ... for (let i = 0; i < amountToLoad; i++) { const image = document.createElement('div'); // 👇 Display each image with skeleton-image class image.classList.add(imageClass, skeletonImageClass); // Include image in container imageContainer.appendChild(image); // Store in temp array to update with actual image when loaded newImageElements.push(image); } // ... }
CSS
.image, .skeleton-image { height: 50vh; border-radius: 5px; border: 1px solid #c0c0c0; /* Three per row, with space for margin */ width: calc((100% / 3) - 24px); /* Initial color before loading animation */ background-color: #eaeaea; /* Grid spacing */ margin: 8px; /* Fit into grid */ display: inline-block; } .skeleton-image { transition: all 200ms ease-in; /* Contain ::after element with absolute positioning */ position: relative; /* Prevent overflow from ::after element */ overflow: hidden; } .skeleton-image::after { content: ""; /* Cover .skeleton-image div*/ position: absolute; top: 0; right: 0; bottom: 0; left: 0; /* Setup for slide-in animation */ transform: translateX(-100%); /* Loader image */ background-image: linear-gradient(90deg, rgba(255, 255, 255, 0) 0, rgba(255, 255, 255, 0.2) 20%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0)); /* Continue animation until image load*/ animation: load 1s infinite; } @keyframes load { /* Slide-in animation */ 100% { transform: translateX(100%) } }

Update skeleton images

We get colors instead of images.

JavaScript
function loadMoreImages() { // ... // Create skeleton images and stored them in "newImageElements" variable // Simulate delay from network request setTimeout(() => { // Colors instead of images const colors = getColors(amountToLoad); for (let i = 0; i < colors.length; i++) { const color = colors[i]; // 👇 Remove skeleton loading indicator and show color newImageElements[i].classList.remove(skeletonImageClass); newImageElements[i].style.backgroundColor = color; } }, 2000); // ... } function getColors(count) { const result = []; let randUrl = undefined; while (result.length < count) { // Prevent duplicate images while (!randUrl || result.includes(randUrl)) { randUrl = getRandomColor(); } result.push(randUrl); } return result; } function getRandomColor() { const h = Math.floor(Math.random() * 360); return `hsl(${h}deg, 90%, 85%)`; }

Stop infinite scroll

This is a demo so we’ll have a artificial number of images like 50.

JavaScript
const imageCountText = document.getElementById('image-count'); // ... let imagesShown = 0; // ... function loadMoreImages() { // ... const amountToLoad = Math.min(loadLimit, imageLimit - imagesShown); // Load skeleton images... // Update skeleton images... // Update image count imagesShown += amountToLoad; imageCountText.innerText = imagesShown; if (imagesShown === imageLimit) { observer.unobserve(loadTrigger); } }

Optimize performance with throttling

By using a throttle function to only allow new loadings within a certain time.

JavaScript
let throttleTimer; // Only one image batch can be loaded within a second const throttleTime = 1000; // ... function throttle(callback, time) { // Prevent additional calls until timeout elapses if (throttleTimer) { console.log('throttling'); return; } throttleTimer = true; setTimeout(() => { callback(); // Allow additional calls after timeout elapses throttleTimer = false; }, time); }

By calling throttle() in the Intersection Observer’s callback with a time of 1000, we ensure that loadMoreImages() is never called multiple times within a second.

JavaScript
function detectScroll() { const observer = new IntersectionObserver( (entries) => { // ... throttle(() => { loadMoreImages(); }, throttleTime); } } }, // ... ); // ... }

structuredClone(): The easiest way to deep copy objects in JavaScript

Deep copying is a regular programming task for passing or storing data.

  • Shallow copy: Only copies the first level of the object
  • Deep copy: Copies all levels of the object
JavaScript
const obj = { name: 'Tari', friends: [{ name: 'Messi'}]}; const shallowCopy = { ...obj }; const deepCopy = dCopy(obj); console.log(obj.friends === shallowCopy.friends); // ❌ true console.log(obj.friends === deepCopy.friends); // ✅ false

But all this while we’ve never had a built-in way to perfectly deep copy objects and it’s been a pain.

We always had to lean on third-party libraries for deep copying and keeping circular references.

All that changes now with the new structuredClone() — an easy and efficient way to deep copy any object.

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

Cloning circular references with ease:

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

Something you could never do with the JSON stringify/parse hack:

Go as deep as you want:

JavaScript
// ↘️ const obj = { a: { b: { c: { d: { e: 'Coding Beauty', }, }, }, }, }; const clone = structuredClone(obj); console.log(clone.a.b.c.d === obj.a.b.c.d); // ✅ false console.log(clone.a.b.c.d.e); // Coding Beauty

Limitations you should know

structuredClone() is very powerful but it has important weaknesses you should know:

Can’t clone functions or methods

Because of the special algorithm it uses.

Can’t clone DOM elements

Doesn’t preserve RegExp lastIndex property

I mean, no one’s cloning regexes but it’s one to note:

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

Important to be aware of them to avoid unexpected behavior when using the function.

Clone some, move

This is a more sophisticated one.

You transfer inner objects from source to clone instead of copying.

Which means there’s nothing left in source to change:

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

Overall structuredClone() is a valuable addition to a developer’s toolkit and makes object cloning easier than ever in JavaScript

Recreate the Material Design text field with HTML, CSS, and JavaScript

No doubt you’ve seen the beautiful text field if you’re one of Gmail’s 2 billion active users:

It’s fluid, it’s intuitive, it’s colorful 🎨.

It’s Material Design: the wildly popular UI design system powering YouTube, WhatsApp, and many other apps with billions of users.

Let’s embark on a journey of recreating it from scratch with pure vanilla HTML, CSS, and JavaScript.

1. Start: Create basic input and label

As always we start with the critical HTML foundation, the skeleton:

The text input, a label, and a wrapper for both:

HTML
<!-- For text animation -- soon --> <div class="input-container"> <input type="text" id="fname" name="fname" value="" aria-labelledby="label-fname" /> <label class="label" for="fname" id="label-fname"> <div class="text">First Name</div> </label> </div>

2. Style input and label

I find it pretty satisfying: using CSS to gradually flesh out a stunning UI on the backs of a solid HTML foundation.

Let’s start:

Firs the <input> and its container:

CSS
.input-container { position: relative; /* parent of .label */ } input { height: 48px; width: 280px; border: 1px solid #c0c0c0; border-radius: 4px; box-sizing: border-box; padding: 16px; } .label { /* to stack on input */ position: absolute; top: 0; bottom: 0; left: 16px; /* match input padding */ /* center in .input-container */ display: flex; align-items: center; } .label .text { position: absolute; width: max-content; }

3. Remove pointer events

It resembles a text field now, but look what happens when I try focusing:

The label is part of the text field and the cursor should reflect that:

Solution? cursor: text

CSS
.label { ... cursor: text; /* Prevent blocking <input> focus */ pointer-events: none; }

4. Style input font

Now it’s time to customize font settings:

If you know Material Design well, you know Roboto is at the center of everything — much to the annoyance of some.

We’ll grab the embed code from Google Fonts:

Embed:

Use:

CSS
input, .label .text { font-family: 'Roboto'; font-size: 16px; }

5. Style input on focus

You’ll do this with the :focus selector:

CSS

input:focus {
  outline: none;
  border: 2px solid blue;
}

6. Fluidity magic: Style label on input focus

On focus the label does 3 things:

  1. Shrinks
  2. Move to top input border
  3. Match input border color

Of course we can do all these with CSS:

CSS
input:focus + .label .text { /* 1. Shrinks */ font-size: 12px; /* 2. Move to top input border */ transform: translate(0, -100%); top: 15%; padding-left: 4px; padding-right: 4px; /* 3. Match input border color */ background-color: white; color: #0b57d0; }

All we need to complete the fluidity is CSS transition:

CSS
label .text { transition: all 0.15s ease-out; }

7. One more thing

Small issue: The label always goes to the original position after the input loses focus:

Because it depends on CSS :focus which goes away on focus lost.

But this should only happen when there’s no input yet.

CSS can’t fix this alone, we’re going to deploy the entire 3-tiered army of web dev.

HTML: input value to zero.

HTML
<input type="text" id="fname" name="fname" value="" aria-labelledby="label-fname" />

CSS: :not selector to give unfocused input label same position and size when not empty:

JavaScript
input:focus + .label .text, /* ✅ no input yet */ :not(input[value='']) + .label .text { /* 1. Shrink */ font-size: 12px; transform: translate(0, -100%); /* 2. Move to top */ top: 15%; padding-left: 4px; padding-right: 4px; /* 3. Active color */ background-color: white; color: #0b57d0; }

And JavaScript: Sync initial input value attribute with user input

JavaScript
const input = document.getElementById('fname'); input.addEventListener('input', () => { input.setAttribute('value', input.value); });
JavaScript
const input = document.getElementById('fname'); input.addEventListener('input', () => { input.setAttribute('value', input.value); });

That’s it! We’ve successfully created an outlined Material Design text field.

With React or Vue it’ll be pretty easy to abstract everything we’ve done into a reusable component.

Here’s the link to the full demo: CodePen

10 rare HTML tags that nobody ever uses

There’s way more to HTML than <div>, <a>, and <p>.

So much more sophisticated and powerful tags that you’ve probably never used.

From modern list visualization to 🎨 colorful highlights, let’s look at 10 little-known but capable HTML tags.

1. abbr

The <abbr> tag defines an abbreviation or acronym, like HTML, CSS, and JS.

And LOL too – though that’s more of a standalone word these days.

I'm reading about
<abbr title="Hypertext Markup Language">HTML</abbr>
tags at
<abbr title="Coding Beauty">CB</abbr>
The abbreviation is indicated with a dotted line by default.
Dotted line for abbreviation.

We use the title attribute of the <abbr> tag to show the description of the abbreviation/acronym when you hover over the element:

Hover over <abbr> to show the full form:

Hovering over the <abbr> element.

2. q

The <q> tag indicates that the text inside of it is a short inline quotation.

<q>Coding creates informative tutorials on Web Development technologies</q>

Modern browsers typically implement this tag by wrapping the enclosed text in quotation marks:

The text in the <q> tag is wrapped with quotation marks.

3. s

<s> strikes through.

To correct without destroying the change history.

Buy for <s>$200</s> $100
Indicating price change with the <s> tag.

The <del> and <ins> pair are similar but semantically meant for document updates instead of corrections.

<!DOCTYPE html>
<html lang="en">
  <head>
    <style>
      del {
        background-color: lightsalmon;
      }

      ins {
        text-decoration: none;
        background-color: lightgreen;
      }
    </style>
  </head>
  <body>
    My favorite programming language is <del>JavaScript</del>
    <ins>TypeScript</ins>
  </body>
</html>
Indicating editorial changes in a document with the <del> and <ins> tags.
Indicating editorial changes in a document with the <del> and <ins> tags.

4. mark

Marks or highlights text.

Coding <mark>Beauty</mark> Website

Yellow background color by default:

The <mark> tag applies a bright yellow background to its enclosed text.

Like how browsers show search results.

Display search results for the letter "e" with the <mark> tag.
e e e e e e ….

5. wbr

<wbr> tells browser, “You can only break text here and there”

So the browser doesn’t get lousy and start break crucial words all over the place.

That’s why it’s wbr — Word BReak Opportunity

<p>this-is-a-very-long-text-created-to-test-the-wbr-tag</p>
The text is broken at a location chosen by the browser.
Browser is joking around.

But now with <wbr />

<p>this-is-a-very-long-te<wbr />xt-created-to-test-the-wbr-tag</p>

Broken precisely after ...-te:

The text is broken at the location set with the <wbr> tag.
Obviously no reason to break there in real-world code though.

6. details

<details> is all about expanding and contracting — like the universe.

<details>
  <summary>Lorem Ipsum</summary>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Deleniti eos
  quod fugiat quasi repudiandae, minus quae facere. Sed, quia? Quod
  cupiditate asperiores neque iste consectetur tempore eum repellat incidunt
  qui.
</details>

Contract:

A closed disclosure widget.
The disclosure widget is closed (default state).

Expand:

An open disclosure widget.
The disclosure widget is open.

7. optgroup

The name says it all — grouping options.

You can usually group gigantic option lists into clear hierarchies, and <outgroup> is here to help.

<select name="country" id="countries">
  <optgroup label="North America">
    <option value="us">United States</option>
    <option value="ca">Canada</option>
  </optgroup>
  <optgroup label="Europe">
    <option value="uk">United Kingdom</option>
    <option value="fr">France</option>
  </optgroup>
</select>

Countries → continents.

An open dropdown list contains grouped options.

8. datalist

<datalist> is all about making inputting text effortless.

With dropdown lists for autocomplete:

<form>
  <label for="lang">Choose a language:</label>
  <input list="langs" name="lang" id="lang" />

  <!-- 🔗<input> list to <datalist> id -->

  <datalist id="langs">
    <option value="English" />
    <option value="French" />
    <option value="Spanish" />
    <option value="Chinese" />
    <option value="German" />
  </datalist>
</form>
An input with an available list of options.
A list of available options for the input is displayed in a dropdown list.
An input with a responsive list of options.
The available options change according to what the user types in the input.

9. fieldset

A set of fields — farmers must find it useful.

Creating a clean visual separation to easily understand the forms.

<form>
  <fieldset>
    <legend>Name</legend>

    <label for="fname">First Name:</label>
    <input type="text" id="fname" name="fname" /><br />
    <label for="mname">Middle Name:</label>
    <input type="text" id="mname" name="mname" /><br />
    <label for="lname">Last Name:</label>
    <input type="text" id="lname" name="lname" />
  </fieldset>
  <br />
  <label for="email">Email:</label>
  <input type="email" id="email" name="email" />
  <br /><br />
  <label for="password">Password:</label>
  <input type="password" id="password" name="password" />
</form>

We use the <legend> tag to define a caption for the <fieldset> element.

Input elements, some grouped with a <fieldset> tag.

10. sup and sub

<sup> — superscript.

<sub> — subscript.

<p>This text contains <sub>subscript</sub> text</p>
<p>This text contains <sup>superscript</sup> text</p>
The text contains both subscript and superscript.

Something more intense: neutralization reaction 🧪

&#x1D465;<sup>2</sup> - 3&#x1D465; - 28 = 0. Solve for &#x1D465;. <br />
<br />
H<sub>2</sub>SO<sub>4</sub> + NaOH &#8594; Na<sub>2</sub>SO<sub>4</sub> +
H<sub>2</sub>O

Conclusion

In this article, we explored some of the least known and utilized tags in HTML. These rare tags can be quite useful in particular situations despite their low usage.

You can actually stop a “forEach” loop in JavaScript – in 5 ways

Can you break out of a “forEach” loop in JavaScript?

It’s an amazing question to challenge just how well you really know JavaScript.

Because we’re not talking for loops — or this would have been ridiculously easy: you just break:

But you wouldn’t dare do this with forEach, or disaster happens:

What about return… mhmm.

What do you think is going to happen here:

return should easily end the loop at 5 and take us to the outer log right?

Wrong:

Remember: forEach takes a callback and calls it FOR EACH item in the array.

JavaScript
// Something like this: Array.prototype.forEach = function (callback, thisCtx) { const length = this.length; let i = 0; while (i < length) { // 👇 callback run once and only once callback.call(thisCtx, this[i], i, this); i++; } };

So return only ends the current callback call and iteration; doing absolutely nothing to stop the overall loop.

It’s like here; trying to end func2() from func1() — obviously not going to work:

5 terrible ways to stop a forEach loop

1. Throw an exception

You can stop any forEach loop by throwing an exception:

JavaScript
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; try { nums.forEach((num) => { if (num === 5) { throw new Error('just to stop a loop?'); } console.log(num); }); } catch { console.log('finally stopped!'); }

Of course we’re just having fun here — this would be horrible to see in real-world code. We only create exceptions for problems, not planned code like this.

2. process.exit()

This one is extreme:

JavaScript
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; nums.forEach((num) => { if (num === 5) { process.exit(0); } console.log(num); });

Not only are you ending the loop, you’re ending the entire program!

You won’t even get to the console.log() here:

3. Array some()

This is bad.

It works and some people recommended it for this; but this lowers readability as it’s clearly not what it’s meant for.

This is what it’s meant for:

JavaScript
const nums = ['bc', 'bz', 'ab', 'bd']; const hasStartingA = nums.some((num) => num.startsWith('a') ); const hasStartingP = nums.some((num) => num.startsWith('p') ); console.log(hasStartingA); // true console.log(hasStartingP); // false

4. Set array length to 0

But here’s something even more daring: Setting the length of the array to 0!

JavaScript
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; function myFunc() { nums.forEach((num) => { if (num === 5) { nums.length = 0; } console.log(num); }); console.log('it worked!'); console.log(nums); } myFunc();

Setting the array’s length completely destroys and resets it — EMPTY array:

5. Use Array splice()

Things get even weirder when you use Array splice() to stop the foreach loop, deleting slashing away elements mid-way!

JavaScript
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; function myFunc() { nums.forEach((num, i) => { if (num === 5) { nums.splice(i + 1, nums.length - i); } console.log(num); }); console.log('spliced away!'); console.log(nums); } myFunc();

3 great ways to stop a loop

1. Do you really need to break?

Instead of using the terrible methods above to stop a forEach loop…

Why not refactor your code so you don’t need to break at all?

So, instead of this:

JavaScript
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; try { nums.forEach((num) => { if (num === 5) { // ❌ break at 5 throw new Error('just to stop a loop?'); } console.log(num); }); } catch { console.log('finally stopped!'); }

We could have simply done this:

JavaScript
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; nums.forEach((num) => { if (num < 5) { // ignore 5 or more console.log(num); } }); console.log('no need to break!');

2. Use for of

But if you really want to jump out of the loop early then you’re much better of with the for..of loop:

JavaScript
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; try { for (const num of nums) { if (num === 5) { break; // 👈 break works } console.log(num); } } catch { console.log('finally stopped!'); }

3. Use traditional for

Or with the traditional for loop, for more fine-grained control:

JavaScript
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; try { for (let i = 0; i < nums.length; i += 2) { // 👈 jump by 2 const num = nums[i]; if (num === 5) { break; } console.log(num); } } catch { console.log('finally stopped!'); }

Final thoughts

So there are ways to “break” from a forEach loop, but they’re pretty messy and insane.

Instead try refactoring the code to avoid needing to break in the first place. Or switch to for and for..of for a cleaner, readable approach.

Stop using nested ifs: Do this instead

Typical use case for nested ifs: you want to perform all sorts of checks on some data to make sure it’s valid before finally doing something useful with it.

Don’t do this! 👇

JavaScript
function sendMoney(account, amount) { if (account.balance > amount) { if (amount > 0) { if (account.sender === 'user-token') { account.balance -= amount; console.log('Transfer completed'); } else { console.log('Forbidden user'); } } else { console.log('Invalid transfer amount'); } } else { console.log('Insufficient funds'); } }

There’s a better way:

JavaScript
// ✅ function sendMoney(account, amount) { if (account.balance < amount) { console.log('Insufficient funds'); return; } if (amount <= 0) { console.log('Invalid transfer amount'); return; } if (account.sender !== 'user-token') { console.log('Forbidden user'); return; } account.balance -= amount; console.log('Transfer completed'); }

See how much cleaner it is? Instead of nesting ifs, we have multiple if statements that do a check and return immediately if the condition wasn’t met. In this pattern, we can call each of the if statements a guard clause.

If you do a lot of Node.js, you’ve probably seen this flow in Express middleware:

JavaScript
function authMiddleware(req, res, next) { const authToken = req.headers.authorization; if (!authToken) { return res.status(401).json({ error: 'Unauthorized' }); } if (authToken !== 'secret-token') { return res.status(401).json({ error: 'Invalid token' }); } if (req.query.admin === 'true') { req.isAdmin = true; } next(); }

It’s much better than this, right? :

JavaScript
function authMiddleware(req, res, next) => { const authToken = req.headers.authorization; if (authToken) { if (authToken === 'secret-token') { if (req.query.admin === 'true') { req.isAdmin = true; } return next(); } else { return res.status(401).json({ error: 'Invalid token' }); } } else { return res.status(401).json({ error: 'Unauthorized' }); } };

You never go beyond one level of nesting. We can avoid the mess that we see in callback hell.

How to convert nested ifs to guard clauses

The logic for this for doing this is simple:

1. Find the innermost/success if

Here we can clearly see it’s the cond3 if. After this, if we don’t do any more checks and take the action we’ve always wanted to take.

JavaScript
function func(cond1, cond2, cond3) { if (cond1) { if (cond2) { if (cond3) { console.log('PASSED!'); console.log('taking success action...'); } else { console.log('failed condition 3'); } } else { console.log('failed condition 2'); } } else { console.log('failed condition 1'); } }

2. Invert the outermost if and return

Negate the if condition to put the else statements’ body in there and add a return after.

Delete the else braces (keep the body, it still contains the formerly nested ifs, and move the closing if brace to just after the return.

So:

JavaScript
function func(cond1, cond2, cond3) { if (!cond1) { // 👈 inverted if condition // 👇 body of former else clause console.log('failed condition 1'); return; // 👈 exit on fail } // 👇 remaining nested ifs to convert to guard clauses if (cond2) { if (cond3) { console.log('PASSED!'); console.log('taking success action...'); } else { console.log('failed condition 3'); } } else { console.log('failed condition 2'); } }

3. Do the same for each nested if until you reach the success if

And then:

JavaScript
function func(cond1, cond2, cond3) { if (!cond1) { console.log('failed condition 1'); return; } if (!cond2) { console.log('failed condition 2'); return; } // 👇 remaining nested ifs to convert if (cond3) { console.log('PASSED!'); console.log('taking success action...'); } else { console.log('failed condition 3'); } }

And finally:

JavaScript
function func(cond1, cond2, cond3) { if (!cond1) { console.log('failed condition 1'); return; } if (!cond2) { console.log('failed condition 2'); return; } if (!cond3) { console.log('failed condition 3'); return; } console.log('PASSED!'); console.log('taking success action...'); }

I use the JavaScript Booster extension to make inverting if statements in VS Code much easier.

Here we only had to put the cursor in the if keyword and activate the Show Code Actions command (Ctrl + . by default).

Check out this article for an awesome list of VSCode extensions you should definitely install alongside with JavaScript Booster.

Tip: Split guard clauses into multiple functions and always avoid if/else

What if we want to do something other after checking the data in an if/else? For instance:

JavaScript
function func(cond1, cond2) { if (cond1) { if (cond2) { console.log('PASSED!'); console.log('taking success action...'); } else { console.log('failed condition 2'); } console.log('after cond2 check'); } else { console.log('failed condition 1'); } console.log('after cond1 check'); }

In this function regardless of cond1‘s value, the 'after cond1 check' the line will still print. Similar thing for the cond2 value if cond1 is true.

In this case, it takes a bit more work to use guard clauses:

If we try to use guard clauses, we’ll end up repeating the lines that come after the if/else checks:

JavaScript
function func(cond1, cond2) { if (!cond1) { console.log('failed condition 1'); console.log('after cond1 check'); return; } if (!cond2) { console.log('failed condition 2'); console.log('after cond2 check'); console.log('after cond1 check'); return; } console.log('PASSED!'); console.log('taking success action...'); console.log('after cond2 check'); console.log('after cond1 check'); } func(true);

Because the lines must be printed, we print them in the guard clause before returning. And then, we print it in all(!) the following guard clauses. And once again, in the main function body if all the guard clauses were passed.

So what can we do about this? How can we use guard clauses and still stick to the DRY principle?

Well, we split the logic into multiple functions:

JavaScript
function func(cond1, cond2) { checkCond1(cond1, cond2); console.log('after cond1 check'); } function checkCond1(cond1, cond2) { if (!cond1) { console.log('failed condition 1'); return; } checkCond2(cond2); console.log('after cond2 check'); } function checkCond2(cond2) { if (!cond2) { console.log('failed condition 2'); return; } console.log('PASSED!'); console.log('taking success action...'); }

Let’s apply this to the Express middleware we saw earlier:

JavaScript
function authMiddleware(req, res, next) { checkAuthValidTokenAdmin(req, res, next); } function checkAuthValidTokenAdmin(req, res, next) { const authToken = req.headers.authorization; if (!authToken) { return res.status(401).json({ error: 'Unauthorized' }); } checkValidTokenAdmin(req, res, next); } function checkValidTokenAdmin(req, res, next) { const authToken = req.headers.authorization; if (authToken !== 'secret-token') { return res.status(401).json({ error: 'Invalid token' }); } checkAdmin(req, res, next); } function checkAdmin(req, res, next) { if (req.query.admin === 'true') { req.isAdmin = true; } next(); }

In a way, we’ve replaced the if/else statements with a chain of responsibility pattern. Of course, this might be an overkill for simple logic like a basic Express request middleware, but the advantage here is that it delegates each additional check to a separate function, separating responsibilities and preventing excess nesting.

Key takeaways

Using nested ifs in code often leads to complex and hard-to-maintain code; Instead, we can use guard clauses to make our code more readable and linear.

We can apply guard clauses to different scenarios and split them into multiple functions to avoid repetition and split responsibilities. By adopting this pattern, we end up writing cleaner and more maintainable code.

The 5 most transformative JavaScript features from ES14

JavaScript has come a long way in the past 10 years with brand new feature upgrades in each one.

Still remember when we created classes like this?

JavaScript
function Car(make, model) { this.make = make; this.model = model; } // And had to join strings like this Car.prototype.drive = function() { console.log("Vroom! This " + this.make + " " + this.model + " is driving!"); };

Yeah, a lot has changed!

Let’s take a look at the 5 most significant features that arrived in ES14 (2023); and see the ones you missed.

1. toSorted()

Sweet syntactic sugar.

ES14’s toSorted() method made it easier to sort an array and return a copy without mutation.

Instead of this:

JavaScript
const nums = [5, 2, 6, 3, 1, 7, 4]; const sorted = clone.sort(); console.log(sorted); // [1, 2, 3, 4, 5, 6, 7] // ❌❌ Mutated console.log(nums); // [1, 2, 3, 4, 5, 6, 7]

We now got to do this ✅:

JavaScript
const nums = [5, 2, 6, 3, 1, 7, 4]; // ✅ toSorted() prevents mutation const sorted = nums.toSorted(); console.log(sorted); // [1, 2, 3, 4, 5, 6, 7] console.log(nums); // [5, 2, 6, 3, 1, 7, 4]

toSorted() takes a callback for controlling sorting behavior – ascending or descending, alphabetical or numeric. Just like sort().

2. Array find from last

Searching from the first item isn’t always ideal:

JavaScript
const tasks = [ { date: '2017-03-05', name: '👟run a 5k' }, { date: '2017-03-04', name: '🏋️lift 100kg' }, { date: '2017-03-04', name: '🎶write a song' }, // 10 million records... { date: '2024-04-24', name: '🛏️finally sleep on time' }, { date: '2024-04-24', name: '📝1h writing with no breaks' }, ]; const found = tasks.find((item) => item.date === '2024-03-25'); const foundIndex = tasks.findIndex((item) => item.date === '2024-03-25'); console.log(found); // { value: '2024-03-25', name: 'do 1000 pushups' } console.log(foundIndex); // 9,874,910

You can easily see that it’ll be much faster for me to search our gigantic list from the end instead of start.

JavaScript
const tasks = [ { date: '2017-03-05', name: 'run a 5k' }, { date: '2017-03-04', name: 'lift 100kg' }, { date: '2017-03-04', name: 'write a song' }, // 10 million records... { date: '2024-04-24', name: 'finally sleep on time' }, { date: '2024-04-24', name: '1h writing with no breaks' }, ]; // ✅ Much faster const found = tasks.findLast((item) => item.date === '2024-03-25'); const foundIndex = tasks.findLastIndex((item) => item.date === '2024-03-25'); console.log(found); // { value: '2024-03-25', name: 'do 1000 pushups' } console.log(foundIndex); // 9,874,910

And they’re also times you MUST search from the end for your program work.

Like we want to find the last even number in a list of numbers, find and findIndex will be incredibly off.

JavaScript
const nums = [7, 14, 3, 8, 10, 9]; // ❌ gives 14, instead of 10 const lastEven = nums.find((value) => value % 2 === 0); // ❌ gives 1, instead of 4 const lastEvenIndex = nums.findIndex((value) => value % 2 === 0); console.log(lastEven); // 14 console.log(lastEvenIndex); // 1

And calling reverse() won’t work either, even as slow as it would be:

JavaScript
const nums = [7, 14, 3, 8, 10, 9]; // ❌ Copying the entire array with the spread syntax before // calling reverse() const reversed = [...nums].reverse(); // correctly gives 10 const lastEven = reversed.find((value) => value % 2 === 0); // ❌ gives 1, instead of 4 const reversedIndex = reversed.findIndex((value) => value % 2 === 0); // Need to re-calculate to get original index const lastEvenIndex = reversed.length - 1 - reversedIndex; console.log(lastEven); // 10 console.log(reversedIndex); // 1 console.log(lastEvenIndex); // 4

So in cases like where the findLast() and findLastIndex() methods come in handy.

JavaScript
const nums = [7, 14, 3, 8, 10, 9]; // ✅ Search from end const lastEven = nums.findLast((num) => num % 2 === 0); // ✅ Maintain proper indexes const lastEvenIndex = nums.findLastIndex((num) => num % 2 === 0); console.log(lastEven); // 10 console.log(lastEvenIndex); // 4

This code is shorter and more readable. Most importantly, it produces the correct result.

3. toReversed()

Another new Array method to promote immutability and functional programming.

Before – with reverse() ❌:

JavaScript
const arr = [5, 4, 3, 2, 1]; const reversed = arr.reverse(); console.log(reversed); // [1, 2, 3, 4, 5] // ❌ Original modified console.log(arr); // [1, 2, 3, 4, 5]

Now – with toReversed() ✅:

JavaScript
const arr = [5, 4, 3, 2, 1]; const reversed = arr.toReversed(); console.log(reversed); // [1, 2, 3, 4, 5] // ✅ No modification console.log(arr); // [5, 4, 3, 2, 1]

I find these immutable methods awesome for constantly chaining methods over and over without worrying about the original variables:

JavaScript
// ✅ Results are independent of each other const nums = [5, 2, 6, 3, 1, 7, 4]; const result = nums .toSorted() .toReversed() .map((n) => n * 2) .join(); console.log(result); // 14,12,10,8,6,4,2 const result2 = nums .map((n) => 1 / n) .toSorted() .map((n) => n.toFixed(2)) .toReversed(); console.log(result2); // [ '1.00', '0.50', '0.33', '0.25', // '0.20', '0.17', '0.14' ]

4. toSpliced()

Lovers of functional programming will no doubt be pleased with all these new Array methods.

This is the immutable counterpart of .splice():

JavaScript
const colors = ['red🔴', 'purple🟣', 'orange🟠', 'yellow🟡']; // Remove 2 items from index 1 and replace with 2 new items const spliced = colors.toSpliced(1, 2, 'blue🔵', 'green🟢'); console.log(spliced); // [ 'red🔴', 'blue🔵', 'green🟢', 'yellow🟡' ] // Original not modified console.log(colors); // ['red🔴', 'purple🟣', 'orange🟠', 'yellow🟡'];

5. Array with() method

with() is our way of quickly change an array element with no mutation whatsoever.

Instead of this usual way:

JavaScript
const arr = [5, 4, 7, 2, 1] // Mutates array to change element arr[2] = 3; console.log(arr); // [5, 4, 3, 2, 1]

ES14 now let us do this:

JavaScript
const arr = [5, 4, 7, 2, 1]; const replaced = arr.with(2, 3); console.log(replaced); // [5, 4, 3, 2, 1] // Original not modified console.log(arr); // [5, 4, 7, 2, 1]

Final thoughts

They were other features but ES14 was all about easier functional programming and built-in immutability.

With the rise of React we’ve seen declarative JavaScript explode in popularity; it’s only natural that more of them come baked into the language as sweet syntactic sugar.

3 ways to show line breaks in HTML without ever using br

Of course <br/> is what we all grew up with from our HTML beginnings, but there’s more.

Like… CSS white-space: pre-wrap:

HTML
<div id="box"> Coding is cognitively demanding, mentally stimulating, emotionally rewarding, beauty, unity power </div>
CSS
#box { background-color: #e0e0e0; width: 250px; font-family: Arial; white-space: pre-wrap; }

Without pre-wrap:

pre-wrap preserves line breaks and sequences of whitespace in the element’s text.

So the 4 spaces between the words in the first line are shown in the output along with the line break.

Even the space used for text indentation is also shown in the output, adding extra left padding to the container.

JS too

pre-wrap also acknowledges the \n character when set from JavaScript; with innerText or innerHTML:

JavaScript
const box = document.getElementById('box'); box.innerText = 'Coding is \n logic, art, growth, \n creation';

Without pre-wrap:

pre

pre works a lot like pre-wrap but no more auto wrapping:

For example:

HTML
<div id="box"> JavaScript at Coding Beauty HTML at Coding Beauty CSS at Coding Beauty </div>
CSS
#box { white-space: pre; background-color: #e0e0e0; width: 250px; font-family: Arial; }

If pre was pre-wrap in this example:

The behavior with pre is the same when you set the innerHTML or innerText property of the element to a string using JavaScript.

Newlines only

white-space:pre-line: Ignore extra spaces but show line breaks:

HTML
<div id="box"> Coding is growth unity power beauty </div>
CSS
#box { background-color: #e0e0e0; width: 250px; font-family: Arial; white-space: pre-line }

pre-line -> pre-wrap:

Like the previous two possible white-space values, pre-line works in the same way when you set the innerHTML or innerText property of the element to a string using JavaScript.

Fix “Cannot read property ‘map’ of undefined” in React

Are you currently experiencing the “Cannot read property ‘map’ of undefined” error in your React app?

The "Cannot read properties of undefined (reading 'map')" error in the browser console.
The “Cannot read properties of undefined (reading ‘map’)” error in the browser console.

This error happens when you call the map() method on a variable that was meant to be an array, but is actually undefined. The variable could be a property or state variable.

For example:

JavaScript
import { useState, useEffect } from 'react'; import { fetchBooks } from './books'; function App() { // ❌ `books` is `undefined` const [books, setBooks] = useState(undefined); useEffect(() => { (async () => { setBooks(await fetchBooks()); })(); }, []); return ( <div> {books.map((book) => ( <div key={book.id}> <h2>Title: {book.title}</h2> <p>Author: {book.author}</p> </div> ))} </div> ); } export default App;

We’ll use this example to learn some easy ways to quickly fix this error in React.

Fix: Use optional chaining operator (?.)

To fix the “Cannot use property ‘map’ of undefined” error in React.js, use the optional chaining operator (?.) to access the map() method:

JavaScript
import { useState, useEffect } from 'react'; import { fetchBooks } from './books'; function App() { const [books, setBooks] = useState(undefined); useEffect(() => { (async () => { setBooks(await fetchBooks()); })(); }, []); return ( <div> {/* ✅ Fix with optional chaining (?.) */} {books?.map((book) => ( <div key={book.id}> <h2>Title: {book.title}</h2> <p>Author: {book.author}</p> </div> ))} </div> ); } export default App;

The optional chaining operator lets us safely access a property on a value that may be undefined or null. If it is, the operator will return undefined immediately and prevent the property access or method call.

JavaScript
const auth = undefined; console.log(auth); // undefined // ✅ No error console.log(auth?.user?.name); // undefined

Fix: Use AND operator (&&)

You can also use the && operator to check if the value is undefined before access it in the JSX:

JavaScript
import { useState, useEffect } from 'react'; import { fetchBooks } from './books'; function App() { const [books, setBooks] = useState(undefined); useEffect(() => { (async () => { setBooks(await fetchBooks()); })(); }, []); return ( <div> {/* ✅ Fix with AND operator (&&) */} {books && books.map((book) => ( <div key={book.id}> <h2>Title: {book.title}</h2> <p>Author: {book.author}</p> </div> ))} </div> ); } export default App;

Here’s what a chain of && does: it returns the right-most variable if all the variables are truthy. Otherwise, it returns the left-most falsy variable:

JavaScript
console.log(undefined && 0 && []); // undefined console.log(10 && null && 'coding'); // null console.log(10 && [5, 7] && 'coding'); // coding

Note: These are the falsy values in JavaScript: undefined, null, 0, false, '' (empty string), and NaN. Every other value is truthy.

Fix: Initialize state variable to empty array

The applies when the array value is a state variable like in our example.

We set the state to an empty array ([]) at the point where it’s created, so it never becomes undefined, preventing the “Cannot read property ‘map’ of undefined” error.

JavaScript
import { useState, useEffect } from 'react'; import { fetchBooks } from './books'; function App() { // ✅ `books` starts out as an array, not `undefined` const [books, setBooks] = useState([]); useEffect(() => { (async () => { setBooks(await fetchBooks()); })(); }, []); return ( <div> {books.map((book) => ( <div key={book.id}> <h2>Title: {book.title}</h2> <p>Author: {book.author}</p> </div> ))} </div> ); } export default App;

Fix: Create a loading state when fetching data

Apart from initializing the state to an empty array you can also display a loading indicator when performing network request, or some other time-consuming operation:

JavaScript
import { useState, useEffect } from 'react'; import { fetchBooks } from './books'; function App() { const [books, setBooks] = useState(undefined); const [loading, setLoading] = useState(true); useEffect(() => { (async () => { setBooks(await fetchBooks()); })(); // ✅ Lists books with .map() after loading completes setLoading(false); }, []); let listEl; if (loading) { listEl = <div>Loading...</div>; } else { listEl = ( <div> {books.map((book) => ( <div key={book.id}> <h2>Title: {book.title}</h2> <p>Author: {book.author}</p> </div> ))} </div> ); } return <div>{listEl}</div> } export default App;

Most web user interfaces have at least three states – loading, error, and success state, and we could be better off representing all three of them:

JavaScript
import { useState, useEffect } from 'react'; import { fetchBooks } from './books'; // TypeScript // type UIState = 'loading' | 'error' | 'success'; function App() { const [books, setBooks] = useState(undefined); const [state, setState] = useState('loading'); // TypeScript // const [state, setState] = useState<UIState>('loading'); useEffect(() => { try { (async () => { setBooks(await fetchBooks()); setState('success'); })(); // ✅ Lists books with .map() after loading completes } catch (err) { setState('error'); } }, []); const listViewMap = { loading: <div>Loading...</div>, error: <div>An error occured, try again later.</div>, success: ( <div> {books.map((book) => ( <div key={book.id}> <h2>Title: {book.title}</h2> <p>Author: {book.author}</p> </div> ))} </div> ), }; const listEl = listViewMap[state]; return <div>{listEl}</div>; } export default App;

Fix: Check the value assigned to the array

Maybe you initialized the array properly and did everything else right, but you set it to undefined at some point in the code.

If the array is to be filled with API data, are you sure you’re making the network request properly.

For example, if our fetchBooks() function was defined like below, it will cause a “Cannot read property ‘map’ of undefined” error when there’s a network error on the user’s device.

JavaScript
export async function fetchBooks() { const res = fetch('https://api.example/books', { headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, }); // ❌ Will return `undefined` if status code is not 200 return res.status === 200 ? (await res).json() : undefined; }

Make sure you handle all the edge cases in your app.

Fix: Check your variable names

Sometimes the error happens due to a error in your variable names.

JavaScript
import { useState, useEffect } from 'react'; import { fetchBooks } from './books'; function App() { const [books, setBooks] = useState([]); useEffect(() => { (async () => { setBooks(await fetchBooks()); })(); }, []); return ( <div> {books.map((books) => ( <div key={book.id}> <h2>Title: {book.title}</h2> <p>Author: {book.author}</p> </div> ))} </div> ); } export default App;

Here we mistakenly create a books variable in the map() callback but we use book identifier in the JSX, which is what we actually intended. The causes the unfortunate error, aside from the fact that it shadows the outer books state variable.

[SOLVED] Cannot use import statement outside a module in JavaScript

Are you currently experiencing the “Cannot use import statement outside a module” error in JavaScript?

The "Cannot use import statement outside a module" error in a browser console.
The “Cannot use import statement outside a module” error in a browser console.

This is a well-known error that happens when you use the import keyword to load a file or package that is not a module.

Let’s learn how to easily fix this error in Node.js or the browser.

Fix “Cannot use import statement outside a module” in browser

Fix: Set type="module" in <script> tag

The “Cannot use import statement outside a module” error happens in a browser when you import a file that is a module without indicating this in the <script> tag.

index.html
<!DOCTYPE html> <html> <head> <title>Coding Beauty</title> <link rel="icon" href="favicon.ico" /> </head> <body> A site to make you enjoy coding <!-- ❌ SyntaxError: Cannot use import statement outside a module --> <script src="index.js"></script> </body> </html>

To fix it, add type="module" to the <script> tag.

index.html
<!DOCTYPE html> <html> <head> <title>Coding Beauty</title> <link rel="icon" href="favicon.ico" /> </head> <body> A site to make you enjoy coding <!-- ✅ Loads script successfully --> <script type="module" src="index.js"></script> </body> </html>

Fix “Cannot use import statement outside a module” in Node.js

The “Cannot use import statement outside a module” error happens when you use the import keyword in a Node.js project that doesn’t use the ES module import format.

index.js
// ❌ SyntaxError: Cannot use import statement outside a module import axios from 'axios'; const { data } = ( await axios.post('https://api.example.com/hi', { hello: 'world', }) ).data; console.log(data);

Fix: Set type: "module" in package.json

To fix the error in Node.js, set the package.json type field to “module”.

package.json
{ // ... "type": "module", // ... }

Now you can use the import statement with no errors:

index.js
// ✅ Imports successfully import axios from 'axios'; const { data } = ( await axios.post('https://api.example.com/hi', { hello: 'world', }) ).data; console.log(data);

If there’s no package.json in your project, you can initialize one with the npm init -y command.

Shell
npm init -y

The -y flags creates the package.json with all the default options – no user prompts for the fields.

Fix: Use require instead of import

Alternatively, you can fix the “Cannot use import statement outside a module” error in JavaScript by using the require() function in place of the import syntax:

index.js
// ✅ Works - require instead of import const axios = require('axios'); const { data } = ( await axios.post('https://api.example.com/hi', { hello: 'world', }) ).data; console.log(data);

But require() only works on the older, Node-specific CommonJS module system, and these days more and more modules are dropping support for CommonJS in favor of ES6+ modules.

For example, if you use require() for modules like got, node-fetch, and chalk, you’ll get the “require of ES modules is not supported error”.

index.js
// ❌ [ERR_REQUIRE_ESM]: require() of ES Module not supported const chalk = require('chalk'; console.log(chalk.blue('Coding Beauty'));

If you can’t switch to an ES module environment, you can fix this by dynamically importing the module with the async import() function. For example:

index.js
// CommonJS module // ✅ Imports successfully const chalk = (await import('chalk')).default; console.log(chalk.blue('Coding Beauty'));

Or, you can downgrade to an earlier version of the package that supported CommonJS and require().

Shell
npm install chalk@4 # Yarn yarn add got@4

Here are the versions you should install for various well-known NPM packages to avoid this ERR_REQUIRE_ESM error:

Package versions for downgrading to fix the "Cannot use import statement outside a module" error in JavaScript.

Fix “Cannot use import statement outside a module” in TypeScript

If the module field in tsconfig.json is set to commonjs, any import statement in the TypeScript source will change to require() calls after the compilation and potentially cause this error.

tsconfig.json
{ //... "type": "module" }

Prevent this by setting module to esnext or nodenext

tsconfig.json
{ "type": "module" }

nodenext indicates to the TypeScript compiler that the project can emit files in either ESM or CommonJS format.