npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tollerud/email

v5.6.0

Published

Tollerud branded email primitives + templates — React Email, tokens synced from @tollerud/ui

Downloads

1,727

Readme

@tollerud/email

On-brand, client-tested HTML email for the Tollerud design system, built on React Email.

Email is a different render target from the browser — table-based layout, inline-only styles, no CSS custom properties, and aggressive client quirks (Outlook's Word engine, Gmail, corporate webmail). So this package shares Tollerud's design tokens, not the @tollerud/ui web components. Token values are inlined as literals (via the generated lib/tokens.ts in the monorepo root), because var(--tollerud-*) does not resolve in mail clients.

Do not render @tollerud/ui React components into email. They rely on flexbox/grid, external stylesheets, and CSS variables that break in many inboxes. Use the primitives here instead.

Install

npm install @tollerud/email

Peer deps: react / react-dom (>=18).

Usage

Compose a template as a React element and render it to an HTML string, then hand that string to your mailer (Resend, AWS SES, Nodemailer, Postmark, …).

import { render, WelcomeEmail } from '@tollerud/email'

const html = await render(
  <WelcomeEmail
    name="Mathias"
    productName="Graphify"
    ctaUrl="https://app.example.com/dashboard"
    header={{ productName: 'Graphify' }}
    footer={{ labels: { tollerudProject: 'A Tollerud Project' }, address: 'Oslo, Norway', unsubscribeUrl }}
  />,
)

await mailer.send({ to, subject: 'Welcome to Graphify', html })

Or build your own from primitives:

import { render, EmailLayout, EmailHeader, EmailHeading, EmailText, EmailButton, EmailFooter } from '@tollerud/email'

const html = await render(
  <EmailLayout preview="Your report is ready">
    <EmailHeader productName="Graphify" />
    <EmailHeading>Weekly report</EmailHeading>
    <EmailText>Your report for last week is ready to view.</EmailText>
    <EmailButton href={reportUrl}>View report</EmailButton>
    <EmailFooter unsubscribeUrl={reportUrl} />
  </EmailLayout>,
)

Exports

Renderingrender, pretty, toPlainText (re-exported from @react-email/render; render is async-capable).

Primitives

| Component | Key props | |-----------|-----------| | EmailLayout | preview?, lang? — the <Html>/<Head>/<Body> shell (light default + dark-mode <style>) | | EmailHeader | productName, monogram?, logoSrc?, align?: 'left' \| 'center', divider? — branded top (monogram + project name large) | | BrandMark | height?, src? — the monogram (hosted PNG; auto dark-on-light / yellow-in-dark, or your own via src) | | EmailButton | href, variant?: 'primary' \| 'secondary' | | EmailHeading | as?: 'h1' \| 'h2' \| 'h3' | | EmailText | tone?: 'default' \| 'muted' \| 'fine' | | EmailDivider | variant?: 'default' \| 'accent' | | EmailFooter | labels? (tollerudProject/attribution/allRightsReserved), monogram?, logoSrc?, address?, unsubscribeUrl?, links? — the Tollerud footer, → tollerud.no |

TemplatesWelcomeEmail, VerifyEmail, PasswordResetEmail, ReceiptEmail. Each accepts an optional header?: EmailHeaderProps to render the branded header at the top, and an overridable copy prop (see below).

Configurability

  • Content + branding are fully prop-driven (name, productName, URLs, header, footer, labels, …).

  • Copy / i18n — every template takes a copy prop. Each exports a *Copy interface whose dynamic lines are functions (so interpolated values still flow through) and static lines are strings. Pass any subset to reword or localize; defaults are unchanged.

    <WelcomeEmail
      name="Mathias" productName="Graphify" ctaUrl={url} ctaLabel="Åpne dashbordet"
      copy={{
        heading: (n) => `Velkommen${n ? ', ' + n : ''}.`,
        body: (p) => `Din ${p}-konto er klar. Ta en titt rundt.`,
        help: 'Trenger du hjelp? Bare svar på denne e-posten.',
      }}
    />
  • Style escape hatch — every primitive takes an optional style merged last, overriding the token defaults for one-off tweaks: <EmailButton href={url} style={{ borderRadius: '999px' }}>Pill</EmailButton>.

  • Visual design otherwise stays token-locked to the Tollerud brand by default — colors, fonts, spacing, and sizes come from the shared tokens, so emails stay on-brand unless you deliberately override via style.

Monogram in email

EmailHeader and EmailFooter show the Tollerud monogram via BrandMark, as a hosted PNG — inline SVG is stripped by Gmail and Outlook. By default it uses the dark monogram on light backgrounds and swaps to the yellow monogram in dark mode (design.tollerud.dev/brand/email-monogram-{dark,yellow}.png; regenerate with node scripts/gen-email-monogram.mjs). Pass logoSrc to use your own hosted image (a single image, no dark-mode swap). The large project name in the header always renders too, so the brand reads regardless.

Tokenstokens (raw values, synced from @tollerud/ui) and emailTheme (email semantic mapping).

Theme & dark mode

The email is light by default — a light background is the only thing that renders predictably in every client, including Gmail. (Gmail ignores color-scheme, applies its own color transforms to dark emails, and strips inline SVG, so a dark-first email breaks there.)

  • Inline styles are light (white card, dark text, yellow button); surfaces also carry bgcolor attributes.
  • A @media (prefers-color-scheme: dark) <style> block restores the noir palette on clients that honor it — Apple Mail, iOS Mail. Gmail ignores it and keeps the safe light rendering.
  • The yellow button stays #FFFF00 with black text in both modes.
  • EmailFooter's "A Tollerud Project" link shares the footer's muted class, so the whole wordmark ("A Tollerud Project. … All rights reserved.") recolors together under the dark-mode block. The fine-print line below it is centered.
  • Any custom text you render outside the primitives (e.g. a bespoke table) must carry the matching t-* class — emailClass.text / .muted / .fine — or its inline light color won't be recolored by the dark-mode block and it will render dark-on-dark. ReceiptEmail's line-item table is wired this way.
  • Still test in Litmus or Email on Acid before a large send.

Compliance

For bulk mail, pass address and unsubscribeUrl to EmailFooter (or the template footer prop) to stay CAN-SPAM compliant.

Maintenance (monorepo)

Tokens and version are synced from the root package — do not hand-edit src/tokens.ts or the version in package.json:

npm run gen:tokens   # regenerate lib/tokens.ts from tokens.css
npm run sync:email   # copy tokens + lock version into packages/email

npm run validate runs verify:email-sync to enforce lockstep.