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

@vitrina/email-builder

v0.1.4

Published

Unlayer-style drag-and-drop email builder for React. Rows/columns/blocks (text, heading, button, image, divider, spacer, social, menu, HTML), inline rich-text, undo/redo, desktop/mobile preview. Emits email-safe, dark-mode-proof table HTML. Framework-agno

Readme

@vitrina/email-builder

npm license

An Unlayer-style drag-and-drop email builder for React. Rows → weighted Columns → Blocks (text, heading, button, image, divider, spacer, social, menu, HTML). Inline rich-text, undo/redo, desktop/mobile preview. It edits a plain EmailDesign JSON object and compiles it to email-safe table HTML — inline styles, forced-light rendering, fluid columns that stack on phones, and Outlook fallbacks.

  • Framework-agnostic — one <EmailBuilder value onChange /> component.
  • Tailwind + shadcn friendly — styled entirely with utility classes + your CSS-var theme tokens. No stylesheet to import.
  • i18n-free — every visible string is injected via a labels prop.
  • Merge-tag aware{{name}}-style tags pass through untouched, for your own per-recipient rendering.
  • Tiny — no editor engine bundled; only highlight.js + lucide-react as deps, React as a peer.

Built by Vitrina for its campaigns product and extracted as a standalone package.

Install

npm i @vitrina/email-builder
# or: pnpm add @vitrina/email-builder / yarn add @vitrina/email-builder

Peer deps: React ≥ 19 and react-dom.

Quick start

import { useState } from 'react';
import { EmailBuilder, compileDesign, defaultDesign, type EmailDesign } from '@vitrina/email-builder';

export function MyEditor() {
  const [design, setDesign] = useState<EmailDesign>(() => defaultDesign());

  return (
    <div style={{ height: 640 }}>
      <EmailBuilder
        value={design}
        onChange={setDesign}
        uploadImage={async (file) => uploadAndReturnPublicUrl(file)}   // optional
        socialIconBase="https://cdn.example.com/social-icons"          // optional
      />
    </div>
  );
}

// When you save/send — compileDesign returns the <body> inner HTML. Wrap it in
// your own shell (doctype/head + compliance footer) and render merge tags
// server-side per recipient.
const bodyHtml = compileDesign(design, { socialIconBase: 'https://cdn.example.com/social-icons' });

Styling requirements

The builder renders Tailwind utility classes and reads shadcn/ui-style CSS variables (--primary, --muted-foreground, --border, --popover, --ring, --destructive, …). Any shadcn base provides them.

Because the classes live inside the compiled package, tell Tailwind to scan it.

Tailwind v4 (globals.css):

@import "tailwindcss";
@source "../node_modules/@vitrina/email-builder/dist";

Tailwind v3 (tailwind.config):

content: ['./src/**/*.{ts,tsx}', './node_modules/@vitrina/email-builder/dist/**/*.js'],

The HTML block's code editor picks up syntax colors from any highlight.js theme you happen to load — optional; it degrades to monochrome without one.

API

| Export | What | | --- | --- | | EmailBuilder | The editor. Props below. | | compileDesign(design, opts?) | EmailDesign → email-safe body HTML string. opts.socialIconBase for hosted social icons. | | defaultDesign() | A pleasant starter design. | | blockCount(design) | Total blocks (e.g. to gate "next"). | | MOBILE_STACK_CSS | Optional <style> for your <head> (extra mobile polish). | | DEFAULT_LABELS, BuilderLabels | The English label bag + its type. | | types | EmailDesign, EmailSettings, Block, BlockType, Row |

<EmailBuilder> props

| Prop | Type | | | --- | --- | --- | | value | EmailDesign | required — the design (controlled) | | onChange | (d: EmailDesign) => void | required | | labels? | Partial<BuilderLabels> | override any string (defaults are English) | | uploadImage? | (file: File) => Promise<string> | host-provided uploader; without it images are URL-only | | socialIconBase? | string | absolute base for hosted icons — <base>/<slug>.png; omit for a colored-chip fallback | | height? | number \| string | editor height (default 640) |

The compile contract

compileDesign emits the <body> inner HTML only. You own the outer shell — doctype/<head>, and any compliance footer (unsubscribe, physical address) your emails need. Merge tags like {{name}} are left verbatim so you can render them per recipient at send time.

Rules the output follows so it renders across clients:

  • Table-based layout, 100% inline styles (no <style>/media-queries in the body).
  • Forced light friendliness — pair with <meta name="color-scheme" content="light only"> in your head to avoid dark-mode inversion breaking your colors.
  • Fluid columns — multi-column rows use the inline-block "hybrid" pattern, so they stack on phones with no media query (Gmail included), with an [if mso] ghost table keeping Outlook side-by-side.
  • Images carry a width attribute (Outlook sizes off it) + max-width:100%.

Email-client notes

| | Gmail | Apple Mail | Outlook (desktop) | | --- | --- | --- | --- | | Core layout, buttons, images | ✅ | ✅ | ✅ | | Column stacking on mobile | ✅ | ✅ | n/a | | border-radius (rounded buttons/icons) | ✅ | ✅ | ⬜ renders square | | Row background images | ✅ | ✅ | ⬜ needs VML |

Social icons need publicly-hosted PNGs at socialIconBase (Gmail/Outlook strip SVG). Slugs: instagram facebook whatsapp x twitter linkedin youtube tiktok pinterest snapchat telegram messenger reddit spotify threads github vimeo tumblr discord email website.

Development

pnpm install
pnpm test          # vitest — compiler + model unit tests
pnpm typecheck
pnpm lint
pnpm build         # tsup → dist (ESM + d.ts)

# runnable playground (see examples/basic):
cd examples/basic && pnpm install && pnpm dev

See CONTRIBUTING.md for the full workflow and CHANGELOG.md for release history.

License

MIT © Vitrina