Skip to content
Go to file


Failed to load latest commit information.
Latest commit message
Commit time


Version Badge Build Status License

Pseudo-element templating

A proof of concept, pet (pseudo-element templating) expands on the capabilities of pseudo-elements by adding support for HTML and data attribute interpolation within the CSS content property.


Download the CJS, ESM, UMD versions or install via NPM:

npm install @ryanmorr/pet


The beauty of pet is that it's a zero API library, meaning there are no functions to import, just the library itself:

import from '@ryanmorr/pet';

Signify an element as a pet element by adding the "pet" attribute. Then define its template within the content property of the ::before pseudo-element:

<div class="component" pet></div>
.component::before {
    content: '<span>Hello World</span>';


<div class="component" pet>
    <span>Hello World</span>

If you experience FOUC, try adding the following to your CSS to ensure the pseudo-element templates are not displayed as plain text:

[pet]::before {
    display: none !important;


Interpolation is achieved through data attributes set on the pet element and mustache-style double curly braces serving as delimiters for tokens within the template. The token found between the delimiters reference the data attribute using the same name conversion as the element.dataset property in JavaScript. For example, an attribute of data-foo-bar-baz-qux would be referenced as {{fooBarBazQux}} within a template.

<div class="component" data-first-name="John" data-last-name="Doe" pet></div>
.component::before {
    content: '<span>Hello world, my name is {{firstName}} {{lastName}}</span>';


<div class="component" data-first-name="John" data-last-name="Doe" pet></div>
    <span>Hello world, my name is John Doe</span>

Programmatically changing a data attribute will automatically patch the changes in the DOM in a performant manner.

When a template is initially rendered, and every time a template is patched, a custom "render" event is dispatched on the pet element:

document.querySelector('.component').addEventListener('render', (e) => {
    // React to changes

Harness the Power of CSS

Create micro templates easily for common patterns:

.phone::before {
    content: '<span><i class="icon-phone"></i> {{number}}</span>';

.email::before {
    content: '<a href="mailto:{{email}}"><i class="icon-email"></i> {{email}}</a>';

Alter a template based on class names and attributes:

.avatar::before {
    content: '<img src="default.jpg" />';

.avatar[data-src]::before {
    content: '<img src="{{src}}" />';


This project is dedicated to the public domain as described by the Unlicense.

You can’t perform that action at this time.