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

expo-rte

v1.0.2

Published

A cross-platform native rich text editor for React Native and Expo with adaptive toolbar and customizable styling options.

Readme

Expo Rich Text Editor (expo-rte)

Expo RTE License Version Downloads

A cross-platform rich text editor for React Native and Expo applications

FeaturesInstallationQuick StartAPIExamplesContributing


✨ Features

  • 🛠️ Highly Customizable - Adaptive toolbar with multiple density options
  • 🌍 Cross-Platform - Works seamlessly on iOS and Android
  • Accessible - WCAG compliant with proper ARIA labels
  • 🎯 Multiple Toolbar Styles - Basic, custom styled, and responsive adaptive toolbars
  • 🔄 Format Toggle - Smart formatting state management
  • 📝 Rich Formatting - Bold, italic, underline, strikethrough, lists, links, and more

🚀 Installation

# npm
npm install expo-rte

# yarn
yarn add expo-rte

# pnpm
pnpm add expo-rte

Development Build

For Expo development builds or bare React Native apps, you'll need to rebuild your app after installing:

# For Expo development builds
npx expo run:ios
npx expo run:android

# For bare React Native
npx react-native run-ios
npx react-native run-android

Note: This library requires a development build and will not work with Expo Go.

📱 Quick Start

Basic Usage

import React, { useRef } from 'react';
import { View } from 'react-native';
import { RichTextEditor, RichTextEditorRef } from 'expo-rte';

export default function App() {
  const editorRef = useRef<RichTextEditorRef>(null);

  const handleContentChange = ({ nativeEvent }) => {
    console.log('Content:', nativeEvent.content);
  };

  return (
    <View style={{ flex: 1, padding: 20 }}>
      <RichTextEditor
        ref={editorRef}
        content="<p>Start typing...</p>"
        placeholder="Enter your text here..."
        onChange={handleContentChange}
        style={{ height: 300 }}
      />
    </View>
  );
}

Advanced Usage with Custom Toolbar

import React, { useRef } from 'react';
import { View } from 'react-native';
import { RichTextEditor, RichTextEditorRef, ToolbarConfig } from 'expo-rte';

const customToolbarConfig: ToolbarConfig = {
  adaptive: true,
  groupButtons: true,
  density: 'comfortable',
  scrollable: true,
  showLabels: true,
  buttons: [
    { type: 'bold', icon: 'B', label: 'Bold', group: 'format' },
    { type: 'italic', icon: 'I', label: 'Italic', group: 'format' },
    { type: 'underline', icon: 'U', label: 'Underline', group: 'format' },
    { type: 'bullet', icon: '•', label: 'Bullet List', group: 'list' },
    { type: 'numbered', icon: '1.', label: 'Numbered List', group: 'list' },
    { type: 'link', icon: '🔗', label: 'Link', value: 'https://example.com', group: 'insert' },
    { type: 'undo', icon: '↶', label: 'Undo', group: 'action' },
    { type: 'redo', icon: '↷', label: 'Redo', group: 'action' },
  ],
};

export default function AdvancedEditor() {
  const editorRef = useRef<RichTextEditorRef>(null);

  return (
    <View style={{ flex: 1, padding: 20 }}>
      <RichTextEditor
        ref={editorRef}
        content="<p><strong>Rich</strong> <em>text</em> editor with <u>custom</u> toolbar!</p>"
        toolbarConfig={customToolbarConfig}
        style={{ height: 400 }}
      />
    </View>
  );
}

📚 API Reference

RichTextEditor Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | content | string | "" | Initial HTML content | | placeholder | string | "" | Placeholder text | | editable | boolean | true | Whether the editor is editable | | showToolbar | boolean | true | Whether to show the toolbar | | toolbarConfig | ToolbarConfig | undefined | Custom toolbar configuration | | customToolbar | ReactNode | undefined | Completely custom toolbar component | | style | ViewStyle | undefined | Container style | | onChange | function | undefined | Content change callback |

RichTextEditorRef Methods

interface RichTextEditorRef {
  setContent: (content: string) => Promise<void>;
  getContent: () => Promise<string>;
  format: (type: FormatType, value?: any) => Promise<void>;
  undo: () => Promise<void>;
  redo: () => Promise<void>;
}

ToolbarConfig

interface ToolbarConfig {
  buttons?: ToolbarButton[];           // Custom button array
  style?: ViewStyle;                   // Toolbar container styling
  buttonStyle?: ViewStyle;             // Individual button styling
  buttonTextStyle?: TextStyle;         // Button text styling
  scrollable?: boolean;                // Enable horizontal scrolling
  showLabels?: boolean;                // Show button labels
  groupButtons?: boolean;              // Group buttons by category
  adaptive?: boolean;                  // Auto-adapt to screen size
  compactMode?: boolean;               // Use compact layout
  maxButtons?: number;                 // Max buttons for adaptive mode
  density?: 'comfortable' | 'compact' | 'dense'; // Button density
}

ToolbarButton

interface ToolbarButton {
  type: FormatType;                    // Button action type
  icon: string | ReactNode;            // Button icon (text or component)
  label?: string;                      // Optional label text
  value?: any;                         // Optional value (e.g., for links)
  group?: 'format' | 'list' | 'action' | 'insert'; // Button grouping
}

Format Types

type FormatType = 
  | 'bold' 
  | 'italic' 
  | 'underline' 
  | 'strikethrough' 
  | 'bullet' 
  | 'numbered' 
  | 'link' 
  | 'undo' 
  | 'redo';

🎨 Toolbar Customization

Responsive Toolbar

const responsiveConfig: ToolbarConfig = {
  adaptive: true,
  density: 'comfortable',
  scrollable: true,
  groupButtons: true,
  maxButtons: 8,
  buttons: [
    { type: 'bold', icon: 'B', label: 'Bold', group: 'format' },
    { type: 'italic', icon: 'I', label: 'Italic', group: 'format' },
    { type: 'underline', icon: 'U', label: 'Underline', group: 'format' },
    { type: 'bullet', icon: '•', label: 'Bullets', group: 'list' },
    { type: 'numbered', icon: '1.', label: 'Numbers', group: 'list' },
    { type: 'undo', icon: '↶', label: 'Undo', group: 'action' },
    { type: 'redo', icon: '↷', label: 'Redo', group: 'action' },
  ],
};

Custom Styled Toolbar

const customConfig: ToolbarConfig = {
  buttons: [
    { type: 'bold', icon: '𝐁', label: 'Bold' },
    { type: 'italic', icon: '𝐼', label: 'Italic' },
    { type: 'link', icon: '🔗', label: 'Link', value: 'https://example.com' },
  ],
  buttonStyle: {
    backgroundColor: '#007AFF',
    borderRadius: 8,
    paddingHorizontal: 12,
  },
  buttonTextStyle: {
    color: '#ffffff',
    fontWeight: '600',
  },
  showLabels: true,
  density: 'comfortable',
};

📚 Documentation Examples

For comprehensive examples and real-world usage patterns, see our Examples Documentation:

Quick Example

import React, { useRef } from 'react';
import { View } from 'react-native';
import { RichTextEditor, RichTextEditorRef, ToolbarConfig } from 'expo-rte';

const customConfig: ToolbarConfig = {
  adaptive: true,
  density: 'comfortable',
  buttons: [
    { type: 'bold', icon: 'B', label: 'Bold' },
    { type: 'italic', icon: 'I', label: 'Italic' },
    { type: 'undo', icon: '↶', label: 'Undo' },
  ],
};

export default function MyEditor() {
  const editorRef = useRef<RichTextEditorRef>(null);

  return (
    <View style={{ flex: 1, padding: 20 }}>
      <RichTextEditor
        ref={editorRef}
        toolbarConfig={customConfig}
        placeholder="Start writing..."
        style={{ height: 300 }}
      />
    </View>
  );
}

📱 Responsive Design

The editor automatically adapts to different screen sizes:

  • 📱 Small screens (<400px): Compact buttons, essential formatting only
  • 💻 Regular screens (400-768px): Standard button sizes, full toolbar
  • 📊 Tablets (768px+): Larger touch targets, more spacing

Manual Responsive Configuration

const responsiveConfig: ToolbarConfig = {
  adaptive: true,
  density: 'comfortable', // 'comfortable' | 'compact' | 'dense'
  maxButtons: 6, // Limit buttons on small screens
  scrollable: true, // Enable scrolling when needed
};

🔧 Advanced Features

Content Import/Export

// Set rich content
await editorRef.current?.setContent(`
  <h1>My Document</h1>
  <p>This is <strong>bold</strong> and <em>italic</em> text.</p>
  <ul>
    <li>Bullet point 1</li>
    <li>Bullet point 2</li>
  </ul>
`);

// Get HTML content
const htmlContent = await editorRef.current?.getContent();

Undo/Redo

// Programmatic undo/redo
await editorRef.current?.undo();
await editorRef.current?.redo();

🛠️ Customization

Custom Button Icons

import { MaterialIcons } from '@expo/vector-icons';

const customButtons: ToolbarButton[] = [
  {
    type: 'bold',
    icon: <MaterialIcons name="format-bold" size={20} color="#333" />,
    label: 'Bold'
  },
  // ... more buttons with custom icons
];

Styling

const customStyle = {
  container: {
    borderRadius: 12,
    backgroundColor: '#f5f5f5',
  },
  toolbar: {
    backgroundColor: '#ffffff',
    borderBottomColor: '#e0e0e0',
  },
  button: {
    backgroundColor: '#007AFF',
    borderRadius: 8,
  },
  buttonText: {
    color: '#ffffff',
    fontWeight: '600',
  }
};

<RichTextEditor
  style={customStyle.container}
  toolbarConfig={{
    style: customStyle.toolbar,
    buttonStyle: customStyle.button,
    buttonTextStyle: customStyle.buttonText,
  }}
/>

🐛 Troubleshooting

Common Issues

  1. Editor not appearing: Ensure you're using a development build, not Expo Go
  2. Formatting not working: Check that the toolbar is enabled and buttons are configured
  3. Content not updating: Verify the onChange callback is properly connected
  4. Performance issues: Consider using adaptive: true for better performance on lower-end devices

Debug Mode

// Enable debug logging
<RichTextEditor
  onChange={({ nativeEvent }) => {
    console.log('Content changed:', nativeEvent.content);
  }}
/>

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

# Clone the repository
git clone https://github.com/mdadul/expo-rte.git
cd expo-rte

# Install dependencies
npm install

# Run the example app
cd example
npm install
npx expo run:ios # or npx expo run:android

Running Tests

npm test

Building

npm run build

📄 License

MIT License - see the LICENSE file for details.

⬆ Back to top

Made with ❤️ by Emdadul Islam