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

@usemonocle/visual-email-editor

v0.0.1

Published

A headless, customizable email template builder built with React, TypeScript, and modern web technologies

Readme

Visual Email Editor - Tabular Clone

A headless, customizable email template builder built with React, TypeScript, and modern web technologies. Inspired by Tabular.email, this editor allows you to import HTML strings, visually edit them, and export email-safe HTML.

🎯 Goals

  • HTML Import: Import HTML strings from API or user paste
  • Visual Editing: Drag-and-drop interface with full control
  • HTML Export: Export email-safe HTML that works across 50+ email clients
  • Headless Architecture: Build your own components, full control
  • Responsive Preview: Desktop and mobile preview modes
  • Component Library: Reusable email blocks

🏗️ Architecture

Core Libraries

State Management:

  • Zustand - Lightweight, unopinionated state management
  • Simple store for editor state (nodes, selection, history)

Drag & Drop:

  • @dnd-kit/core - Modern, accessible drag-and-drop
  • @dnd-kit/sortable - Sortable list functionality
  • @dnd-kit/utilities - Helper utilities

Rich Text Editing:

  • @tiptap/react - Headless rich text editor
  • @tiptap/starter-kit - Essential extensions
  • @tiptap/extension-text-align - Text alignment
  • @tiptap/extension-color - Text color
  • @tiptap/extension-text-style - Text styling

HTML Parsing:

  • node-html-parser - Fast, browser-compatible HTML parser
  • Parse HTML strings into component tree
  • Extract styles, attributes, and structure

HTML Export:

  • ReactDOMServer - Render React components to HTML
  • juice or inline-css - Inline CSS for email compatibility

UI Components:

  • shadcn/ui - Re-usable components built on Radix UI and Tailwind CSS
    • Copy components directly into your project
    • Fully customizable
    • Built on Radix UI primitives
    • Components: Popover, Select, Slider, Separator, Label, Toggle Group, Button, Input, Card, etc.
  • Tailwind CSS - Utility-first CSS framework
  • Lucide React - Icon library

⚠️ Development Guidelines

Use shadcn/ui Components

Do NOT create custom UI components. Always use shadcn/ui components when possible.

  • ✅ Use Popover for floating toolbars and menus
  • ✅ Use Dialog for modals
  • ✅ Use ToggleGroup for button groups
  • ✅ Use Select for dropdowns
  • ✅ Use Button, Input, Label for form controls
  • ✅ Keep each React component in a dedicated file (avoid multiple inline component definitions in a single file)
  • ❌ Do NOT create custom floating divs with manual positioning
  • ❌ Do NOT create custom modal implementations
  • ❌ Do NOT reinvent existing Radix UI primitives

shadcn/ui components provide:

  • Built-in accessibility (ARIA attributes, focus management)
  • Collision detection (won't go off-screen)
  • Consistent styling with the design system
  • Less custom code to maintain

To add a new shadcn component:

npx shadcn@latest add [component-name]

Utilities:

  • clsx - Conditional className utility
  • tailwind-merge - Merge Tailwind classes
  • class-variance-authority - Component variants

📦 Required Dependencies

Core Dependencies

{
  "dependencies": {
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "zustand": "^4.5.0",
    "@dnd-kit/core": "^6.1.0",
    "@dnd-kit/sortable": "^8.0.0",
    "@dnd-kit/utilities": "^3.2.2",
    "@tiptap/react": "^3.13.0",
    "@tiptap/starter-kit": "^3.13.0",
    "@tiptap/extension-text-align": "^3.13.0",
    "@tiptap/extension-color": "^3.13.0",
    "@tiptap/extension-text-style": "^3.13.0",
    "node-html-parser": "^6.1.0",
    "juice": "^10.0.0",
    "@radix-ui/react-popover": "^1.1.15",
    "@radix-ui/react-select": "^2.2.6",
    "@radix-ui/react-slider": "^1.3.6",
    "@radix-ui/react-separator": "^1.1.8",
    "@radix-ui/react-label": "^2.1.8",
    "@radix-ui/react-toggle-group": "^1.1.11",
    "@radix-ui/react-slot": "^1.2.4",
    "@radix-ui/react-dialog": "^1.1.15",
    "@radix-ui/react-tabs": "^1.1.1",
    "@radix-ui/react-dropdown-menu": "^2.1.15",
    "tailwindcss": "^4.1.17",
    "lucide-react": "^0.556.0",
    "clsx": "^2.1.1",
    "tailwind-merge": "^3.4.0",
    "class-variance-authority": "^0.7.1"
  }
}

🏛️ Architecture Overview

┌─────────────────────────────────────────┐
│           Email Editor Store             │
│         (Zustand)                        │
│  - Nodes tree                            │
│  - Selection state                       │
│  - History (undo/redo)                  │
│  - Viewport mode (desktop/mobile)       │
└─────────────────────────────────────────┘
                    │
        ┌───────────┴───────────┐
        │                       │
┌───────▼────────┐    ┌─────────▼────────┐
│  Canvas Area   │    │  Settings Panel   │
│  (DnD Kit)    │    │  (shadcn/ui)      │
│                │    │                   │
│  - Drag zones  │    │  - Property edits │
│  - Drop zones  │    │  - Style controls│
│  - Selection   │    │  - Layout options│
└────────────────┘    └──────────────────┘
        │
┌───────▼─────────────────────────────────┐
│         Component Library                │
│  - Container (horizontal/vertical)      │
│  - Text (TipTap)                        │
│  - Image                                │
│  - Button                               │
│  - Divider                              │
│  - Spacer                               │
└──────────────────────────────────────────┘

🚀 Implementation Plan

Phase 1: Core Infrastructure

  1. State Management (Zustand)

    • Editor store with nodes tree
    • Selection state
    • History stack (undo/redo)
    • Viewport mode state
  2. Drag & Drop Setup (@dnd-kit)

    • DndContext provider
    • Sortable containers
    • Drag handles
    • Drop zones
  3. Component System

    • Base component interface
    • Component registry
    • Props system
  4. Reliability and Performance

    • Autosave (local/session) and recover flow
    • Undo/redo stack limits and batching
    • Large-template rendering strategy (virtualization or chunked renders)
    • Throttled CSS inlining/export for big documents

Phase 2: Core Components

  1. Container Components

    • Horizontal frame
    • Vertical frame
    • Canvas container
    • Table-based rows and columns with per-cell padding/margins
    • Column stacking rules for mobile
  2. Content Components

    • Text block (TipTap integration)
    • Image block
    • Button block
    • Divider block
    • Spacer block
    • VML-safe button variant for Outlook
  3. Component Features

    • Selection highlighting
    • Drag handles
    • Resize handles (optional)
    • Context menu
    • Hover duplicate/delete controls
    • Quick alignment and spacing controls

Phase 3: Editor UI

  1. Toolbar

    • Component palette
    • Undo/redo
    • Preview toggle
    • Export button
    • Copy HTML
    • Copy shareable link
    • Send test email
  2. Settings Panel (shadcn/ui components)

    • Property editor (Input, Select)
    • Style controls (Slider, Color Picker)
    • Layout options (Toggle Group)
    • Visibility toggle (Switch)
    • Dynamic content support
  3. Viewport

    • Desktop preview
    • Mobile preview
    • Responsive toggle
    • Grid guides and table outlines

Phase 4: HTML Import/Export

  1. HTML Parser (node-html-parser)

    • Parse HTML string
    • Extract component structure
    • Map HTML elements to components
    • Extract styles and attributes
  2. Component Mapper

    • HTML → Component registry
    • Style extraction
    • Attribute mapping
    • Nested structure handling
  3. HTML Exporter

    • Component tree → HTML
    • ReactDOMServer rendering
    • CSS inlining (juice)
    • Email-safe HTML generation
    • Email safety validation (disallow unsafe CSS/attrs, require alt text)
    • Table structure validation
    • Copy HTML action
    • Send test email hook

Phase 5: Advanced Features

  1. Templates

    • Save templates
    • Load templates
    • Template library
    • Starter gallery and random template loader
  2. Responsive Design

    • Mobile-specific styles
    • Breakpoint handling
    • Preview modes
  3. Email Client Compatibility

    • Outlook compatibility
    • Gmail compatibility
    • Inline CSS
    • Table-based layouts
    • VML fallbacks for buttons and backgrounds

📁 Project Structure

src/
├── store/
│   ├── editorStore.ts          # Zustand store
│   ├── types.ts                # TypeScript types
│   └── utils.ts                # Store utilities
├── components/
│   ├── editor/
│   │   ├── Canvas.tsx          # Main canvas area
│   │   ├── Toolbar.tsx         # Top toolbar
│   │   ├── SettingsPanel.tsx   # Right sidebar
│   │   ├── ComponentPalette.tsx # Component library
│   │   └── Viewport.tsx        # Preview area
│   ├── blocks/
│   │   ├── Container.tsx       # Container component
│   │   ├── Text.tsx            # Text block (TipTap)
│   │   ├── Image.tsx           # Image block
│   │   ├── Button.tsx          # Button block
│   │   └── index.ts            # Component registry
│   └── ui/                     # shadcn/ui components
│       ├── button.tsx
│       ├── input.tsx
│       ├── select.tsx
│       ├── slider.tsx
│       ├── popover.tsx
│       ├── card.tsx
│       └── ...
├── lib/
│   ├── html-parser.ts          # HTML → Component tree
│   ├── html-exporter.ts        # Component tree → HTML
│   └── email-utils.ts          # Email-specific utilities
└── hooks/
    ├── useDragDrop.ts          # DnD Kit hooks
    ├── useSelection.ts         # Selection management
    └── useHistory.ts           # Undo/redo

🔑 Key Features

1. HTML Import

  • Parse HTML strings (from API or paste)
  • Map to component tree
  • Preserve styles and structure
  • Handle nested elements

2. Visual Editing

  • Drag-and-drop components
  • Resize components
  • Property editing
  • Style customization
  • Layout controls

3. HTML Export

  • Generate email-safe HTML
  • Inline CSS
  • Table-based layouts
  • Client compatibility

4. Component System

  • Custom components
  • Reusable blocks
  • Component library
  • Template system

🎨 Component API

Base Component Interface

interface EmailComponent {
  id: string;
  type: string;
  props: Record<string, any>;
  children?: string[];
  parentId?: string;
}

Component Registry

const componentRegistry = {
  container: Container,
  text: Text,
  image: Image,
  button: Button,
  // ...
};

🔄 Data Flow

HTML String
    ↓
[HTML Parser]
    ↓
Component Tree (Zustand Store)
    ↓
[Editor UI] ← → [User Interactions]
    ↓
Updated Component Tree
    ↓
[HTML Exporter]
    ↓
Email-Safe HTML

📝 Implementation Checklist

Core Setup

  • [ ] Install all dependencies
  • [ ] Set up Zustand store
  • [ ] Configure DnD Kit
  • [ ] Set up TipTap
  • [ ] Configure HTML parser

Components

  • [ ] Container (horizontal/vertical)
  • [ ] Text block (TipTap)
  • [ ] Image block
  • [ ] Button block
  • [ ] Divider block
  • [ ] Spacer block

Editor Features

  • [ ] Drag and drop
  • [ ] Selection system
  • [ ] Settings panel
  • [ ] Toolbar
  • [ ] Component palette

Import/Export

  • [ ] HTML parser
  • [ ] Component mapper
  • [ ] HTML exporter
  • [ ] CSS inliner

Advanced

  • [ ] Undo/redo
  • [ ] Templates
  • [ ] Responsive preview
  • [ ] Email client testing

🚦 Getting Started

  1. Install Dependencies

    bun install
  2. Set up shadcn/ui

    npx shadcn@latest init

    Then add components as needed:

    npx shadcn@latest add button
    npx shadcn@latest add input
    npx shadcn@latest add select
    npx shadcn@latest add slider
    npx shadcn@latest add popover
    npx shadcn@latest add card
    npx shadcn@latest add label
    npx shadcn@latest add separator
    npx shadcn@latest add toggle-group
    npx shadcn@latest add dialog
    npx shadcn@latest add tabs
  3. Start Development Server

    bun run dev
  4. Build for Production

    bun run build

📚 Resources

🎯 Comparison with Tabular

| Feature | Tabular | This Editor | | ------------------ | ------- | ------------- | | HTML Import | ✅ | ✅ (Custom) | | HTML Export | ✅ | ✅ (Custom) | | Drag & Drop | ✅ | ✅ (@dnd-kit) | | Component Library | ✅ | ✅ (Custom) | | Responsive Preview | ✅ | ✅ (Planned) | | Templates | ✅ | ✅ (Planned) | | Headless | ❌ | ✅ | | Full Control | ❌ | ✅ |

🤝 Contributing

This is a custom implementation. All components are built from scratch for maximum control and flexibility.

📄 License

[Your License Here]