Image without description
  • Jacco Meijer
  • |
  • Mar 21, 2024

UI Library with MDX documentation

Using the simple Render JSX plugin for Esbuild this post shows how to setup a simple UI library.

Render JSX plugin for Esbuild

The last post showed a simple plugin for Esbuild.

Image without description
  • Jacco Meijer
  • |
  • Mar 21, 2024

Render JSX plugin for Esbuild

Transform Esbuild generated JSX bundles to HTML pages.

Enhanced plugin

This plugin was enhanced with a few lines of code to support Front Matter, CSS bundles and images. The enhanced plugin was used to create a small JSX UI library known as Green Lib.

Eleventy MDX

Once MDX became a supported template language for Eleventy, the enhanced plugin was of little use anymore and all content was migrated to a Eleventy setup. The Green Lib survived this migration.

Green Lib

The library documents each compontent with a MDX document. Very simular - but much simpler - to tools like Stoybook.

A quick reference implementation shows the library capabilities. It simply renders all components.

Fast evolving CSS

This post is part of a series that originated with the question "can the Contentful-Gatsby-Netlify trio be simplified?".

The original idea to put this trio together goes back to 2018. Six years later, much has changed in the world of CSS.

CSS Specificity

A classic CSS challenge is CSS specificity. The selector with the highest specificity value wins. Inline styles have a specificity of 1000 which could only be overridden by the !important rule. Lots of fun!

This challenge resulted in theories like the Inverted Triangle CSS.

ITCSS

"Specificity is inversely proportional to how many elements they affect."

Similar concepts to manage specificity are in this library. The structure (objects) and utility classes have a lot in common with ITCSS.

CSS Cascade Layers

The @layer rule added in 2022 greatly improved managing specificity. When importing CSS like this:

@import './css/global/reset.css' layer(reset);
@import './css/global/markdown.css' layer(markdown);
@import './bundles/css/structures.css' layer(structures);
@import './bundles/css/components.css' layer(components);
@import './bundles/css/utilities.css' layer(utilities);

Specificity can be managed like this:

@layer reset, markdown, structures, components, ce, utilities, custom;

CSS on the custom layer will always override CSS on the layers below. This is a great way to manage the cascade. No need for the !important rule anymore!

:is and :where

A concise way of writing rules and more control over specificity:

  • :is(list) → specificity is set to the most specific selector in the list
  • :where(list) → removes specificity for all selectors in the list

Clamp

Clamp is another useful addition to modern CSS. Amongst many things, it allows for dynamic font and space scales. This library uses scales generated at Utopia.

Design tokens and CSS Custom Properties

Space scales are added to the project by using design tokens.

Design tokens allow for importing things like colors and spaces from Figma directly into CSS. This library uses the design-tokens-cli package to covert Design Tokens to CSS Custom Properties.

More on that at the W3C Design tokens community group. This is the latest version of the spec.

Eslint v9

Not a CSS improvement, but working with JSX, a relevant change in the landscape. Eslint finally decided on a new eslint config format called flat config. The VSCode Eslint plugin has a Experimental: Use Flat Config flag which makes the plugin work with the new (greatly improved!) config.

Native Nested CSS

The list of CSS improvements is long. Nested CSS is natively supported by all major browsers. No more need for a CSS preprocessor to use this.

Container queries

Another interesting addition is what is named 'container queries'. When defining:

.parent {
  container-type: inline-size;
}

Children of this parent can use:

@container (min-width: 700px) {
  .child h3 {
    font-size: 2em;
  }
}

This gives a lot more control than the existing media queries.

Web components

By experiment, two components in the library have been set up as Custom Elements with isolated shadow DOM. The components were elected because they require Javascript to function.

This works well, but faces all the problems of styling Custom Elements.

NOTE: Zach Leatherman, author of 11ty, wrote a great post on the modern issues of styling Custom Elements.

The library produces one CSS bundle which can be reused in the Custom Element. Because the browser caches the bundle, it will not be downloaded twice. Still, this solution is not perfect. As outlined by Zach in the post mentioned above.

Declarative Shadow Dom

Since Feb 20, 2024 all major browsers support 'Declarative Shadow Dom'. The declarative part means that 'Shadow Dom' can be enabled without Javascript:

<template shadowrootmode="open"></template>

This brings the advantages of isolating Javascript and styling. Obviously, isolation makes sharing styles harder.

React build

The current library is simply part of the site build and MDX imports are like this:

import { Topic } from '../../../green-lib/components/topic/topic'

The library can easily be turned into a React npm package. Enabling reuse and verioning. Imprting would then be:

import { Topic } from '@jaccomeijer/green-lib/react'

Using the first import, a bundle could be created for e.g. Preact or another JSX Factory. The second is useful for frameworks like NextJs and Astro.

Conclusion

Setting up the library was straightforward because of the simplicity and speed of Esbuild. Having a MDX document right next to the CSS provides for a quick way to draft up a component. It's like developing a library with a UI Storybook built-in.

Adding a React bundle to the library makes it more universal. The library can then be used in React projects and MDX environments.

Nested CSS, Container queries, CSS Layers, etc., the list of CSS improvement in the last six years is long. This improves the Developer Experience. CSS Layers for example, are clearly visible in the development tools of a modern browser. A major improvement over guessing the specificity of a selector in the old days.

Github

This site, the library reference implementation and the ui library itself are all in one repository for simplicity.


Other posts

Image without description
  • Jacco Meijer
  • |
  • May 1, 2025

CISSP certification and Enterprise Architecture

How do the CISSP certification domains relate to Enterprise Architecture and the ArchiMate layers?

Image without description
  • Jacco Meijer
  • |
  • Apr 23, 2025

Architect roles in the ArchiMate context

An ArchiMate model that maps architect roles to the ArchiMate framework layers.

Image without description
  • Jacco Meijer
  • |
  • Mar 18, 2025

Visualizing IT Architecture in three languages, UML, C4 and ArchiMate

What are the differences and what are these languages most used for?

Image without description
  • Jacco Meijer
  • |
  • Feb 18, 2025

OAuth 2.0 and OpenID Connect Sequence Diagrams

Technical specs can be hard to read. While still highly technical, the UML Sequence Diagrams provided in this blog are a lot easier to understand.

Image without description
  • Jacco Meijer
  • |
  • Jan 9, 2025

OWASP and CISSP

OWASP recommendations from the independent information security certification CISSP.

Image without description
  • Jacco Meijer
  • |
  • Mar 20, 2024

Render JSX plugin for Esbuild

Transform Esbuild generated JSX bundles to HTML pages.

Image without description
  • Jacco Meijer
  • |
  • Mar 19, 2024

Esbuild as a static site generator for MDX

Static site generators gain popularity. This blog is about using Esbuild as a static site generator for MDX.

Image without description
  • Jacco Meijer
  • |
  • Mar 18, 2024

11ty and Github pages

Simplifying the Contentful-Gatsby-Netlfy trio.

Image without description
  • Jacco Meijer
  • |
  • Jun 30, 2022

NPM7 and @npmcli/arborist

@npmcli/arborist is a powerful library that handles the new NPM 7 workspaces. This blog is about a simple make tool that uses the library.

Image without description
  • Jacco Meijer
  • |
  • May 12, 2022

Comparing React app, Nextjs and Gatsby

A new React project starts with a React toolchain. Main tools in the chains are SSR, React server components and GraphQL.

Image without description
  • Jacco Meijer
  • |
  • May 10, 2022

Versioning strategy for NPM modules

It is important to be able to bump the version of a NPM package without side effects.

Image without description
  • Jacco Meijer
  • |
  • Apr 12, 2022

React component themes and CSS variables

Creating React components with flexible themes by using CSS variables.

Image without description
  • Jacco Meijer
  • |
  • Mar 21, 2022

Content modeling with variants

The efficiency of a variant field in a content model.

Image without description
  • Jacco Meijer
  • |
  • Mar 12, 2022

Documentation

Documenting a software project is challenging. Here's a few simple guidelines that help a team writing clear documentation.

Image without description
  • Jacco Meijer
  • |
  • Mar 11, 2022

Javascript history

In 1986 David Ungar and Randall B. Smith developed Self at Xerox PARC. Inspired by Java, Scheme and Self Brendan Eich created Javascript in 1995.

Image without description
  • Jacco Meijer
  • |
  • Mar 10, 2022

On Javascript transpilers, bundlers and modules

There's Javascript transpilers, modules, bundles and bundlers. This is a brief overview of all of these.

Image without description
  • Jacco Meijer
  • |
  • Feb 11, 2022

Agile Scrum

The Agile Scrum framework is flexible enough to be used in many different ways. Here's one way of working.

Image without description
  • Jacco Meijer
  • |
  • Jan 20, 2022

What happened to Wheelroom?

Founded in 2018. Started to fly in 2020 and abandoned in 2021. What happened?

Image without description
  • Jacco Meijer
  • |
  • Jan 19, 2022

Contentful, Netlify and Gatsby four years later

What did we learn from using Contentful for four years?

Image without description
  • Jacco Meijer
  • |
  • Jan 18, 2022

Typescript interface for React UI components

How to define an interface for React UI components that prevents breaking changes.

Image without description
  • Jacco Meijer
  • |
  • Jan 17, 2022

Naming React components

What's in a name? A clear naming strategy helps developers communicate. Most devs rather spend time writing component code than wasting time on a good component name.