An Idiosyncratic Blog

🎨 Using global class selectors in CSS Modules

Published on
β€’ 3 minutes read

This site is build using React, and uses CSS Modules. If you were to inspect element on this site, you'd find CSS class names similar to PostContent-module--markdown-body--adE4E. This is generated using CSS Modules. It allows me to import CSS using JS syntax. It als has a configuration to add arbitrary class names during build to avoid style collisions between components in a page.

CSS Modules are simply CSS files with a *.module.css extension.

.markdown-body a {
  color: var(--color-link);
  text-decoration: none;
}
.markdown-body a:hover {
  text-decoration: underline;
}
.markdown-body a.footnote-ref {
  background-color: lighten(#61afef, 25%);
  border-radius: 3px;
}

And to use it in a Component, we import it like any other JS module.

import React from 'react'
import { markdownBody } from './PostContent.module.scss'
import './Prism.css'
const PostContent = ({ post }) => {
  return (
    <article className={markdownBody}>
      <section dangerouslySetInnerHTML={{ __html: post }} itemProp="articleBody" />
    </article>
  )
}

export default PostContent

Now the issue was, the Markdown classes were handled by gatsby-transformer-remark, a plugin used to convert markdown to html. I had to target a specific class, .footnote-ref to add a background to it. Initial code was, .markdown-body a.footnote-ref. But when inspecting the footnote element, because the CSS was declared in a module file, the class name ended up as .PostContent-module--markdown-body--adE4E a.PostContent-module--footnote-ref--1To04. This CSS was not styling the element, because the element had a class of .footnote-ref.

Took me a while, but I found the solution in CSS Loader README.

:local(.className) {
  background: red;
}
:local .className {
  color: green;
}
:local(.className .subClass) {
  color: green;
}
:local .className .subClass :global(.global-class-name) {
  color: blue;
}

By using :global() selector, we can keep the CSS class as it is, hence the name global selector.

._23_aKvs-b8bW2Vg3fwHozO {
  background: red;
}
._23_aKvs-b8bW2Vg3fwHozO {
  color: green;
}
._23_aKvs-b8bW2Vg3fwHozO ._13LGdX8RMStbBE9w-t0gZ1 {
  color: green;
}
._23_aKvs-b8bW2Vg3fwHozO ._13LGdX8RMStbBE9w-t0gZ1 .global-class-name {
  color: blue;
}

This is exactly what I wanted. So now to change my css,

.markdown-body a {
  color: var(--color-link);
  text-decoration: none;
}
.markdown-body a:hover {
  text-decoration: underline;
}
.markdown-body a:global(.footnote-ref) {
  background-color: lighten(#61afef, 25%);
  border-radius: 3px;
}

And et voilΓ , the CSS is .PostContent-module--markdown-body--adE4E a.footnote-ref. You can check out the Footnote Element style here.

So TIL, about :global() and :local() selectors in CSS Modules.

Until next time! ✌🏽