All articles

tutorials

How to add a highlighter underline to Shopify headlines (no code)

Three ways to highlight text in Shopify — a Pro tag, hand-rolled CSS with absolute ::after, and an inline span hack. Working code for every 2.0 theme.

The Pulsar team9 min read
A Shopify homepage headline with a single word highlighted by a hand-drawn yellow marker underline.

A marker-style highlight under one word in your H1 is the cheapest design upgrade in the Shopify catalogue. It directs the eye exactly where you want it, breaks up a wall of grey text, and signals that someone — anyone — thought about the page for more than four minutes. The catch is that most tutorials hand you a background-color: yellow rectangle that looks like a 1998 Word document. This guide walks through three ways to do it properly — animated, brand-coloured, and accessible — and tells you exactly where each one falls over.

TL;DR

  • Fastest: install Pulsar and wrap a word in $h{color: #facc15}word$. Animated SVG draw-on, scroll-triggered, reduced-motion-safe. ~30 seconds.
  • Free + manual: add a .marker class to your theme stylesheet with an absolutely positioned ::after pseudo-element and a scaleX transition. Works, but you'll fight Shopify's HTML sanitizer and every theme update.
  • One-off: paste a <mark> or <span style="background:..."> straight into a Rich Text section. Easiest for a single hero headline; hideous if you have more than one.

The three approaches, side by side

ApproachTime to shipAnimated draw-onRespects `prefers-reduced-motion`Survives theme updatesCost
Pulsar $h{...} tag~30 secondsYes, scroll-triggeredYes, built inYesPulsar Pro
Custom CSS ::after20–30 minutesYes, if you write the JSOnly if you add the media queryOften notFree
Inline <mark> / span~30 secondsNoN/A (no motion)Yes, until your theme sanitises itFree
Two Shopify headlines side by side: one with a flat yellow rectangle behind the word, one with a hand-drawn marker stroke underneath.
Same word, two highlight styles. The flat rectangle reads as a redacted document. The marker stroke reads as design.

Approach 1 — The no-code path (Pulsar $h{...})

Pulsar's highlight tag wraps a word in a <pulsar-highlight> custom element. The runtime injects an SVG marker stroke as an ::after-style overlay, sets its pathLength, and uses an IntersectionObserver to play the draw-on animation once the headline scrolls into view. You don't write any of that — you write $h{color: #facc15}word$.

  1. Install Pulsar from the Shopify App Store. The highlight tag lives on the Pro plan.
  2. Enable the Pulsar Inline app embed in your theme editor (one toggle under Theme settings → App embeds).
  3. Edit any headline that's matched by your configured selectors (default: h1, h2, p). Wrap a word: $h{color: #facc15; opacity: 0.7}standout$.
  4. Save and reload the storefront. The marker draws in as the headline enters the viewport.
Pulsar highlight syntax — you type
We make $h{color: #facc15; opacity: 0.8}beautiful$ candles
Shoppers see
We make beautiful candles

Every attribute the underlying web component accepts is exposed in the tag. The most common ones:

  • color — any CSS colour. Hex, named, rgb(...), or a CSS variable from your theme.
  • opacity0 to 1. The default (0.4) looks like a faded marker; bump it to 0.8 for a more confident stroke.
  • data-stroke-width — defaults to 20. Lower numbers (812) read as a fine-liner; higher numbers (25+) as a chisel marker.
  • is-animatedtrue or false. Turn the draw-on off for above-the-fold static use.
  • duration — animation length in seconds. Default 3.2. Anything under 1.0 looks twitchy.
  • effect-id — picks which highlight curve to render (1 by default; more shipped over time).
Screenshot of the Pulsar admin showing the highlight effect builder with a color picker and opacity slider.
Pulsar's Effect Library — pick a colour and opacity, copy the tag, paste it into any headline.

Approach 2 — Custom CSS with an absolute ::after

If you don't want to install an app, you can fake the effect with a pseudo-element that sits behind the text. The trick is to position it absolutely, give it the visual character of a marker stroke (rounded ends, slightly off-axis), and animate transform: scaleX(...) from 0 to 1 so it appears to draw left-to-right. A static background-color won't get you there — it'll look like a hyperlink from 2003.

Step 1 — Add the highlight utility class

assets/base.css
.marker {
  position: relative;
  display: inline-block;
  /* Make sure the pseudo-element doesn't push siblings around */
  isolation: isolate;
}

.marker::after {
  content: "";
  position: absolute;
  left: -0.05em;
  right: -0.05em;
  bottom: 0.05em;
  /* The marker stroke itself */
  height: 0.45em;
  background: #facc15;
  opacity: 0.7;
  border-radius: 0.25em 0.6em 0.2em 0.5em; /* uneven = hand-drawn */
  z-index: -1;
  /* Draw-on animation */
  transform-origin: left center;
  transform: scaleX(0);
  transition: transform 0.9s cubic-bezier(0.65, 0, 0.35, 1);
}

.marker.is-visible::after {
  transform: scaleX(1);
}

@media (prefers-reduced-motion: reduce) {
  .marker::after {
    transition: none;
    transform: scaleX(1);
  }
}

Step 2 — Wire up the scroll trigger

CSS alone can't tell when a headline enters the viewport. You need a small IntersectionObserver snippet that toggles the is-visible class. Drop this in assets/theme.js (Dawn) or your equivalent global script:

assets/theme.js
(() => {
  const els = document.querySelectorAll(".marker");
  if (!els.length) return;

  // Respect the OS-level setting. No observer, no animation — just paint it.
  const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
  if (reduce) {
    els.forEach((el) => el.classList.add("is-visible"));
    return;
  }

  const io = new IntersectionObserver(
    (entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          entry.target.classList.add("is-visible");
          io.unobserve(entry.target);
        }
      });
    },
    { threshold: 0.4, rootMargin: "0px 0px -10% 0px" }
  );

  els.forEach((el) => io.observe(el));
})();

Step 3 — Wrap the word in the section template

Find the section template that renders the headline you want to mark. For a homepage banner in Dawn that's sections/image-banner.liquid; for a product title it's sections/main-product.liquid. You can't wrap from the theme editor — the Rich Text field strips custom classes — so the wrapping has to live in Liquid:

<h1>We make <span class="marker">beautiful</span> candles</h1>

Approach 3 — Inline <mark> or span hack in Rich Text

For a one-off — a single hero headline you'll never iterate on — you can paste raw HTML into a Rich Text section's <> source view. The native HTML element for this is <mark>, which has the bonus of semantic meaning (it announces "highlighted" to screen readers). Most themes style it as a yellow box by default, which you can override inline:

<h2>We make <mark style="background:#facc15;padding:0.1em 0.2em;border-radius:0.2em">beautiful</mark> candles</h2>

Or, if you want the marker-stroke look without the JS, a span with a linear-gradient background tracked to the bottom of the line:

<h2>We make <span style="background:linear-gradient(180deg,transparent 65%,#facc15 65%);padding:0 0.1em">beautiful</span> candles</h2>

Picking a highlight colour that doesn't look like a 2017 SaaS deck

The default for marker highlights is school-bus yellow, and there's a reason — it has the highest contrast against white without darkening the text underneath. But it also reads as "generic landing page" if every brand on the internet uses it. A few rules that age better:

  • Borrow from your brand palette, then desaturate. If your buttons are emerald #10b981, your highlight should be a faded emerald (#10b981 at opacity: 0.35) — not pure yellow. Visual consistency outperforms novelty every time.
  • Neon is for premium brands, not budget. Hot pink, electric green, and acid yellow read as expensive only if the rest of the page is restrained. On a busy storefront they read as a sale banner.
  • Cool tones for premium, warm for energy. Highlighting in a soft lavender or pale blue signals editorial/luxury. Highlighting in orange or yellow signals urgency.
  • Always test at `opacity: 0.6–0.8`. Solid 1.0 highlights compete with the text. A slight transparency lets the typography breathe.
  • Avoid red unless you mean it. A red marker stroke under a word reads as an error or a strike-through, not a highlight. Use amber instead.
Six Shopify headlines stacked vertically, each with the same word highlighted in a different color: yellow, amber, soft pink, lavender, mint, and neon green.
Six different highlights, same word. Lavender (third from top) and amber (second) consistently outperform default yellow in heatmap tests.

Accessibility — what to actually do

A highlight is one of the few text effects that can improve accessibility instead of harming it, but only if you respect a few rules:

  • Use `<mark>` semantically where you can. Screen readers announce it as "highlighted [word]" — useful context. The Pulsar $h{...} tag does not currently emit <mark>, so if you want the announcement, wrap the entire pulsar tag in <mark>: <mark>$h{color: #facc15}word$</mark>.
  • Test contrast with the highlight removed. Your text must pass WCAG AA contrast against the page background without the highlight present — never against the highlight itself. The highlight is decorative.
  • Honour `prefers-reduced-motion`. Pulsar does this automatically; the CSS approach above includes the media query. Some users get motion-sick from draw-on animations.
  • Don't rely on highlight as the only signal. If a highlight is conveying critical information ("this is on sale"), pair it with text — "Sale: …". Colour-blind users may not see the highlight at all.

Common bugs and how to fix them

+The highlight covers the text instead of sitting behind it
Your pseudo-element has a positive z-index. Set it to -1 and add isolation: isolate to the parent. If you're using Pulsar and seeing this, your theme has a global position: static rule that's breaking the shadow-DOM positioning — file a bug with your shop URL and we'll patch it.
+The draw-on animation plays once and then disappears on a soft reload
The IntersectionObserver fires on the first viewport intersection only, by design. If you're loading the page already scrolled past the headline, the observer never triggers. Lower the threshold to 0.01 or remove the unobserve line so it can re-fire.
+The marker is visible in the admin preview but missing on the live store
If you're on Pulsar, this is almost always the beacon stripping Pro elements because the shop isn't on Pro. The fix is to upgrade — the underlying text remains, only the SVG overlay is removed. If you're hand-rolling the CSS, check that your theme.js bundle is actually being shipped to production (a common build pipeline error).
+My highlight extends past the end of the word on long lines
You're hitting line-break wrap behaviour. Add box-decoration-break: clone; -webkit-box-decoration-break: clone; to the highlighted span. Each visual line then gets its own marker fragment instead of one stretched across all of them.
+Will Google penalise me for animated text effects?
No. Googlebot reads the underlying HTML, which is plain text — <h1>We make beautiful candles</h1> — regardless of whether beautiful has a marker overlay. The Core Web Vitals impact of a single <pulsar-highlight> is negligible (one SVG, ~200 bytes, no layout shift if you let the runtime size the parent first).

Which approach should you pick?

If you want an animated marker highlight that survives every theme update and never makes you touch CSS — install Pulsar and use $h{...}. If you're a developer shipping a custom theme for a client and the highlight needs to be free forever — Approach 2, knowing you've signed up to maintain the CSS and the IntersectionObserver yourself. If you only need to highlight one word on one page and never again — Approach 3, knowing your theme's sanitiser might delete it on save.

For more on what the rest of the Pulsar syntax can do — gradients, circles, animated draws — see the gradient text guide and the animated circle effect walk-through. The full tag reference lives in the Pulsar syntax cheatsheet.

About the author

The Pulsar team

Shopify text styling

Pulsar is the easiest way to stylize headlines in your Shopify store — colors, gradients, animated highlights and circles, no theme code required.

Install Pulsar — Free