Tag: Developers

Typography for Developers

Taimur Abdaal leads design at Retool, a fast way to build internal tools. They’re working on a new design system for their platform, to let anyone easily build beautiful custom apps. Typography will be a huge part of this and Taimur wrote this based on that experience.

You may have read the title for this post and thought, “Why on earth does a developer need to know anything about typography?” I mean, there’s already a lot on your plate and you’re making hundreds of decisions a day. Should you use React or Vue? npm or Yarn? ES6 or ES7? Sadly, this often leaves something like type as an afterthought. But, let’s remember that web design is 95% typography:

95% of the information on the web is written language. It is only logical to say that a web designer should get good training in the main discipline of shaping written information, in other words: Typography.

Even though we deal with content everyday — whether reading, writing, or designing it — typography can be daunting to delve into because it’s filled with jargon and subjectivity, and it’s uncommon to see it taught extensively at school.

This is intended as a practical guide for developers to learn web typography. We’ll cover a range of practical and useful topics, like how to choose and use custom fonts on the web, but more importantly, how to lay text out to create a pleasant user experience. We’ll go over the principles of typography and the CSS properties that control them, as well as handy tips to get good results, quickly.

What is typography?

First and foremost, typography is about usability. Type is the user interface for conveying information, and conveying information is what we’re here to do on the web. There are many levers we can pull to affect the usability of reading text, and only by being deliberate about these can we create a pleasant experience for our users.

After (and only after) usability, typography is about emotion. Do the letters complement your content, or contradict it? Do they amplify your brand’s personality, or dampen it? Applied to the same text, different type will make people feel different things. Being deliberate about typography lets us control these feelings.

Same text, different personalities. I’ll bet the first experience is much more expensive. Typefaces: Bodoni 72 (Top), Tsukushi A Round Gothic (Bottom)

Despite what many golden ratio enthusiasts might try to tell you, typography isn’t an exact science. Good guidelines will get you most of the way there, but you’ll need to apply a little intuition too. Luckily, you’ve been reading text your whole life — books, magazines, the Internet — so you have a lot more untapped intuition than you think!

What’s in a font?

Let’s start off by getting a handle on some basic terminology and how fonts are categorized.

Typeface vs. Font

This is how the two have traditionally been defined and distinguished from one another:

  • Typeface: The design of a collection of glyphs (e.g. letters, numbers, symbols)
  • Font: A specific size, weight, or style of a typeface (e.g. regular, bold, italic)

In essence, a typeface is like a song and a font is like its MP3 file. You’ll see both terms used in typography literature, so it’s worth knowing the distinction. “Font vs. Typeface” is also a bit of meme in the design community — you might see it crop up on Twitter, so it’ll help to be “in the know.”

But, more recently, you can essentially use both terms interchangeably and people will know what you mean.

How fonts are categorized

The broadest split is between serif and sans-serif typefaces. It’s likely you’ve come across these terms just by seeing some some typeface names floating around (like, ahem, Comic Sans).

A “serif” is a small stroke attached to the ends of letters, giving them a traditional feel. In fact, most books and newspapers are set in serif typefaces. On the contrary, sans-serif typefaces don’t have these extra strokes, giving them a smooth, modern feel.

Times (left) and Helvetica Neue (right)

Both serif and sans-serif have categories within them. For example, serif has sub-categories including didone, slab and old style.

Didot (left), Rockwell (center) and Hoefler Text (right)

As far as sans-serif goes, it includes humanist, geometric and grotesk as sub-categories.

Gill Sans (left), Futura (center) and Aktiv Grotesk (right)

Monospace fonts (yes, fonts) are a noteworthy category all its own. Each glyph (i.e. letter/number/symbol) in a monospace font has the same width (hence the mono spacing terminology), so it’s possible to arrange them into visual structures. You may be well familiar with monospace because we see it often when writing code, where it’s helpful to make brackets and indents line up visually. The code editor you have open right now is likely using monospace.


How to choose fonts and font pairings

This is subjective, and depends on what you’re trying to do. Each typeface has its own personality, so you’ll have to find one that aligns with your brand or the content it’s communicating. Typefaces have to be considered within the context that they’re being applied. Are we looking for formality? Maybe start with the serif family. Warm, fun and friendly? That might be a cue for sans-serif. Heck, there’s a time and a place even for Comic Sans… really! Just know that there is no hard science to choosing a font, and even the most trained of typographers are considering contextual cues to find the “right” one.

But fonts can be paired together in the same design. For example, some designs use one typeface for headings and another for body text. This is a good way to get a unique look, but it does take a fair bit of work to get it right. Like colors in a palette, some typefaces work well together while others clash. And even purposeful clashing can make sense, again, given the right context.

The only way to find out if two fonts are complementary is to see them together. Tools like FontPair and TypeConnection can help with this. If a font catches your eye when surfing the web, WhatFont is a great browser extension to help identify it. Another great resource is Typewolf which allows you to see examples of great web typography, including different font combinations in use:

Alice Lee (left), American Documentary (center) and Studio Stereo (right)

While there’s a lot of subjectivity in choosing fonts, there are some objective considerations.

Font weight as a consideration

Some font families have a wide range of font weights — Light, Book, Regular, Medium, Semi-Bold, Bold, Black — whereas others just have a couple.

Inter UI comes with a fantastic range of weights

If you’re building a complex web app UI, you might need a range of font weights to establish hierarchy in different contexts. For something less complex, say a blog, you’ll likely be fine with just a couple.

Complex UI hierarchy (left) and Simple blog hierarchy (right)

Variable fonts are an exciting new technology that provide precise control over a font’s characteristics. For font weights, this means there’s no longer limitations to using “Light,” “Regular,” and “Bold,” but really any weight in between. Try some variable fonts out here and check out Ollie Williams’ post as well.

It’s still early days — there aren’t many variable fonts available right now, and browser support is limited. But definitely a space worth watching!

Consider the legibility of a font

Some typefaces are harder to read than others. Stay away from elaborate fonts when it comes to paragraphs, and if you must have tiny text somewhere, make sure its typeface is legible at those tiny sizes.

Of these two examples, which is easier on the eyes? (There is a right answer here. 🙂)

See the Pen
Font Comparison: Body
by Geoff Graham (@geoffgraham)
on CodePen.

Remember, fonts come in a variety of styles

Making a font bold isn’t as simple as adding an outline to the text, and italics are more than slanted letters. Good fonts have specific bold and italic styles, without which the browser tries to “fake” it:


These faux styles tend to reduce legibility and break the text’s visual cohesion because the browser can only do so much with what it’s given. Stick to fonts that offer true bold/italics styles, if you can.

Other things worth consideration

What we’ve looked at so far are the high level characteristics and features of fonts that can help us decide which to choose for a particular design or context. There are many other things that can (and probably should) be taken into consideration, including:

  • Language support: Some fonts have glyphs for foreign characters, which may be a requirement for a project geared toward a multilingual audience or that contains multilingual content.
  • Ligatures: Some fonts (typically serifs) have glyphs to replace otherwise awkward characters, like ffi and ffl which are multiple characters in a single glyph.
  • File size: You’re a developer, so I know you care about performance. Some fonts come in bigger files than others and those can cause a site to take a hit on load times.

Using fonts on the world wide web

A mere 10 years ago, there were two complex ways to use custom fonts on the web:

  • SiFR: Embedding a Flash (remember that thing?) widget to render text.
  • cufon: converting the font to a proprietary format, and using a specific JavaScript rendering engine to generate the text using VML on an HTML <canvas>.

Today, there’s all we need is a single simple one: @font-face. It lets you specify a font file URL, which the browser then downloads and uses on your site.

You can use the @font-face declaration to define your custom font:

@font-face {   font-family: 'MyWebFont';   src: url('webfont.eot'); /* IE9 Compat Modes */   src: url('webfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */         url('webfont.woff2') format('woff2'), /* Super Modern Browsers */         url('webfont.woff') format('woff'), /* Pretty Modern Browsers */         url('webfont.ttf')  format('truetype'), /* Safari, Android, iOS */         url('webfont.svg#svgFontName') format('svg'); /* Legacy iOS */ }

And then refer to it as normal, by the font-family attribute:

body {   font-family: 'MyWebFont', Fallback, sans-serif; }

Even though @font-face is light years ahead of the old school approaches to custom web fonts, there is quite a bit to consider as far as browser support goes. Here’s a guide to getting the right amount of cross-browser support.

The impact of fonts on performance

Performance is the only downside to using custom fonts on the web. Fonts are relatively large assets — often hundreds of kilobytes in size — and will have and adverse effect on the speed of any site.

Here are some tips to soften the blow:

  • Use GZIP compression on your web font files.
  • Disable font features you don’t need, e.g. hinting, kerning.
  • Remove glyphs that you don’t need, e.g. foreign language characters.

One tool that can help tailor a font file to suit your needs is Transfonter. Just make sure you have the rights to any font that you want to use on your site because, well, it’s just the right thing to do.

Some services will host web fonts for you

One other significant way to shed some of the weight of using custom web fonts is to use a service that will host and serve them for you. The benefit here is that third-parties store the files on a speedy CDN, optimize them, and serve them to your site via a JavaScript snippet that gets dropped into the document head. In short: it takes a lot of hassle off your hands.

How easy is it to use a hosted service? Consider that using anything on Google Fonts only requires a single <link> in the HTML head:

<html>   <head>     <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">   <style>     body {       font-family: 'Roboto', sans-serif;     }   </style> </head>  <!-- Rest of the document -->

This example was taken from Google Fonts — the most popular hosted font service. It’s free to use, and, at the time of writing, has a catalogue of 915 font families. The quality of these can be hit-or-miss. Some are truly top-notch — beautiful design, many weights, true bold/italics, and advanced features like ligatures. Others, typically the more novel designs, are bare-bones, and might not be suitable for serious projects with evolving needs.

Adobe Fonts is also very popular. It comes bundled with Adobe’s Creative Cloud offering, which starts at $ 20.99 per month. At the time of writing, it has a catalogue of 1,636 font families. These are typically high quality fonts that you’d have to pay for, but with Adobe Fonts, you can access them all in a Netflix all-you-can-eat model.

Here are some other options:

  • Adobe Edge Web Fonts: This is the free version of Adobe Fonts. Adobe partnered with Google on this, so there’s a lot of overlap with the Google Fonts library. It has 503 font families in total.
  • Fontspring: This is a massive library of over 14,000 font families, but with an individual licensing model. This means paying more up-front, starting at ~$ 20 per individual font (and per weight or style), but no recurring costs. It’s also self-serve — you’ll have to host the files yourself.
  • MyFonts by Monotype: This is major type foundry. Similar to Fontspring: massive library of font families with an individual licensing model.
  • Fonts.com: This is similar to Fontspring. Options for one-off or pay-as-you go pricing (based on page views).
  • Cloud.typography by Hoefler&Co: This is a major type foundry. Over 1,000 font families (all by Hoefler&Co), with options for hosted (subscription, starting at $ 99 per year) or self-hosted (individually licensed) web fonts. The benefit here is that you get access to a library of fonts you cannot find anywhere else.
  • Fontstand: This services allows you to “rent” individual fonts cheaply on a monthly basis, starting ~$ 10 per month), which you get to own automatically after 12 months. To date, it boasts 1,500 families, with a hosted web font service.

CSS and Typography

OK, let’s move on to the intersection of design and development. We’ve covered a lot of the foundational terms and concepts of typography, but now we can turn our attention to what affordances we have to manipulate and style type, specifically with CSS.

Adjusting font sizing

Changing the size of a font is something that inevitably pops up in a typical project. Size is important because it creates hierarchy, implicitly guiding the user through the page. So, in this section, we’re going to look at two CSS features that are available in our tool belt for adjusting font sizes to create better content hierarchy.

Sizes can be expressed in a different units of measure

Did you know that there are 15 different units for sizing in CSS? Crazy, right? Most of us are probably aware of and comfortable working with pixels (px) but there are so many other ways we can define the size of a font.

Some of these are relative units, and others are absolute. The actual size of an element expressed in relative units depends on other parts of the page, while the actual size of an element expressed in absolute units is always the same. And, as you might expect, that difference is important because they serve different functions, depending on a design’s needs.

Of the 15 units we have available, we will selectively look at two in particular: px and em. Not only are these perhaps the two most used units that you’ll see used to define font sizes, but they also perfectly demonstrate the difference between absolute and relative sizing.

First off, px is an absolute unit and it actually doesn’t have much to do with pixels (it’s considered an angular measurement), but it’s defined so that a line of width 1px appears sharp and visible, no matter the screen resolution. The px value corresponds, roughly, to a little more than the distance from the highest ascender (e.g. the top of the letter A) to the lowest descender (e.g. the bottom of the letter p) in the font. Some fonts have taller letters than others, so 16px in one font might look noticeably “bigger” than 16px in another. Yet another consideration to take into account when choosing a font!

Interestingly enough, when it comes to typography, the px is a unit to be understood, but not used. The true purpose of px units is to serve as the foundation of a type system based on relative units. In other words, it’s an absolute value that a relative unit can point to in order to define its own size relative to that value.

Which takes us to em, a relative unit. Text with a font size of 2em would be twice as big as the font-size of its parent element. The body doesn’t have a parent element, but each device has its own default font-size for the body element. For example, desktop browsers usually default to 16px. Other devices (e.g. mobile phones and TVs) might have different defaults that are optimized for their form factors.

The em lets you reason about your typography intuitively: “I want this title to be twice as big as the paragraph text” corresponds directly to 2em. It’s also easy to maintain — if you need a media query to make everything bigger on mobile, it’s a simple matter of increasing one font-size attribute. Dealing in em units also lets you set other typographical elements in relation to font-size, as we’ll see later.

There are semantic HTML elements that CSS can target to adjust size

You’re sold on the em, but how many em units should each element be? You’ll want to have a range of text sizes to establish hierarchy between different elements of your page. More often than not, you’ll see hierarchies that are six level deep, which corresponds to the HTML heading elements, h1 through h6.

The right size scale depends on the use case. As a guideline, many people choose to use a modular scale. That refers to a scale based on a constant ratio for successive text elements in the hierarchy.

Example of a modular scale with a ratio of 1.4

Modular Scales is a tool by Tim Brown, who popularized this approach, which makes it easy to visualize different size scales.

Adjusting a font’s vertical spacing and alignment

The physical size of a font is a super common way we use CSS to style a font, but vertical spacing is another incredibly powerful way CSS can help improve the legibility of content.

Use line-height to define how tall to make a line of text

Line height is one of the most important factors affecting readability. It’s controlled by the line-height property, best expressed as a unit-less number that corresponds to a multiple of the defined font size.

Let’s say we are working with a computed font size of 16px (specified in the CSS as em units, of course), a line-height of 1.2 would make each line 19.2px tall. (Remember that px aren’t actually pixels, so decimals are valid!)

Most browsers default to a line-height of 1.2 but the problem is that this is usually too tight — you probably want something closer to 1.5 because provides a little more breathing room for your eyes when reading.

Here are some general guidelines to define a good line height:

  • Increase line-height for thick fonts
  • Increase line-height when fonts are a dark color
  • Increase line-height for long-form content
Increasing the line-height can drastically improve legibility
Fonts can’t dance, but they still have rhythm

Rhythm describes how text flows vertically on a page. Much like music, some amount of consistency and structure usually leads to good “rhythm.” Like most design techniques, rhythm isn’t an exact science but there are some sensible guidelines that give good results.

One school of thought prescribes the use of paragraph line height as a baseline unit from which all other spacing is derived. This includes gaps between paragraphs and headings, and padding between the text and other page elements.

Under this system, you might set the line height of a heading to twice the line height of paragraphs, and leave a one-line gap between a heading and paragraph. Handily, you can use the same em units to define margins and padding, so there’s really no need to hard-code anything.

Read more about rhythm here.

Horizontal Shape

Hopefully you’re convinced by now that vertical spacing is an important factor in improving legibility that we can control in CSS. Equally important is the horizontal spacing of individual characters and the overall width of content.

CSS can control the space between letters

Letter spacing is one of the most important factors affecting legibility. It is controlled by the CSS letter-spacing property, best expressed (again) in em units to keep everything relative. Tracking (the typography term for “letter spacing”) depends entirely on the font — some fonts will look great by default, while others might need a little tweaking.

In general, you only need to worry about letter spacing for text elements that are particularly big or small because most fonts are spaced well at a typical paragraph size.

For larger text, like headings and titles, you’ll often want to reduce the space between letters. And a little bit of space goes a long way. For example, -0.02em is a tiny decimal, but a good starting point, which can be tweaked until it looks just right to your eye. The only time you should think about increasing letter spacing is when dealing with stylistically unusual text — things like all-capped titles and even some number sequences.

Adding or subtracting as little as 0.02em can refine the appearance of words

Some specific pairs of letters, like AV, can look awkwardly spaced without a little manual tweaking. Well-crafted fonts typically specify custom spacing for such pairs, and setting the font-kerning property to normal lets you enable this. Browsers disable this on smaller text by default. Here is a little more on letter spacing, as well as other CSS tools we have to control font spacing in general.

The length of a line of text is more important than you might think

It’s unpleasant for our eyes to move long distances while reading, so the width of lines should be deliberate. General consensus is that a good width is somewhere between 60 and 70 characters per line. If you find that a line of text (especially for long-form content) drastically falls outside this range, then start adjusting.

The ch is a little-known CSS unit that we didn’t cover earlier, but can be helpful to keep line length in check. It’s a relative unit, defined as the width of the 0 character in the element’s font. Because narrow characters like l and i are relatively frequent, setting the width of a text container to something like 50ch should result in lines that are 60-70 character long.

p {   width: 50ch; }

CSS can smooth otherwise crispy fonts

-webkit-font-smoothing is a nifty CSS property that controls how fonts are anti-aliased. This is a fancy way of saying it can draw shades of gray around otherwise square pixels to create a smoother appearance. Do note, however, the -webkit prefix there, because that indicates that the property is only supported by WebKit browsers, e.g. Safari.

The default setting is subpixel-antialiased, but it’s worth seeing what your type looks like when it’s set to just antialiased. It can improve the way many fonts look, especially for text on non-white backgrounds.

At small font sizes, this should be used with caution — it lowers contrast, affecting readability. You should also make sure to adjust letter-spacing when using this, since greater anti-aliasing will increase the space between letters.

Anti-aliased (left) Subpixel Anti-aliased (right)

Wrapping up

Phew! We covered a lot of ground in a relatively short amount of space. Still, this is by no means an exhaustive guide, but rather, something that I hope will encourage you to take more control over the typography in your future projects, and to seek an even deeper knowledge of the topic. For that, I’ve compiled a list of additional resources to help you level up from here.

Learning about typography

Typography Inspiration

Identifying Fonts

  • WhatFont
  • Identifont
  • WhatTheFont
  • Typography in CSS

    The post Typography for Developers appeared first on CSS-Tricks.



    Front-End Developers Have to Manage the Loading Experience

    Web performance is a huge complicated topic. There are metrics like total requests, page weight, time to glass, time to interactive, first input delay, etc. There are things to think about like asynchronous requests, render blocking, and priority downloading. We often talk about performance budgets and performance culture.

    How that first document comes down from the server is a hot topic. That is where most back-end related performance talk enters the picture. It gives rise to architectures like the JAMstack, where gosh, at least we don’t have to worry about index.html being slow.

    Images have a performance story all to themselves (formats! responsive images!). Fonts also (FOUT’n’friends!). CSS also (talk about render blocking!). Service workers can be involved at every level. And, of course, JavaScript is perhaps the most talked about villain of performance. All of this is balanced with perhaps the most important general performance concept: perceived performance. Front-end developers already have a ton of stuff we’re responsible for regarding performance. 80% is the generally quoted number and that sounds about right to me.

    For a moment, let’s assume we’re going to build a site and we’re not going to server-side render it. Instead, we’re going to load an empty document and kick off data API calls as quickly as we can, then render the site with that data. Not a terribly rare scenario these days. As you might imagine, >we now have another major concern: handling the loading experience.

    I mused about this the other day. Here’s an example:

    I’d say that loading experience is pretty janky, and I’m on about the best hardware and internet connection money can buy. It’s not a disaster and surely many, many thousands of people use this particular site successfully every day. That said, it doesn’t feel fast, smooth, or particularly nice like you’d think a high-budget website would in these Future Times.

    Part of the reason is probably because that page isn’t server-side rendered. For whatever reason (we can’t really know from the outside), that’s not the way they went. Could be developer efficiency, security, a temporary state during a re-write… who knows! (It probably isn’t ignorance.)

    What are we to do? Well, I think this is a somewhat new problem in front-end development. We’ve told the browser: “Hey, we got this. We’re gonna load things all out of order depending on when our APIs cough stuff up to us and our front-end framework decides it’s time to do so.” I can see the perspective here where this isn’t ideal and we’ve given up something that browsers are incredibly good at only to do it less well ourselves. But hey, like I’ve laid out a bit here, the world is complicated.

    What is actually happening is that these front-end frameworks are aware of this issue and are doing things to help manage it. Back in April of this year, Dan Abramov introduced React Suspense. It seems like a tool for helping front-end devs like us manage the idea that we now need to deal with more loading state stuff than we ever have before:

    At about 14 minutes, he gets into fetching data with placeholder components, caching and such. This issue isn’t isolated to React, of course, but keeping in that theme, here’s a conference talk by Andrew Clark that hit home with me even more quickly (but ultimately uses the same demo and such):

    Just the idea of waiting to show spinners for a little bit can go a long way in de-jankifying loading.

    Mikael Ainalem puts a point on this in a recent article, A Brief History of Flickering Spinners. He explains more clearly what I was trying to say:

    One reason behind this development is the change we’ve seen in asynchronous programming. Asynchronous programming is a lot easier than it used to be. Most modern languages have good support for loading data on the fly. Modern JavaScript has incorporated Promises and with ES7 comes the async and await keywords. With the async/await keywords one can easily fetch data and process it when needed. This means that we need to think a step further about how we show users that data is loading.

    Plus, he offers some solutions!

    See the Pen Flickering spinners by Mikael Ainalem (@ainalem) on CodePen.

    We’ve got to get better at this.

    The post Front-End Developers Have to Manage the Loading Experience appeared first on CSS-Tricks.


    , , , ,

    A Guide to Custom Elements for React Developers

    I had to build a UI recently and (for the first time in a long while) I didn’t have the option of using React.js, which is my preferred solution for UI these days. So, I looked at what the built-in browser APIs had to offer and saw that using custom elements (aka Web Components) may just be the remedy that this React developer needed.

    Custom elements can offer the same general benefits of React components without being tied to a specific framework implementation. A custom element gives us a new HTML tag that we can programmatically control through a native browser API.

    Let’s talk about the benefits of component-based UI:

    • Encapsulation – concerns scoped to that component remain in that component’s implementation
    • Reusability – when the UI is separated into more generic pieces, they’re easier to break into patterns that you’re more likely to repeat
    • Isolation – because components are designed to be encapsulated and with that, you get the added benefit of isolation, which allows you scope bugs and changes to a particular part of your application easier

    Use cases

    You might be wondering who is using custom elements in production. Notably:

    • GitHub is using custom elements for their modal dialogs, autocomplete and display time.
    • YouTube’s new web app is built with Polymer and web components.

    Similarities to the Component API

    When trying to compare React Components versus custom elements, I found the APIs really similar:

    • They’re both classes that aren’t “new” and are able that extend a base class
    • They both inherit a mounting or rendering lifecycle
    • They both take static or dynamic input via props or attributes


    So, let’s build a tiny application that lists details about a GitHub repository.

    Screenshot of end result

    If I were going to approach this with React, I would define a simple component like this:

    <Repository name="charliewilco/obsidian" />

    This component takes a single prop — the name of the repository — and we implement it like this:

    class Repository extends React.Component {   state = {     repo: null   };    async getDetails(name) {     return await fetch(`https://api.github.com/repos/$ {name}`, {       mode: 'cors'     }).then(res => res.json());   }    async componentDidMount() {     const { name } = this.props;     const repo = await this.getDetails(name);     this.setState({ repo });   }    render() {     const { repo } = this.state;      if (!repo) {       return <h1>Loading</h1>;     }      if (repo.message) {       return <div className="Card Card--error">Error: {repo.message}</div>;     }      return (       <div class="Card">         <aside>           <img             width="48"             height="48"             class="Avatar"             src={repo.owner.avatar_url}             alt="Profile picture for $ {repo.owner.login}"           />         </aside>         <header>           <h2 class="Card__title">{repo.full_name}</h2>           <span class="Card__meta">{repo.description}</span>         </header>       </div>     );   } }

    See the Pen React Demo – GitHub by Charles (@charliewilco) on CodePen.

    To break this down further, we have a component that has its own state, which is the repo details. Initially, we set it to be null because we don’t have any of that data yet, so we’ll have a loading indicator while the data is fetched.

    During the React lifecycle, we’ll use fetch to go get the data from GitHub, set up the card, and trigger a re-render with setState() after we get the data back. All of these different states the UI takes are represented in the render() method.

    Defining / Using a Custom Element

    Doing this with custom elements is a little different. Like the React component, our custom element will take a single attribute — again, the name of the repository — and manage its own state.

    Our element will look like this:

    <github-repo name="charliewilco/obsidian"></github-repo> <github-repo name="charliewilco/level.css"></github-repo> <github-repo name="charliewilco/react-branches"></github-repo> <github-repo name="charliewilco/react-gluejar"></github-repo> <github-repo name="charliewilco/dotfiles"></github-repo>

    See the Pen Custom Elements Demo – GitHub by Charles (@charliewilco) on CodePen.

    To start, all we need to do to define and register a custom element is create a class that extends the HTMLElement class and then register the name of the element with customElements.define().

    class OurCustomElement extends HTMLElement {} window.customElements.define('our-element', OurCustomElement);

    And we can call it:


    This new element isn’t very useful, but with custom elements, we get three methods to expand the functionality of this element. These are almost analogous to React’s lifecycle methods for their Component API. The two lifecycle-like methods most relevant to us are the disconnectedCallBack and the connectedCallback and since this is a class, it comes with a constructor.

    Name Called when
    constructor An instance of the element is created or upgraded. Useful for initializing state, settings up event listeners, or creating Shadow DOM. See the spec for restrictions on what you can do in the constructor.
    connectedCallback The element is inserted into the DOM. Useful for running setup code, such as fetching resources or rendering UI. Generally, you should try to delay work until this time
    disconnectedCallback When the element is removed from the DOM. Useful for running clean-up code.

    To implement our custom element, we’ll create the class and set up some attributes related to that UI:

    class Repository extends HTMLElement {   constructor() {     super();      this.repoDetails = null;      this.name = this.getAttribute("name");     this.endpoint = `https://api.github.com/repos/$ {this.name}`         this.innerHTML = `<h1>Loading</h1>`   } }

    By calling super() in our constructor, the context of this is the element itself and all the DOM manipulation APIs can be used. So far, we’ve set the default repository details to null, gotten the repo name from element’s attribute, created an endpoint to call so we don’t have to define it later and, most importantly, set the initial HTML to be a loading indicator.

    In order to get the details about that element’s repository, we’re going to need to make a request to GitHub’s API. We’ll use fetch and, since that’s Promise-based, we’ll use async and await to make our code more readable. You can learn more about the async/await keywords here and more about the browser’s fetch API here. You can also tweet at me to find out whether I prefer it to the Axios library. (Hint, it depends if I had tea or coffee with my breakfast.)

    Now, let’s add a method to this class to ask GitHub for details about the repository.

    class Repository extends HTMLElement {   constructor() {     // ...   }    async getDetails() {     return await fetch(this.endpoint, { mode: "cors" }).then(res => res.json());   } }

    Next, let’s use the connectedCallback method and the Shadow DOM to use the return value from this method. Using this method will do something similar as when we called Repository.componentDidMount() in the React example. Instead, we’ll override the null value we initially gave this.repoDetails — we’ll use this later when we start to call the template to create the HTML.

    class Repository extends HTMLElement {   constructor() {     // ...   }    async getDetails() {     // ...   }    async connectedCallback() {     let repo = await this.getDetails();     this.repoDetails = repo;     this.initShadowDOM();   }    initShadowDOM() {     let shadowRoot = this.attachShadow({ mode: "open" });     shadowRoot.innerHTML = this.template;   } }

    You’ll notice that we’re calling methods related to the Shadow DOM. Besides being a rejected title for a Marvel movie, the Shadow DOM has its own rich API worth looking into. For our purposes, though, it’s going to abstract the implementation of adding innerHTML to the element.

    Now we’re assigning the innerHTML to be equal to the value of this.template. Let’s define that now:

    class Repository extends HTMLElement {   get template() {     const repo = this.repoDetails;        // if we get an error message let's show that back to the user     if (repo.message) {       return `<div class="Card Card--error">Error: $ {repo.message}</div>`     } else {       return `       <div class="Card">         <aside>           <img width="48" height="48" class="Avatar" src="$ {repo.owner.avatar_url}" alt="Profile picture for $ {repo.owner.login}" />         </aside>         <header>           <h2 class="Card__title">$ {repo.full_name}</h2>           <span class="Card__meta">$ {repo.description}</span>         </header>       </div>       `     }   } }

    That’s pretty much it. We’ve defined a custom element that manages its own state, fetches its own data, and reflects that state back to the user while giving us an HTML element to use in our application.

    After going through this exercise, I found that the only required dependency for custom elements is the browser’s native APIs rather than a framework to additionally parse and execute. This makes for a more portable and reusable solution with similar APIs to the frameworks you already love and use to make your living.

    There are drawbacks of using this approach, of course. We’re talking about various browser support issues and some lack of consistency. Plus, working with DOM manipulation APIs can be very confusing. Sometimes they are assignments. Sometimes they are functions. Sometimes those functions take a callback and sometimes they don’t. If you don’t believe me, take a look at adding a class to an HTML element created via document.createElement(), which is one of the top five reasons to use React. The basic implementation isn’t that complicated but it is inconsistent with other similar document methods.

    The real question is: does it even out in the wash? Maybe. React is still pretty good at the things it’s designed to be very very good at: the virtual DOM, managing application state, encapsulation, and passing data down the tree. There’s next to no incentive to use custom elements inside that framework. Custom elements, on the other hand, are simply available by virtue of building an application for the browser.

    Learn more

    The post A Guide to Custom Elements for React Developers appeared first on CSS-Tricks.


    , , , ,