Featured

Pure Styling of Components with TypeScript & CSS: Part 2 — Comparison to Styled-Components

CSS-in-JS is a popular approach to styling components within React apps. These libraries are much more sophisticated than simply inline styles. I chose one popular library, styled-components, to compare to the Subatomic CSS approach I detailed in my previous post. I look at the clarity of components, the amount of flexibility, and performance.

HTML structure

styled-components encourages a one-to-one mapping between React components and HTML elements. If you have a nav item that is made of a <li> containing an <a>, with them sitting inside a <ul> and all surrounded by a <nav>, then you could create components like so:

export const NavLink = styled.a`
  padding: 0.5rem 1rem;
  color: blue;
`;

export const NavItem = styled.li`
  list-style: none;
`;

export const NavList = styled.ul``;

export const Nav = styled.nav`
  padding: 0 1rem;
`;

And then use them like so:

<Nav>
  <NavList>
    <NavItem>
      <NavLink href="/features">Features</NavLink>
    </NavItem>
    <NavItem>
      <NavLink href="/pricing">Pricing</NavLink>
    </NavItem>
    <NavItem>
      <NavLink href="/sign-in">Sign in</NavLink>
    </NavItem>
  </NavList>
</Nav>

It’s convenient for you to make a component for each particular HTML element. But, the <NavList> and <NavItem> components conceptually do not add much. They do in the final HTML with their <ul> and <li>, but at the component level they are mostly noise.

It would be much cleaner to have just <Nav> and <NavItem>. Semantically we have a bunch of nav items inside a nav. The other components are really just implementation details of HTML. It would be much cleaner to have:

<Nav>
  <NavItem to="/features">Features</NavItem>
  <NavItem to="/pricing">Pricing</NavItem>
  <NavItem to="/sign-in">Sign in</NavItem>
</Nav>

How could we create these components?

const NavLink = styled.a`
  padding: 0.5rem 1rem;
  color: blue;
`;

export const NavItem = styled(({ to, className, children }: { to: string; className: string; children: React.Node }) => (
  <li className={className}>
    <NavLink href={to}>{children}</NavLink>
  </li>
))`
  list-style: none;
`

export const Nav = styled(({ className, children }: { className: string; children: React.Node }) => {
  return (
    <nav className={className}>
      <ul>{children}</ul>
    </nav>
  );
})`
  padding: 0 1rem;
`;

I find this much better at the usage side, but much more complicated than the previous component definitions. Also, the backticks are not sitting and reading so elegantly now. There’s a loss of clarity.

So what’s an alternative? Consider with subatomic classes instead:

.list-reset {
  list-style: none !important;
}

.px-2 {
  padding-left: 0.5rem !important;
  padding-right: 0.5rem !important;
}
.py-4 {
  padding-top: 1rem !important;
  padding-top: 1rem !important;
}

.text-blue {
  color: blue !important;
}
export function NavItem({ to, children }: { to: string; children: React.Node }) {
  return <li className="list-reset">
    <a href={to} className="px-2 py-4 text-blue">{children}</a>
  </li>;
}

export function Nav({ children }: { children: React.Node }) {
  return <nav className="py-4">
    <ul>
      {children}
    </ul>
  </nav>;
}

The CSS may feel like a once-off, but actually we can build a palette of these subatomic styles with the colors and padding and utilities common between many of our components. You get a really reusable set of classes that enforce consistency between components, and soon you can create new components without having to add any new CSS.

Within the components, there’s much less going on than the second styled-components approach, but it’s performing the same task.

The key thing for me is the HTML tags and class names are easily readable. There’s not much else getting in the way of clarity.

We can use these components in that same nice, concise way:

<Nav>
  <NavItem to="/features">Features</NavItem>
  <NavItem to="/pricing">Pricing</NavItem>
  <NavItem to="/sign-in">Sign in</NavItem>
</Nav>

Dynamic styles based on props

Ok, we haven’t stretched styled-components’ abilities yet. Let use one powerful ability: use different styles depending on what props are passed.

Let’s make a list of items. Each item is coloured. The items will alternate by color: red, blue, orange, red, blue, orange, and again and so on.

We can do this by dividing the item index by 3, and depending on the remainder (either 0, 1, or 2), we’ll use a particular color.

This is how we’d write this using styled-components:

export const Item3Colors = styled.div`
  color: ${(props: ItemProps) => {
    const index3 = props.index % 3;
    return index3 === 0 ? "red" : index3 === 1 ? "blue" : "orange";
  }};
  font-family: sans-serif;
  font-size: 1.25rem;
`;

We interpolate in a function that will calculate the value for the color property given the current props.

And with Subatomic CSS classes:

.font-sans {
  font-family: sans-serif !important;
}

.text-lg {
  font-size: 1.25rem !important;
}

.text-red {
  color: red !important;
}
.text-blue {
  color: blue !important;
}
.text-orange {
  color: orange !important;
}
export function Item3Colors({ children, index }: ItemProps) {
  const index3 = index % 3;
  const colorName = index3 === 0 ? "red" : index3 === 1 ? "blue" : "orange";
  return (
    <div className={`font-sans text-lg text-${colorName}`}>{children}</div>
  );
}

We also interpolated strings, but we calculated a composite class name instead of CSS rules.

Now let’s measure the difference!

Measuring the effect on the user experience

I have built three versions to compare. The first is a baseline with no styling at all. This is to measure the impact of React itself, and to give us a good idea of what overhead our dynamic styling is adding. The second is using styled-components. And the third is using the Subatomic CSS approach described in this post.

You can find links to these projects here:

A good way to measure how this will affect the user is using Google’s online PageSpeed tool. It not only gives an overall score, but also break down key metrics such as time for the user to see something (first contentful and first meaningful paint), and the delay until they can interact with the site (estimated input latency).

No styling: 100 items

PageSpeed

No styling: 1000 items

PageSpeed

Styled components: 100 items

PageSpeed

Styled components: 1000 items

PageSpeed

CSS classes: 100 items

PageSpeed

CSS classes: 1000 items

PageSpeed

First Contentful Paint & Time to Interactive

Both of these numbers measure the same here: likely because it’s the time when React has finished rendering the component.

With 100 items, the styled-components approach (1.8s) took only slightly longer than the pure CSS approach (1.6s). Not styling at all took 1.5s.

When rendering 1000 items, we start to see a gap widening:

  • No styling: 1.7s
  • Styled-components: between 2.2–2.5s
  • Subatomic CSS: between 1.7–1.8s

Estimated Input Latency

The bigger concern is the Estimated Input Latency. The CSS approach has no difference to having no styles: there’s a latency of 10ms.

When styled-components is used to render 1000 items, there’s an input latency between 90–300ms. That’s a significant delay, and the experience to a user would be a feeling of sluggishness.

Download sizes

Using Firefox’s web developer tools, let’s see the size of the assets download by the user’s browser.

No styles

Let’s compare the number of kilobytes downloaded. First, no styles:

This is our baseline. 37KB + 1KB of gzipped JavaScript. Unzipped it’s 117KB. The first 1.xxx.js file contains our dependencies such as React. The main.xxx.js is our app’s JavaScript such as custom components.

Subatomic CSS

Next, we have the subatomic CSS approach. We now have a main.xxx.css file that is less than one kilobyte in size.

The 1.xxx.js is essentially the same size. We added no extra dependencies. The main.xxx.js size has increase, but only by a 1/3 of a kilobyte.

We have gained styling, but with not much overhead at all.

Styled-components

Lastly, let’s see the download sizes for styled-components.

While our main.xxx.js is also not much larger, our 1.xxx.js dependencies is larger. A 15KB difference gzipped doesn’t sound like much, but uncompressed that’s 43KB. It’s over 1/3 larger than before. That’s extra code that has to be parsed and executed before our user sees anything. On a mobile device, this can be significant extra time and power.

Server rendering

Styled-component’s documentation recommends an approach like following for server-side rendering:

import { renderToString } from 'react-dom/server'
import { ServerStyleSheet } from 'styled-components'

const sheet = new ServerStyleSheet()
try {
  const html = renderToString(sheet.collectStyles(<YourApp />))
  const styleTags = sheet.getStyleTags() // or sheet.getStyleElement();
} catch (error) {
  // handle error
  console.error(error)
} finally {
  sheet.seal()
}

As components are rendered, they produce their styles. The styles.collectedStyles() method captures all these styles. You then have to insert the style tags into the served HTML.

With Subatomic CSS, there is no need to capture the styles produced or insert extra tags. They are all in the CSS file already that you link to. There’s no extra work needed at all for server-side rendering.

Hover, focus, active, and media queries

One of the benefits of styled-component’s use of CSS rules is that you can use pseudo classes such as :hover and :focus, or media queries.

Let’s look at writing styling for a link that is normally red and without underlining, and then when hovered becomes both orange and underlined. First with styled-components:

export const Link = styled.a`
  color: red;
  text-decoration: none;
  &:hover {
    color: orange;
    text-decoration: underline;
  }
`;

It’s understandable if you’ve used something like SCSS. The & mean we are target the element itself, so we only have to add the :hover and the rules inside.

Here’s how we’d approach the same problem with subatomic styles:

.text-red { color: red !important; }
.hover\:text-orange:hover { color: orange !important; }

.no-underline { text-decoration: none !important; }
.hover\:underline:hover { text-decoration: underline !important; }
function Link({ href, children }: { href: string; children: React.Node }) {
  return <a className="text-red no-underline hover:text-orange hover:underline" href={href}>{children}</a>;
}

What’s up with those backslashes before the colons? That’s because we want the colon to be treated literally instead of like a pseudo element. We then add the actual :hover pseudo element at the end, so that the rule is only active when the element is being hovered. There is no .hover\:text-orange rule without :hover, so by default this class will have zero effect until the user hovers.

We use similar approaches for :focus and :active and (one of my favorites) :focus-within. We add the prefix to the actual class name so we can see it when declaratively use them as class names in components.

Media queries and breakpoints

You can use the same technique for media queries and breakpoints:

.text-red { color: red !important; }
.text-blue { color: blue !important; }
.text-orange { color: orange !important; }

@media (min-width: 36rem) {
  .sm\:text-red { color: red !important; }
  .sm\:text-blue { color: blue !important; }
  .sm\:text-orange { color: orange !important; }
}

@media (min-width: 48rem) {
  .md\:text-red { color: red !important; }
  .md\:text-blue { color: blue !important; }
  .md\:text-orange { color: orange !important; }
}
function Link({ href, children }: { href: string; children: React.Node }) {
  return <a className="text-red sm:text-blue md:text-orange" href={href}>{children}</a>;
}

Once you have a kit of these, they are really useful. You can achieve sophisticated behaviour while keeping your components easy to read.

It’s all just CSS. It’s just clever class naming.

Well that’s great, I might hear you say. But can you combine media queries with interpolated values? With styled-components, I can punch a function into my styling rules even inside a @media query.

Using the above responsive text color classes, we can.

type ColorName = "red" | "blue" | "orange";

function Link({
  href,
  color,
  colorSm,
  children
}: {
  href: string;
  color: ColorName;
  colorSm: ColorName;
  children: React.Node
}) {
  return <a className={`text-${color} sm:text-${colorSm}`} href={href}>{children}</a>;
}

Here we used a TypeScript defined type to constrain the allowed color name values to only red, blue, or orange — anything else would be a compile-time error.

It is used like so:

<Link color="orange" colorSm="red" href="/">Orange at XS, Red at SM</Link>
<Link color="blue" colorSm="orange" href="/">Blue at XS, Orange at SM</Link>

There’s other enhancements we could do, such as adding a colorMd prop or making them optional, and these are easy to add. I will give more full featured examples in future blog posts.

User experience vs developer experience

Approaches such as styled-components sound great because they make our, the developers, lives easier. If we are able to ship things faster, then that means we can improve our users’ experience faster.

However, I think it’s not so straightforward to assume that an improvement to developer experience (DX) does make enough of a meaningful difference to the UX. Those decisions to improve DX might have made the UX worse by making it slower to load, by adding latency to input, and by using more of the user’s battery. That’s a deficit you can’t just simply get back.

Approaches such as Subatomic CSS provide a great developer experience while not compromising the user experience. Adding minimal overhead is a feature in itself. Niceties to the DX that TypeScript can offer such as autocompletion and class name checking all get compiled away.

Plus, you then have less need to tackle bundle splitting and lazy loading of JavaScript. If your JavaScript is minimal to begin with, then you won’t have to spend extra time optimizing its delivery. And that is even more time we can spend building and shipping.

Coming up

I hope you’ve enjoyed the series so far. Please feel free to reach out to me on Twitter for feedback or suggestions. In future blog posts I plan to cover these topics:

  • Comparison to styled-system
  • Using CSS variables in a Subatomic CSS system
  • The TailwindCSS library
  • Container queries

Programming language ⚡️ energy efficiency compared

A team of Portuguese researchers have compared 27 programming languages by their energy use. They compared both CPU and DRAM energy usage with total time of execution and memory usage to build a fuller picture of efficiency.

The aggregated figures for energy, time, and memory across 27 programming languages.

Unsurprisingly compiled languages such as C and C++ perform best or near the top. Their modern successor Rust also does well.

Golang uses more CPU, but is still relatively lean. It’s especially impressive with memory usage, using even less than C or C++.

Swift and C# are not standouts, but both do very well both with energy and memory use. This contrasts with Java, which is faster and uses less energy, but has over twice the memory usage of these two.

JavaScript is one of the fastest interpreted language, having had over a decade of focused performance improvements. I have to assume they tested with NodeJS — I think server-side JavaScript has many interesting futures outside of this one particular tool.

Ruby and Erlang are both at the high end for energy use and CPU time. This could be because many of what were benchmarked were computationally intensive algorithms, which if you are building web applications you may not be writing many of yourself. However, many of the underlying libraries may still exhibit this sort of performance and energy profile.

All in all, I think it’s an interesting comparison, and I think it’s great to be putting a focus on energy usage as an important metric — it is something to be mindful of for both code running on servers in the cloud, and code on users devices.

You can read the full paper here, and there’s also more analysis to read.

Handy SPA config for Netlify

Although Netlify out of the box won’t work with single page apps’ routing, it is easy to add. You can configure it to send all /* subpath requests to a single index.html file.

Steps for create-react-app

Here we will be using a create-react-app project. This should be easy to apply to other SPA toolkits.

Add a netlify.toml file to your src folder. In it write:

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

Edit your package.json file. Find the scripts section.

  “scripts”: {
    …
    "build": "react-scripts build”,
    …
  }

Replace the build rule with three:

    "build": "npm run build:react && npm run build:config",
    "build:react": "react-scripts build",
    "build:config": "cp src/netlify.toml build/netlify.toml",

This rule builds the static assets using create-react-app’s toolkit, then copies the netlify.toml file to this build directory.

That’s it! As long as Netlify is set to run npm run build then this will work. You will be able to visit subpaths and get the same index.html page served for all.

Pure Styling of Components with TypeScript and CSS: Part 1

The benefits of components have been realized with systems such as React and VueJS. Styling these components has a number of approaches, from CSS classes written in SCSS, inline styles, and dynamically generated stylesheets via something like emotion.

Each styling approach has trade-offs in regards to reusability, performance, and developer experience. Also, special considerations often have to be made when doing server-side rendering.

In this post, we’ll explore TypeScript combined with functional CSS. I believe it offers big benefits over the other choices — it’s extremely reusable, fast, and offers a very pleasant developer experience.


Why CSS?

CSS classes are fundamentally simple. They are a name given to a set of CSS rules. You can reuse classes on as many elements as you like. You can use them from JavaScript or you can use when generating HTML from the server. They are just straightforward.

Well, so they seem. With a semantically named class name, like btn, it is tempting and often deemed necessary to override rules. To add more specificity — “In this context, it should look like this. Otherwise, it should look like this… apart from on this particular page, and when it’s inside the footer.”

Does this look familiar?

<button class="btn">Learn more</button>

<footer>
  <button class="btn">Sign in</button>
</footer>
.btn {
  padding: 0.5rem;
  color: white;
  background-color: green;
}

footer {
  .btn {
    color: blue;
    background-color: white;
  }    
}

Here we have a .btn rule that forms a base for all buttons — a green background with white text. But our footer requires a different color, so we override it when a .btn is within a footer on the page.

There’s nothing wrong with this! It’s what CSS is designed for, and it does well.

However, this approach can over time can degrade into lots of overriding, into unused code and fragile code that you are afraid to make changes to. All this makes the code harder to reason about because there’s two pieces of code interacting with each other: the CSS, and the component’s template.

You might not know what something will look like until you see it in the browser. You see it there, and if it’s wrong then you hunt down whatever CSS rules are producing that effect until it’s fixed.

(It’s similar to the concept of impure imperative code that produces side effects that end up affecting other code unrelated to it. A pure function has no side effects; all it can affect is its output.)

So how could our button work with functional CSS classes?

<button class="padding-2 bg-green text-white">Learn more</button>

<footer>
  <button class="padding-2 bg-white text-blue">Sign in</button>
</footer>
.padding-2 { padding: 0.5rem; }

.bg-green { background: green; }
.bg-white { background: white; }

.text-blue { color: blue; }
.text-white { color: white; }

Well, doesn’t that look stupid! Why would we do that? We’re repeating all the styling choices every time we have a button. For every button we’ll have to say padding-2 and then its chosen background and text color. ”That’s not semantic,” you might say.

The thing is, I’m not writing every <button> raw like this. I’m using components, say in React. Define one <Button> component and use that everywhere.

We could write the markup with the two buttons like so using JSX:

<Button variant="call-to-action">Learn more</Button>

<footer>
  <Button variant="link">Sign in</Button>
</footer>

And let’s define this <Button> component, using TypeScript to specify its props.

import React from "react";

type ButtonVariant = "call-to-action" | "link";

interface ButtonProps {
  variant: ButtonVariant;
  children: string;
}
export function Button({ variant, children }: ButtonProps) {
  return (
    <button className={`padding-2 ${variant === "call-to-action" ? "bg-green text-white" : "bg-white text-blue"}`}>{children}</button>
  )
}

Here we say there are two variations of buttons: a call to action, and one that looks like a link. This is our semantic layer. Semantics are important in the HTML markup: what tag and attributes you use will affect audible screen readers.

Our class names do not affect this semantic layer that the user sees. The class names are us authors, and the desire to have a semantic layer there is for the benefit of letting us make sense of what we are authoring. Which is especially important as the code evolves over time.

Semantic class names look a bit like this:

  1. semantic .btn-primary class name
  2. transformed into semantic $primary-color SCSS variable
  3. transformed into presentational background CSS rule with #0f6138 as a value

The semantic layer for this path of setting the background color for a primary button end up losing their semantic meaning when they are actually processed by the browser. The background property is set to a RGB color written in hexadecimal. The browser, and particularly the user, gains no additional information by the fact we used the word “primary” in the class name.

With our functional class names, the process looks like this:

  1. semantic component <Button>
  2. transformed into semantic prop variant equal to "call-to-action"
  3. transformed into presentational class name .bg-green
  4. transformed into presentational background CSS rule with #0f6138 as a value

The result is the same, authoring retains the semantic layer. Our component translates our semantic intent into our presentational intent. It’s a clear function of Semantics Props -> Semantic HTML and Presentational Styling

Ok, have we gone too far with the names bg-green? Probably. There’s nothing wrong with semantic class names. In fact, they help us keep a design system consistent and understandable. My problem is that when we become so intent on making our CSS class names have meaning — meaning that doesn’t affect our users — we actually make our jobs harder then they need to be.

Why is it hard? It’s a lot easier to add to CSS than it is to change or remove it. An override will often just get the job done. Until you have to override that override. The extra specificity of selector often falls out of sync of the semantic meaning in several months time as the design is extended and revised. It could all actually be a much simpler system of class names if you could just rewrite it from scratch. So, in that way, the original semantic naming choices have lost a lot of their value.

If we write semantic HTML using semantic components, we have fulfilled our semantic needs for both the user and authors. Our class names fall wherever on the spectrum between semantic and presentational we feel works for us.

(If the meaning of a color is the brand color, then call it that. If it just happens to be orange because the designer thought that looked good, why do we feel we have to invent a semantic name that the designer doesn’t share or apply consistently? Ideally you steer the designer so you have a better defined common language. But this often isn’t adopted by them.)

Let’s rename some of our color classes to be more semantic.

.padding-2 { padding: 0.5rem; }

.bg-primary { background: green; }
.bg-light { background: white; }

.text-link-color { color: blue; }
.text-light { color: white; }
import React from "react";

type ButtonVariant = "call-to-action" | "link";

interface ButtonProps {
  variant: ButtonVariant;
  children: string;
}
export function Button({ variant, children }: ButtonProps) {
  return (
    <button className={`padding-2 ${variant === "call-to-action" ? "bg-primary text-light" : "bg-light text-link-color"}`}>{children}</button>
  )
}

These classes are extremely reusable. A <Pill> component might reuse the same classes. A <PrimaryHeader> might be colored the primary color and so could use the .bg-primary class. Often many elements will share the same spacing of paddings and margins.

We can build a reusable palette of classes. Subatomic elements that are combined with semantic HTML to make components. The CSS for these functional classes will very likely be smaller than many combined component-specific CSS files.


Great Developer Experience with TypeScript

TypeScript can improve the developer experience with these classes. We can add simple functions that build these class name, checking for typos along the way.

First, let’s expand our styles a little:

.padding-1 { padding: 0.25rem; }
.padding-2 { padding: 0.5rem; }
.padding-4 { padding: 1rem; }

.bg-primary { background: green; }
.bg-warning { background: orange; }
.bg-danger { background: red; }
.bg-light { background: #fafafa; }

.text-dark { color: #111; }
.text-link-color { color: blue; }
.text-danger { color: red; }
.text-light { color: white; }

Let’s make a function for the padding set of classes. You’ll notice they share a common prefix padding-. Available suffixes are 1, 2, and 4 — but not 3, 6, or 8.

How can we make sure no-one would accidentally specify padding-3? We can use a TypeScript union type:

type PaddingSuffix = "1" | "2" | "4";
function padding(paddingSuffix: PaddingSuffix): string {
  return `padding-${paddingSuffix}`;
}

We would then use it like so:

const class1 = padding("1"); // "padding-1"
const class4 = padding("4"); // "padding-4"
const class3 = padding("3"); // TypeScript Error!

Passing "3" to our function would produce an error from TypeScript, which prevents our code from even compiling. We won’t find out that the padding-3 class doesn’t exist when we go to the browser, we’ll find out right away as we are authoring our components.

In a tool like VS Code, we’ll even get autocompletion of the available suffixes!

Let’s apply the same technique for our background and text colors.

type BackgroundSuffix = "primary" | "warning" | "danger" | "light";
function background(backgroundSuffix: BackgroundSuffix): string {
  return `background-${backgroundSuffix}`;
}

type TextSuffix = "dark" | "link-color" | "danger" | "light";
function text(textSuffix: TextSuffix): string {
  return `text-${textSuffix}`;
}
background("primary");   // "background-primary"
background("danger");    // "background-danger"
background("dark-blue"); // TypeScript Error!

text("dark");    // "text-dark"
text("light");   // "text-light"
text("success"); // TypeScript Error!

It’s a very simple technique. The functional class names share a common prefix, which is the same name given to the TypeScript function that will produce them.


What other design elements can we look at? Our simple design system might have two font families: a body font and a monospace font for code. It might have a range of font sizes from XS to XXL. And it might have two font weights, regular (also known as 400) and bold (aka 700).

.font-body {
  font-family: system-ui, BlinkMacSystemFont, -apple-system, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}
.font-mono {
  font-family: Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
}

.font-xs { font-size: 0.75rem; }
.font-s { font-size: 0.875rem; }
.font-base { font-size: 1rem; }
.font-l { font-size: 1.5rem; }
.font-xl { font-size: 2rem; }
.font-xxl { font-size: 4rem; }

.font-400 { font-weight: 400; }
.font-700 { font-weight: 700; }
type FontFamily = "body" | "mono";
type FontSize = "xs" | "s" | "base" | "l" | "xl" | "xxl";
type FontWeight = "400" | "700";
type FontSuffix = FontFamily | FontSize | FontWeight;
function font(...fontSuffixes: Array<FontSuffix>): string {
  return fontSuffixes.map(suffix => `font-${suffix}`).join(" ");
}
/* Valid class names */
font("body");                // "font-body"
font("mono", "s");           // "font-mono font-s"
font("body", "base", "700"); // "font-body font-base font-700"
font("body", "700");         // "font-body font-700"
font("body", "xxl", "700");  // "font-body font-xxl font-700"

/* Invalid class names */
font("sans-serif");          // TypeScript Error!
font("body", "base", "500"); // TypeScript Error!
font("body", "xxxxxxl");     // TypeScript Error!

Notice on the first line how we can specify body without saying what font size and weight? This allows you to still take advantage of CSS’s natural approach of inheriting certain properties such as font size and weight from its ancestors.


Summing up

TypeScript not only gives us safety from typos but ensures a restricted palette of fonts, spacing, and colors is stuck to. This palette is extremely reusable, acting as the subatomic elements of all our components.

Our component become simple mapping from semantic props to semantic HTML and class names — a single file to make changes to instead of separate template and stylesheets. We can predictably make changes instead finding a surprise in the browser, requiring us to hunt down and understand the complex nest of CSS selectors.

It’s a fast user experience. CSS is a known quantity, browsers have optimized it for decades. There’s no dynamically inserted stylesheets. You can serve a single CSS file that is easily cached.

Best of all, it works just as well on the server as in the browser. There’s no tricks required of collected all the styles used, or prerendering. We don’t need to integrate with babel or any other tooling. Its performance is predictable.

Future posts will look at working with media queries and breakpoints, at the :hover, :focus, and :focus-within pseudo classes, at using CSS variables, at more complex conditional logic in components, and integrating with Tailwind, a popular functional (aka utility-first) CSS library.


Categorizing the elements of the modern web

In the world of the web, what is a web app and what is a website is now often blended. It’s not as simple as written content is a website, and an interactive tool is a web app. Blogs can be interactive, they can provide tools, live searching, etc.

This is a high level overview of what fits where, of which rules apply to what elements. It’s mainly for myself to help me develop tools.

Content vs its Vehicle

Content

  • Navigation (Primary, Sidebar, etc)
  • Markdown
  • Images
  • Video

Site or App itself

  • CSS
  • JavaScript
  • Components
  • Icons

Mutable vs Immutable

Mutable Entities

  • Blog posts
  • Page content
  • Tag assignments
  • Editable Markdown
  • Editable components
  • Sessions
  • Git Repositories
  • Figma documents
  • Trello boards
  • Google docs / spreadsheets

Immutable Values

  • Images
  • Text snippets
  • Tags
  • Timestamps
  • Git Commits
  • Git Trees

Derivable Values

  • Resized and encoded images
  • Minified CSS or JavaScript
  • Rendered Markdown
  • Published components’ code
  • Rendered components
  • Cryptographic hashes

The difference between CSS Grid and Flexbox

Smart Reducers with React & Hooks

Hooks are on their way soon to React, which offer ways to manage component state and lifecycles in function components.

Also coming is the reducer, a pattern from the popular library Redux. While I think Redux can make apps more complicated than they need to be, I think reducers as a primitive offer some interesting approaches, and being built into React, perhaps new patterns too.

A counter

So let’s take a simple example of a counter. A counter is backed by an integer value, which gets stored in the component’s state. This state is managed by a reducer: a pure function taking the previous state and an action of some sort, and based on the action will return a new state.

Convention has actions holding a type property, which for our counter will be one of: “increment”, “decrement”, “reset”. We handle each action type in the switch statement of countReducer().

Three buttons are rendered: +1, -1, and reset. Each button has an onClick handler, which will call dispatch() with the particular action type: increment, decrement, or reset.

import React, { useReducer, useCallback } from "react";
import ReactDOM from "react-dom";

const initialState = { count: 0 };

function countReducer(state, action) {
  switch (action.type) {
    case "reset":
      return initialState;
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      return state;
  }
}

function App() {
  const [state, dispatch] = useReducer(countReducer, initialState);

  return (
    <div className="App">
      <h1>{state.count}</h1>
      <button onClick={ () => dispatch("decrement") }>-1</button>
      <button onClick={ () => dispatch("increment") }>+1</button>
      <button onClick={ () => dispatch("reset") }>Reset</button>
    </div>
  );
}

By themselves creating these three onClick handler functions has little overhead. However, because every time our component renders we are creating them from scratch and passing new functions to each button’s onClick, React has to remove the old handlers and add the new ones.

It would be better if we didn’t create these handler functions from scratch each time our component renders. If we create them once, and then reuse them, then React wouldn’t have to perform the work of changing the handlers for the buttons.

Can we avoid the creation of three onClick handlers? Yes, we can with custom data attributes. These attributes must be prefixed with data- but everything that follows can be named as we like. We can access these attributes in JavaScript via the DOM’s dataset property.

So, for each button we could set a data-action-type data attribute, and then read that in the click handler. We could also use the useCallback hook to memoize this click handler.

import React, { useReducer, useCallback } from "react";
import ReactDOM from "react-dom";

const initialState = { count: 0 };

function countReducer(state, action) {
  switch (action.type) {
    case "reset":
      return initialState;
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      return state;
  }
}

function App() {
  const [state, dispatch] = useReducer(countReducer, initialState);
  const onClick = useCallback(
    event => {
      // Find our <button>’s DOM element.
      const buttonEl = event.target;
      // Read the button’s data-action-type attribute.
      // Note the kebab-case becomes camelCase.
      const type = buttonEl.dataset.actionType;
      // Dispatch an action of this button’s type to the reducer.
      dispatch({ type });
    },
    [dispatch]
  );

  // Note each button gets its own `data-action-type`,
  // but shares the same `onClick` prop.
  return (
    <div className="App">
      <h1>{state.count}</h1>
      <button data-action-type="decrement" onClick={onClick}>
        -1
      </button>
      <button data-action-type="increment" onClick={onClick}>
        +1
      </button>
      <button data-action-type="reset" onClick={onClick}>
        Reset
      </button>
    </div>
  );
}

So this should avoid in re-renders the need to remove and add click handlers. Not only are we using a single onClick handler for each button, by using the useCallback hook we ensure the component will creating it only once on the initial render and then reuse it in future renders.

Out of interest, could we go further? Could we reduce what we need to pass to each button and make it nicer to removing the data- from view?

import React, { useReducer, useCallback } from "react";
import ReactDOM from "react-dom";

const initialState = { count: 0 };

function countReducer(state, action) {
  switch (action.type) {
    case "reset":
      return initialState;
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      return state;
  }
}

function App() {
  const [state, dispatch] = useReducer(countReducer, initialState);
  const onClick = useCallback(
    event => {
      // Find our <button>’s DOM element.
      const buttonEl = event.target;
      // Read the button’s data-action-type attribute.
      // Note the kebab-case becomes camelCase.
      const type = buttonEl.dataset.actionType;
      // Dispatch an action of this button’s type to the reducer.
      dispatch({ type });
    },
    [dispatch]
  );
  // Define a memoized component that dispatches actions to our reducer
  const ActionButton = useCallback(
    ({ actionType, ...rest }) => {
      // Map from the nice `actionType` prop into the
      // data attribute `data-action-type`.
      // Also pass the `onClick` which every button will share.
      return (
        <button {...rest} data-action-type={actionType} onClick={onClick} />
      );
    },
    [onClick]
  );

  return (
    <div className="App">
      <h1>{state.count}</h1>
      <ActionButton actionType="decrement">-1</ActionButton>
      <ActionButton actionType="increment">+1</ActionButton>
      <ActionButton actionType="reset">Reset</ActionButton>
    </div>
  );
}

Now, you might be thinking: this is just a simple counter demo. What about passing a payload when we dispatch our actions?

One approach could be to add another prop to our ActionButton component, something like actionPayload. However, if we were to also pass this as a data attribute, we would have to serialise the value, which would add extra overhead and make our component slower.

So, instead let’s rely on the fact that our component are meant to be pure: given a set of props taken as input, then the same output should be rendered every time.

Another way to say this is everything in our component, from the elements rendered to the code inside the event handlers, is derived from our props.

This mean the desired custom action is also derived from our props: given a set of props, the same payload will be calculated every time. Therefore, we can calculate the payload needed on-demand when we dispatch.

Here I have added two new action creators: “increment.by10” and “decrement.by10”. I am using a dot to denote these custom actions, and to show which actual action type will be dispatched.

import React, { useReducer, useCallback } from "react";
import ReactDOM from "react-dom";

const initialState = { count: 0 };

function countReducer(state, action) {
  const payload = action.payload || {};
  switch (action.type) {
    case "reset":
      return initialState;
    case "increment":
      return { count: state.count + (payload.amount || 1) };
    case "decrement":
      return { count: state.count - (payload.amount || 1) };
    default:
      return state;
  }
}

function App() {
  const [state, dispatch] = useReducer(countReducer, initialState);
  const onClick = useCallback(
    event => {
      const buttonEl = event.target;
      const type = buttonEl.dataset.actionType;
      switch (type) {
        // Our custom action creators
        case "increment.by10":
          dispatch({ type: "increment", payload: { amount: 10 } });
          break;
        case "decrement.by10":
          dispatch({ type: "decrement", payload: { amount: 10 } });
          break;
        // Normal reducer action
        default:
          dispatch({ type });
      }
    },
    [dispatch]
  );
  const ActionButton = useCallback(
    ({ actionType, ...rest }) => {
      return (
        <button {...rest} data-action-type={actionType} onClick={onClick} />
      );
    },
    [onClick]
  );

  return (
    <div className="App">
      <h1>{state.count}</h1>
      <ActionButton actionType="decrement">-1</ActionButton>
      <ActionButton actionType="increment">+1</ActionButton>
      <ActionButton actionType="decrement.by10">-10</ActionButton>
      <ActionButton actionType="increment.by10">+10</ActionButton>
      <ActionButton actionType="reset">Reset</ActionButton>
    </div>
  );
}

The reducer has been changed to accept payloads for the “increment” and “decrement” action. However it still remains a pure function, like reducers should be. It’s also lean: we could add “increment.by50” or “increment.by1000” without needing to change our reducer.

You can see or fork an online demo of the above counter here: https://codesandbox.io/s/jlz8pk6yow

Thanks for reading, and if you have any thoughts reach out on Twitter.

Why I hate WordPress but used it anyway for this blog

  1. It gets me writing,
  2. And not wrangling with code.
  3. I get online editing, drafts, Ulysses integration out of the box.
  4. I can make edits and publish from my phone.
  5. My readers get RSS out of the box.
  6. The default 2019 theme looks decent.
  7. It brings categories, pagination, some decent plugins (and some hacky ones).
  8. It renders on the server instead of the client, bringing better SEO.
  9. It doesn’t use service workers which I think applied naively is premature optimisation and a worse user experience.

Handy Makefile Rules and Patterns

Patterns

Required variable

$(or $(build),$(error Must set build variable))

Optional variable with fallback

$(or $(branch),master)

Git

Rebase on origin’s master

rebase_origin_master:
	git pull --rebase origin master

Create a git commit message template with co-authored-by set

# Requires card=…, name=…, and a contributors.txt file
pair:
	@echo "$(card) \n\nCo-authored-by: $(shell grep -i $(name) contributors.txt)" > .git/.gitmessage
	@git config commit.template .git/.gitmessage
	@cat .git/.gitmessage

Rails

Run the most recently modified spec

recent_spec:
	bundle exec rspec $(or $(shell find ./spec -name "*_spec.rb" -cmin -5 -exec ls -1tr "{}" + | tail -n 1),$(error No *_spec.rb file modified recently))

Run specs with changes not yet committed

uncommitted_specs:
	bundle exec rspec $(shell git status --porcelain | grep -E "^[^D][^D] .+_spec.rb$" | cut -c4-)

The CSS Spectrum from Semantic Components to Pragmatic Utilities

A decade or two ago, we usually wrote HTML by hand, whether in templates or as entire pages. Either way, these templates contained raw HTML that formed a structure. They said what was on the page: the semantic meaning behind what presented to the user.

We used ordered or unordered lists, anchors for links, buttons for actions, headings of various priority, and two types of emphasis instead of the predetermined bold and italic elements.

We did this because it made a better experience for our users. They were more accessible, as these semantics could carry over to an audible presentation of the page, or to search engines, or to RSS or read-it-later readers.

But it also made it easier for authors. We had a common language that we could understand and build with. There were various patterns that could be universally understood. You could look at the source code and gleem the intent.

This extended to the styling layer of CSS. Cascading style sheets were separate documents to the pages themselves. Elements on pages would be classed, and in CSS visual rules would be defined for each class. Use the same class on multiple pages, and bam, they would look the same everywhere after having the same rules applied.

Class names could be anything authors desired. They could be single words. They could be multiple words separated by hyphens-like-a-kebab, or allJoinedTogetherWithCapitals. They could have their own little mini hierarchy and system. But, whatever you chose, it didn’t matter. As long as the class names in the HTML and in the CSS matched, they would be applied.

They mattered to authors though. They had to look at them as they made new pages, and evolved the CSS rules. The semantics mattered, and so names that reflected the meaning of the content more than it’s eventual look were desired. A redesign with a new color scheme or rearranged layout could mean throwing all the CSS away if you had names like ‘button-red’ or ‘left-sidebar’. Far better to call them ‘button-danger’ and ‘main-sidebar’, as between redesigns the meaning would stay much the same.

And so we made a rule that CSS class names should not reflect its appearance but its underlying meaning. We broke this rule when we just had to (clearfix anyone?), but doing so was generally regarded as not planning for the future, and, well, just cheating really.

I think in a time of components, we can make some changes. I think we can get rid of many of these semantic CSS classes. Why? Because our components are our semantic layer now.

Remember the structuring of HTML was important for accessibility, but the naming of CSS was really just to make the authors lives easier. Whether a button that looked red to a user had the word ‘red’ in its name or a more considered, meaningful name made no difference to the user. It looked the same, acted the same, and tasted the same (back when UIs looked so good you could lick them).

Components let us organise the building blocks of our pages and UIs into reusables. We can define a DangerButton component, and encapsulated all the styling knowledge inside (whether CSS partials or CSS-in-JS). We can then use this DangerButton in all its glorious meaning again and again, on page after page. When we decide they should no longer be red but bright purple, we have one place to make changes, just like the semantic CSS days.

Our components names and props can convey the full set of meaning, and even better encapsulate not only the styling choices but the amount of HTML too. We don’t need to know the raw elements needed to make a functional link in a navigation bar, we can just use the NavLink component.

So is reusable CSS like we had before encapsulated components dead? I don’t think so.

Utility classes are ultra reusable thin slices of CSS that we assemble to form a complete picture. A DangerButton might have white text on a dark red background, and so we’d use the text-white and bg-red-dark utility classes. We might also sprinkle in text-lg and padding-4 and rounded.

These class names are decidedly not semantic. And they seem to replicate the granularity of CSS rules themselves. Aren’t they just the same as that other villain, inline styles where our CSS is written inside our HTML?

No, because they provide a system. Dark red is defined to one particular shade of crimson and then shared everywhere. The large font size class, text-lg, also can have the exact unit size changed in one exact spot. They might not be semantic, but they don’t spill all their beans.

Plus, they are just plain handy. CSS is fast, caches well, easily made responsive, and works with React or Vue or Elm or Rails. You don’t have to decide which CSS-in-JS library is most in vogue. You don’t even (dare I say) need JS.

Components to utility classes. A spectrum from semantic meaning through to pragmatic efficacy. While it’s not perfect, I think it’s a nice mix of both worlds.

What I plan to learn in 2019

Another year, another set of new shiny technologies to entice you! At Cogent, we recently asked each other what we were planning to learn in 2019. Below is my list: you’ll find a mix of front-end and back-end technologies, as well as some marketing related one.

It’s tempting to learn anything that looks compelling and interesting in any way. I am trying to be a little more particular and choose things that have some maturity. Or things if new, that I think will be here to stay.

One thing I’m keen to learn through is by teaching. To finally have a proper somewhat regular blog and make screencasts. I would start with a blog post, get feedback from people, then record a lesson or walkthrough to share on YouTube.

When I was teaching junior programmers I felt like lots of my knowledge was strengthened by having to articulate concepts that I just took for granted. I’m curious how things work generally so will want to know, but there’s always something that I gloss over — “yep this just works, and I don’t care why or how to do my job”. So it was great to sit down and study these concepts and then explain them in a way that didn’t lead to 35 confused faces.

After wondering if I should focus a blog on a particular topic, I’m thinking I’ll just write about what I’m working on and not worry about if I’m not satisfying ‘web developers’ or whoever with every single post.

What I plan to learn

  • Cloudflare Workers and what they best suit
  • Architecting apps well with the next-gen React
  • Optimising web apps to be faster and leaner
  • GraphQL
  • Golang and what it best suits, maybe compiling it to Webassembly
  • Google App Engine and Datastore
  • Elixir and what it best suits
  • Whether Gigalixir is worthwhile
  • Maybe Websockets and what they best suit
  • Will try CSS Grid again
  • Probably more iOS App development
  • Latest Swift changes
  • Possibly machine learning
  • How to run and launch open source projects
  • Marketing
  • How to plan and write and record screencasts — after teaching I find presenting to a group of people much easier and engaging for me than sitting down and cranking out words
  • How to not over engineer my blog and use something boring like WordPress (Done! You’re reading it)

What I plan to not learn

I find it helpful to have a no list too:

  • Not Reason
  • Not Rust
  • Not Android
  • Probably not React Native unless for a project, then yes
  • Less Node.js
  • Not Electron

I often made ‘no’ lists when teaching for what would not be covered, as it helped to focus the lesson.

What are you planning on learning in 2019? Let me know by tweeting me.

Understanding state

State is what is known by your app.

In a web app, state refers to local state. It only knows a subset of all information. And that information is from a certain point in time: it might have changed since.

In a JavaScript web app, your user’s web browser talks to an API. The API has its own state, usually stored permanently in a database.

(In a server-side web app like one built with Rails, your application usually talks to the database directly.)

So local state. It’s your web app’s state of the world at a certain time. That world depends on factors, such as which account is signed in, or perhaps whether the user is not signed in, which page they are looking at, and what capabilities their account has.

Loading state

For your web app to display information, it has to first load it.

So your web app loads this initial information, and this becomes its state of the world. If five minutes later, the latest information is desired, it must load it again.

Making things more complicated is the fact that there is not just one set of information.

Take Instagram as an example. There is the feed of photos. As you scroll through the feed, more photos are loaded. For a good user experience, photos are loaded before you reach them. But still, only a subset of photos are loaded. It would make little sense to load your feed from the top to the very bottom, as it would likely be hundreds of megabytes of information in total, and be a huge strain on Instagram’s servers to collate all that information.

Instagram offers more than just a feed. Your can explore and search for photos. You can take or upload a photo. You can see a list of activity aimed at you, such as recent comments or likes on your posts. You can also look at your own profile, with the photos you have posted.

Depending on which section you look at, and how you interact within that section (scroll, tap to see details, tap to go to someone’s profile), new information will have to be loaded. The app’s state of the world expands. It goes from a small subset of data, to a larger subset of data.

Managing this state, and coordinating the loading of additional or fresher state, is one of the key skills in building web apps.

A step back. A command line app.

Any app that has an interactive user interface has state. Think of PowerPoint and the file that is being viewed, the currently active slide, whether that slide is being edited, viewed with slides listed to the side, or is being presented. All of those variables are state.

A command line app also has state. The less command efficiently reads from a file, only presenting a slice of it that fits in the terminal window. As the user scrolls and down, the app’s state is updated with the offset slice into the file.

A command line app is a useful starting point, because many operate in the same manner as web apps based on React. In React, the application is built by deriving the entire user interface from state. The application developer declares their intent for what should be displayed on screen given a certain state. If the state changes, then that codified intent is used again, but with the updated state. And so on, every user interaction usually affects the state in some way, and the user interface is updated quickly to respond. This pipeline approach is popular with games, where the displayed image is rebuilt again and again many times a second, fast enough to produce fluid motion.

The alternative is to intertwine the state with what is being presented. As new information comes in, it is not a simple change to state. It is a manual change to what’s on screen too.

A pipeline is like to correct a typo in a printed document, making the change in software, throwing the old copy away, and printing a new fresh copy. Fortunately, in an app built totally with software means that nothing is wasted.

An intertwined approach is more akin to correcting a typo by using whiteout and a fine pen. It’s much less wasteful, but takes much more effort and skill than just printing a new copy would be. The same is true for apps.