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

@beefree.io/react-email-builder

v1.0.3

Published

React components and hooks for the Beefree SDK — drag-and-drop email, page, and popup builder with collaborative editing

Readme

Beefree SDK React Component

npm version License CI TypeScript React

A React wrapper component for the Beefree SDK, making it easy to integrate the Beefree email/page builder into your React applications.

Beefree SDK React Builder

Table of Contents

What is Beefree SDK?

Beefree SDK is a drag-and-drop visual content builder that lets your users design professional emails, landing pages, and popups — without writing code. It powers thousands of SaaS applications worldwide, offering a white-label, embeddable editing experience with real-time collaborative editing, responsive design output, and extensive customization options.

This React package provides a Builder component and a useBuilder hook that handle SDK initialization, lifecycle management, and configuration updates — giving you a React-friendly API to integrate the full Beefree editing experience into your application.

Overview

Features

  • 🎯 Simple React Integration - Drop-in component with minimal setup
  • 🪝 React Hooks Support - useBuilder hook for programmatic control
  • 🔄 Dynamic Configuration - Update builder configuration on the fly
  • 👥 Collaborative Editing - Support for shared/collaborative sessions
  • 📦 TypeScript Support - Full TypeScript definitions included
  • 🎨 Customizable - Full access to Beefree SDK configuration options

Compatibility

| Requirement | Version | |-------------|---------| | React | 17, 18, or 19 | | Node.js | >= 18.0.0 | | TypeScript | >= 4.7 (optional, but recommended) | | Browsers | Chrome, Firefox, Safari, Edge (latest 2 versions) |

Installation

npm install @beefree.io/react-email-builder
# or
yarn add @beefree.io/react-email-builder

Quick Start

1. Get your credentials

Sign up at developers.beefree.io to get your client_id and client_secret.

2. Set up token generation on your backend

Your backend server should exchange credentials for a short-lived token (see Security: Server-Side Token Generation below for details):

// Example: Node.js/Express backend endpoint
app.post('/api/beefree/token', async (req, res) => {
  const response = await fetch('https://auth.getbee.io/loginV2', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      client_id: process.env.BEEFREE_CLIENT_ID,
      client_secret: process.env.BEEFREE_CLIENT_SECRET,
      grant_type: 'password',
    }),
  })
  res.json(await response.json())
})

3. Integrate the builder in your React app

import { useState, useEffect } from 'react'
import { Builder, IToken, useBuilder } from '@beefree.io/react-email-builder'

function EmailEditor() {
  const [token, setToken] = useState<IToken | null>(null)

  const { save, preview } = useBuilder({
    uid: 'user-123',
    container: 'bee-container',
    language: 'en-US',
  })

  useEffect(() => {
    fetch('/api/beefree/token', { method: 'POST' })
      .then((res) => res.json())
      .then(setToken)
  }, [])

  if (!token) return <div>Loading builder...</div>

  return (
    <div>
      <div>
        <button onClick={() => preview()}>Preview</button>
        <button onClick={() => save()}>Save</button>
      </div>
      <Builder
        id="bee-container"
        token={token}
        template={{ comments: {}, page: {} }}
        onSave={(json, html) => console.log('Saved:', { json, html })}
        onError={(err) => console.error('Builder error:', err)}
      />
    </div>
  )
}

API Reference

Builder Component

Props

| Prop | Type | Required | Description | |--------------------|----------------------------------------|----------|--------------------------------------------------------------| | id | string | Yes | The container ID (must match the container from useBuilder) | | token | IToken | Yes | Authentication token from Beefree API | | template | IEntityContentJson | Yes | Initial template/content to load | | shared | boolean | No | Enable collaborative editing session | | sessionId | string | No | Session ID to join (for collaborative editing) | | width | React.CSSProperties['width'] | No | Container width (default: '100%') | | height | React.CSSProperties['height'] | No | Container height (default: '800px') | | loaderUrl | string | No | Custom loader URL for the Beefree SDK | | onLoad | () => void | No | Callback when builder is fully loaded and ready | | onSave | (json, html) => void | No | Callback when content is saved | | onChange | (json, metadata) => void | No | Callback when content changes | | onError | (error: BeePluginError) => void | No | Error callback handler | | onWarning | (warning: BeePluginError) => void | No | Warning callback handler | | onSaveRow | (row: string) => void | No | Callback when a row is saved | | onRemoteChange | (data) => void | No | Callback for collaborative editing remote changes | | onSessionStarted | (data: { sessionId: string }) => void | No | Callback when collaborative session starts | | onTemplateLanguageChange | (language) => void | No | Callback when template language changes |

Basic Configuration

useBuilder({
  uid: 'user-123',
  container: 'bee-container',

  // Customization
  language: 'en-US',
  specialLinks: [
    { type: 'unsubscribe', label: 'Unsubscribe', link: '[unsubscribe]' }
  ],

  // Content management
  contentDialog: {
    saveRow: {
      label: 'Save Row',
      handler: (resolve) => resolve({ name: 'My Row' })
    }
  }
})

return (
  <Builder
    token={token}
    template={{
      comments: {},
      page: {},
    }}
    onSave={(jsonFile, htmlFile) => {
      console.log('Saved:', {jsonFile, htmlFile})
    }}
  />
)

Hooks

useBuilder

The useBuilder hook provides programmatic control over the builder instance and allows you to dynamically update configuration properties (non-callback properties like uid, language, etc.).

import { Builder, useBuilder } from '@beefree.io/react-email-builder'

function MyComponent() {
  // Initialize useBuilder with config including container ID
  const initialConfig = {
    container: 'bee-editor', // This is the ID that links hook and component
    uid: 'user-123',
    language: 'en-US',
    // ...more configs
  }

  const { updateConfig, load, save, saveAsTemplate } = useBuilder(initialConfig)

  // Update configuration dynamically
  const changeLanguage = (lang: string) => {
    updateConfig({ language: lang })
  }

  const changeUser = (userId: string) => {
    updateConfig({ uid: userId })
  }

  const handleSave = async () => {
    const result = await save()
    console.log('Saved:', result)
  }

  return (
    <div>
      <button onClick={() => changeLanguage('it-IT')}>Switch to Italian</button>
      <button onClick={() => changeUser('user-456')}>Change User</button>
      <button onClick={handleSave}>Save</button>

      <Builder
        id="bee-editor"
        token={token}
        template={template}
        // Define callbacks directly in the component
        onSave={(json, html) => {
          console.log('Content saved:', json, html)
        }}
        onChange={(json, metadata) => {
          console.log('Content changed')
        }}
        onLoad={() => {
          console.log('Builder is ready!')
        }}
      />
    </div>
  )
}

Best Practices

🔒 Security: Server-Side Token Generation

⚠️ CRITICAL: Never expose your Beefree API credentials in frontend code!

❌ Bad (Insecure):

// DON'T DO THIS!
const token = await fetch('https://auth.beefree.io/token', {
  method: 'POST',
  body: JSON.stringify({
    client_id: 'your-client-id',      // ❌ Exposed!
    client_secret: 'your-secret',      // ❌ Exposed!
  })
})

✅ Good (Secure):

  1. Backend API endpoint (Node.js/Express example):
// backend/routes/auth.js
app.post('/api/beefree/token', async (req, res) => {
  const response = await fetch('https://auth.beefree.io/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      client_id: process.env.BEEFREE_CLIENT_ID,
      client_secret: process.env.BEEFREE_CLIENT_SECRET,
      uid: req.user.id // Your user's ID
    })
  })

  const token = await response.json()
  res.json(token)
})
  1. Frontend:
// frontend/App.tsx
const fetchToken = async () => {
  const response = await fetch('/api/beefree/token', {
    credentials: 'include' // Include session cookies
  })
  return response.json()
}

📝 Configuration Management

Keep your configuration in useMemo to prevent unnecessary re-renders:

const config = useMemo(() => ({
  uid: user.id,
  container: 'bee-container',
  onSave: handleSave,
  // ... other config
}), [user.id, handleSave])

🎯 Unique Container IDs

When using multiple builders on the same page, ensure unique container IDs:

const config1 = useBuilder({ container: 'builder-1', ...otherProperties })
const config2 = useBuilder({ container: 'builder-2', ...otherProperties})

🔄 Collaborative Editing

For collaborative sessions, share the sessionId between users:

function CollaborativeEditor() {
  const [sessionId, setSessionId] = useState<string | null>(null)

  return (
    <>
      {/* Host creates the session */}
      <Builder
        shared={true}
        onSessionStarted={({ sessionId }) => setSessionId(sessionId)}
        {...otherProps}
      />

      {/* Guest joins with sessionId */}
      {sessionId && (
        <Builder
          shared={true}
          sessionId={sessionId}
          {...otherProps}
        />
      )}
    </>
  )
}

Advanced Usage

Custom Content Dialogs

const config = {
  contentDialog: {
    saveRow: {
      label: 'Save to Library',
      handler: async (resolve) => {
        // Show your custom UI, then resolve
        const rowName = await showCustomDialog()
        resolve({ name: rowName })
      }
    },
    addOn: {
      handler: async (resolve) => {
        const content = await fetchCustomContent()
        resolve(content)
      }
    }
  }
}

External Content Sources

const config = {
  rowsConfiguration: {
    externalContentURLs: [
      {
        name: 'My Saved Rows',
        handle: 'saved-rows',
        isLocal: true
      }
    ]
  },
  hooks: {
    getRows: {
      handler: async (resolve, reject, args) => {
        if (args.handle === 'saved-rows') {
          const rows = await fetchSavedRows()
          resolve(rows)
        } else {
          reject('Handle not found')
        }
      }
    }
  }
}

Mentions/Merge Tags

const config = {
  hooks: {
    getMentions: {
      handler: async (resolve) => {
        const mentions = [
          { username: 'FirstName', value: '{{firstName}}', uid: 'fn' },
          { username: 'LastName', value: '{{lastName}}', uid: 'ln' }
        ]
        resolve(mentions)
      }
    }
  }
}

Examples

The /example directory contains a fully working application that demonstrates:

  • Token authentication flow
  • Collaborative editing with template preservation
  • Save, preview, and export functionality
  • Multi-language UI switching
  • Multiple builder types (Email, Page, Popup, File Manager)

See the example README for setup instructions.

Quick start:

cp .env.sample .env   # Fill in your Beefree credentials
yarn install
yarn start            # Opens at http://localhost:3000

FAQ

How do I authenticate with the Beefree SDK?

Authentication requires a client_id and client_secret, which you get by signing up at developers.beefree.io. These credentials should never be exposed in frontend code. Instead, create a backend endpoint that exchanges them for a short-lived token and pass that token to the Builder component. See Security: Server-Side Token Generation for a complete example.

Can I use this with Next.js, Remix, or Vite?

Yes. This package works with any React-based framework. The Builder component renders a client-side iframe, so in Next.js you should use it inside a 'use client' component. For Vite, it works out of the box. For Remix, use a ClientOnly wrapper or lazy-load the component.

Does it support collaborative editing?

Yes. Set shared={true} on the Builder component to create a collaborative session. The onSessionStarted callback provides a sessionId that other users can use to join the same session. See Collaborative Editing for a full example.

What email clients are supported?

The Beefree SDK generates responsive HTML that is compatible with all major email clients, including Gmail, Outlook (desktop and web), Apple Mail, Yahoo Mail, and mobile email apps. The output follows email HTML best practices with inline CSS and table-based layouts for maximum compatibility.

Can I customize the builder UI?

Yes. The Beefree SDK supports extensive UI customization including custom content dialogs, external content sources, merge tags, special links, and more. See Advanced Usage and the Beefree SDK Documentation for the full range of customization options.

How do I load an existing template?

Pass your template JSON to the template prop of the Builder component. You can also use the load method from the useBuilder hook to programmatically load a template at any time after initialization.

Development

Setup

# Install dependencies
yarn install

# Start development server
yarn start

# Run tests
yarn test

Building

yarn build

Outputs:

  • dist/index.js - CommonJS bundle
  • dist/index.es.js - ES module bundle
  • dist/index.d.ts - TypeScript definitions

Troubleshooting

Builder not loading

  1. Verify token is valid and not expired
  2. Check console for errors
  3. Ensure container ID is unique on the page

Other Frameworks

Beefree SDK wrappers are available for the following frameworks:

| Framework | Package | Repository | |-----------|---------|------------| | Angular | @beefree.io/angular-email-builder | BeefreeSDK/angular-email-builder |

License

Apache-2.0 License

Support

For issues related to:

Resources