Skip to content

posthtml/posthtml-safe-class-names

Repository files navigation

Safe Class Names

Replace escaped characters in class names and CSS selectors

Version Build License Downloads

Introduction

This plugin replaces escaped characters in class names from your <style> tags and inside class="" attributes with safe characters, that do not need escaping.

By default, it replaces:

  • \: and \/ with -
  • \% with pc
  • \. with _

See the full list of replacements.

But... why?

So you can use those cool Tailwind CSS selectors in HTML emails. 😎

Escaped characters in CSS selectors are not currently supported by all email clients, so you can use this plugin to replace them with HTML email-safe alternatives.

Install

npm i posthtml posthtml-safe-class-names

Usage

Consider example.html:

<!DOCTYPE html>
<html>
<head>
  <style>
    .w-3\/5 {
      width: 60%;
    }
    
    .bg-\[\#1da1f1\] {
      background-color: #1da1f1;
    }

    @media (max-width: 600px) {
      .sm\:w-1\/2 {
        width: 50%;
      }
    }
  </style>
</head>
<body>
  <div class="w-3/5 sm:w-1/2 bg-[#1da1f1]">Lorem ipsum</div>
</body>
</html>
import posthtml from 'posthtml'
import {readFileSync, writeFileSync} from 'node:fs'
import safeClassNames from 'posthtml-safe-class-names'

const source = readFileSync('./example.html')

posthtml([
    safeClassNames()
  ])
  .process(source)
  .then(result => fs.writeFileSync('./after.html', result.html))

Result:

<!DOCTYPE html>
<html>
<head>
  <style>
    .sm-w-3-5 {
      width: 60%;
    }

    .bg-_1da1f1 {
      background-color: #1da1f1;
    }

    @media (max-width: 600px) {
      .sm-w-1-2 {
        width: 50%;
      }
    }
  </style>
</head>
<body>
  <div class="w-3-5 sm-w-1-2 bg-_1da1f1">Lorem ipsum</div>
</body>
</html>

Options

replacements

Type: Object
Default: see list

The plugin accepts an options object where you can define character replacement mappings:

{
  ':': '-',
  '\/': '-',
  '%': 'pc',
  '.': '_',
  // ...
}

See the full list of replacements.

Besides adding new mappings, you can of course override the default ones.

Using the same example.html, let's replace \: in our class names with __ instead of -:

posthtml([
    safeClassNames({
      replacements: {
        ':': '__',
      }
    })
  ])
  .process(source)
  .then(result => writeFileSync('./after.html', result.html))

Result:

<!DOCTYPE html>
<html>
<head>
  <style>
    .sm__w-3-5 {
      width: 60%;
    }

    .bg-_1da1f1 {
      background-color: #1da1f1;
    }

    @media (max-width: 600px) {
      .sm__w-1-2 {
        width: 50%;
      }
    }
  </style>
</head>
<body>
  <div class="w-3-5 sm__w-1-2 bg-_1da1f1">Lorem ipsum</div>
</body>
</html>

ignored

Type: Array
Default: [{heads: '{{', tails: '}}'}, {heads: '{{{', tails: '}}}'}]

An array of objects each containing heads/tails strings that mark the start and end of a class name to ignore. If a class name matches a pattern defined here, it will not be processed.

posthtml([
    safeClassNames({
      ignored: [
        {heads: '[[', tails: ']]'},
      ]
    })
  ])
  .process('<div class="foo:bar [[ biz ]]">')
  .then(result => console.log(result.html))

  // <div class="foo-bar [[ biz ]]">