17th week of 2021

Published on

Last updated on

Site-specific components in a multi-site React app, fallback refs in React, cool UI recreations, and more.

Table of contents

👨‍💼 Work

React: Site-specific components in a multi-site project

A multi-site React project has likely two kinds of components:

  • Common components, used by two or more sites and residing e.g. under the src/common/ folder.
  • Site-specific components, used only by one site and residing e.g. under the folders src/site-a/, src/site-b/ and so on.

An example of a common component is Link: a hyperlink with certain styles and logic, used on all sites for most links.

Let's say that Site A, and only that site, requires some extra logic in the Link component. What are my options? Let's think:

  1. Add the extra logic to the common Link component. This would be messy, because the common component would then have site-specific logic in it.
  2. Create an entirely separate, site-specific Link component for Site A. I don't like this option because the common and site-specific Link components would have lots of duplicate code. Links are very common, so any future changes would have to be made to two components.
  3. Create a "child component" for Site A, so that the site-specific component ultimately renders the common Link component. This would be nice, but the problem would be that developers would need to remember to import the site-specific component when working on Site A's code, and to import the common component when working on other sites' codes.

I eventually found a way to avoid the problem in the third option! Behold one of this week's learnings: ESLint: Restrict which files can be imported in a given folder.

👨‍🚀 Personal

My goal for this week was to implement RSS feeds for my cookbook[1] and weekly log. I started working on the goal, but didn't finish it.

Implementing the new feeds isn't difficult. Finding time and discipline is.

Being late one week is okay (right?!). Being late two weeks is not very nice, so you can look forward to the new RSS feeds next week. Fingers crossed. 🤞

👨‍🎓 Learnings

ESLint: Restrict which files can be imported in a given folder

The heading of this section is the name of the ESLint rule import/no-restricted-paths. It's one of the rules in the eslint-plugin-import plugin.

For context about why I needed this rule, see React: Site-specific components in a multi-site project.

Here's what I added to our ESLint config to solve the problem discussed in the linked section:

module.exports = {
  'import/no-restricted-paths': [
      zones: [
          target: 'src/site-a/',
          from: 'src/common/Link.js',
          message: 'Import the site-specific Link component instead.',

I.e. the config makes ESLint throw an error if you try to import src/common/Link.js in any file under src/site-a/. Plus ESLint will show the custom message so no one has to guess why importing the common Link component fails. Excellent!

To prevent importing certain npm packages, you could use ESLint's native rule no-restricted-imports. A useful example case is if you want developers to import your own Link component instead of React Router's Link component.

React: Use a fallback ref with forwardRef

If you have a React component which uses React.forwardRef(), normally the component is expected to receive a ref from its parent component. But what if you want the component to have a ref even if it doesn't receive a ref from its parent?

Long story short, I had this problem and solved it by using the useImperativeHandle() hook for the first time ever. Here's how:

const Child = React.forwardRef((props, forwardedRef) => {
  const innerRef = useRef()

  // Expose `innerRef` as-is to the parent,
  // so that `forwardedRef.current` points to the same DOM element
  // as `innerRef.current` does
  useImperativeHandle(forwardedRef, () => innerRef.current)

  // Do something with `innerRef`...

  return <div ref={innerRef}>...</div>

function Parent() {
  const ref = useRef()

  // Do something with `ref`...

  return <Child ref={ref} />

Now it's OK to render <Child> on its own or via <Parent>. Without the useImperativeHandle() hook, you could only render <Child> via <Parent>.

If this is confusing, go ahead and read Jake Trent's article Fallback Ref in React. That's where I learned this trick!

🕵️‍♂️ Cool stuff

JavaScript: HTML Sanitizer API is coming

Mike West, who's working on Chrome's security team, tweeted about a work-in-progress HTML Sanitizer API:

HTML sanitizers are critical to web applications, mitigating the risk of XSS when working with untrusted strings. The HTML Sanitizer API is a work-in-progress (behind a flag in Chrome and Firefox) that shifts responsibility for this task to the browser: wicg.github.io/sanitizer-api/

Having to install one fewer dependency and letting browsers handle more security-related stuff sounds good.

CSS: More engaging focus outlines

Adam Argyle tweeted a snippet to make focus outlines more engaging:

@media (prefers-reduced-motion: no-preference) {
  :focus {
    transition: outline-offset 0.25s ease;
    outline-offset: 5px;

The snippet adds a small transition to focus outlines so that it's easier to see what element is receiving focus. See the tweet for a video or try it out on Codepen. (The demo doesn't seem to work as well on Firefox as it does on Chrome.)

I don't know yet if I'm a fan of this as I suspect that the transitions can quickly become irritating.

Tailwind: iPhone lock screen recreation using Tailwind

Jon Eide Johnson tweeted his recreation of his iPhone lock screen using only Tailwind and Heroicons. It's gorgeous!

Check out the tweet for a screenshot, a link to a demo on Tailwind Play, and a few learnings.

Note about the demo: looks like CSS backdrop filters are not yet supported on Firefox. Or actually they are supported, but are still behind two feature flags.

JavaScript + SVG: Apple Keynote Event animation recreation

Check out Recreating the Apple Keynote Event animation using SVG, Canvas, and GreenSock on Bram.us for another visually stunning recreation, this time by Louis Hoebregts. There's also a breakdown of the recreation. Very nice!

(Note to self: I should start using images in these "Cool stuff" sections. 🙉)


  1. I no longer have a cookbook section on this website: Goodbye Cookbook, hello more blog posts.

💁‍♂️ More Weekly log entries

Next week: 18th week of 2021