20th week of 2021

Published on

Last updated on

Handling page changes with React Router, <strong> and <em> from accessibility perspective, user-defined conversion operators in C#, cool color matching app.

Table of contents

👨‍💼 Work

React Router: Scroll to top on page change

When navigating in a Single Page Application (SPA), you have to handle scrolling manually. Here's a solution that's often recommended, but this is wrong:

import { useLocation } from 'react-router-dom'

// Use this hook in some top-level component
// which is inside a `<Router>` component
function useOnPageChange() {
  const { pathname } = useLocation()

  useEffect(() => {
    window.scrollTo(0, 0)
  }, [pathname])

It's wrong because the page is scrolled on all page changes – even when using the browser's back and forward navigation buttons.

Compare with any non-SPA site, like my website. When using the browser's back/forward buttons, the previous/next page's scrolling position should be restored. The page should be scrolled to top only when navigating to new pages.

The fix is to check the value of the history object's action parameter:

import { useHistory, useLocation } from 'react-router-dom'

function useOnPageChange() {
  const { action } = useHistory()
  const { pathname } = useLocation()

  useEffect(() => {
    // Do nothing when using the browser's back/forward buttons
    if (action === 'POP') return

    window.scrollTo(0, 0)
  }, [action, pathname])

You could (and probably should) also do other things in the hook, like focus the main heading of the new page.

👨‍🚀 Personal

My goal for this week was to publish a cookbook recipe. Here it is: Delegate types in C#: Action vs Func vs Predicate.

Next week I'd like to stop and think whether I really need a blog and a cookbook. Some of my current blog posts feel like they should be cookbook recipes, and vice versa, so it's a hassle and causes unnecessary mental burden. I might ditch the cookbook and convert the current recipes to blog posts. But more on this next week!

Update on Jun 12, 2021: I no longer have a cookbook section on this website. See Goodbye Cookbook, hello more blog posts.

👨‍🎓 Learnings

a11y: <strong> and <em> should be treated as progressive enhancement

Martin Underhill writes that bold and italics aren't read by screen readers. "Interestingly, the NVDA screen reader added support for emphasis [in 2015], only to remove it following complaints by users."

I had noticed before that screen readers indeed don't announce if the currently read text is bold or italics.

But I hadn't considered this mindset:

Text-level semantics like italics and bold should be treated as a progressive enhancement. In other words, your sentences should make sense without emphasis; those <em> and <strong> wrappers should just offer a nice added extra for [sighted users].

Makes sense.

Strikethrough is a similar but more difficult case because it adds content. Read Martin's another post Be careful with strikethrough for more details. The post contains several good points why strikethrough is better avoided entirely.

C#: Implicit and explicit type conversion operators

User-defined conversion operators in C# allow defining custom implicit and explicit type conversions.

I learned about them from Nick Chapsas's video Automatic type conversion with Implicit and Explicit operators in C#. I hadn't previously heard of them.


public class UserId
    public Guid Value { get; }

    public UserId(Guid value)
        Value = value;

    public static implicit operator UserId(Guid guid)
        return new UserId(guid);

// Elsewhere:

Guid id = Guid.NewGuid();
UserId userId = id; // Implicit type conversion

Check out the video for more details and examples.

User-defined conversion operators are easily confusing and should usually be avoided. Value objects can be a good exception.

🕵️‍♂️ Cool stuff

Color.io Match: Color matching app

Color.io's Match app is "a free image color matching app that can copy colors of any image with one click."

  1. Upload a photo.
  2. Select a nice-looking photo in the app.
  3. Your photo will now have similar colors as the other photo.

Nice and easy!

The author has described the app's tech stack in a Reddit thread on /r/webdev/:

I sketched the design in figma and built the frontend with Cue.js (my own reactive wrapper around custom elements). The image processing is done in WebGL. I tried to recreate the image drag & zoom behaviour from iOS.

Check out the Reddit link for the full comment. Very interesting stuff!

💁‍♂️ More Weekly log entries

Next week: 21st week of 2021

Previous week: 19th week of 2021