A modern, Tiptap-based rich text editor that's fully compatible with Contentful's rich text format. Provides the same editing experience as Contentful's native editor while maintaining perfect compatibility with Contentful's document structure.
- β Full Contentful Compatibility - Seamless conversion between Contentful and Tiptap formats
- β Modern UI - Clean, intuitive interface matching Contentful's design
- β TypeScript Support - Complete type safety with Contentful's rich text types
- β Extensible - Built on Tiptap v2 for easy customization
- β Lightweight - Tree-shakeable, only import what you need
- β Responsive - Works on desktop and mobile devices
- β
Optional Border Control - Customize editor appearance with
showBorderprop (New in v2.0.4)
npm install @crashbytes/contentful-richtext-editorimport React, { useState } from 'react';
import { ContentfulRichTextEditor } from '@crashbytes/contentful-richtext-editor';
import '@crashbytes/contentful-richtext-editor/dist/index.css';
import { Document } from '@contentful/rich-text-types';
function App() {
const [content, setContent] = useState<Document>();
const handleChange = (document: Document) => {
setContent(document);
console.log('Contentful document:', document);
};
return (
<div>
<h1>My Rich Text Editor</h1>
<ContentfulRichTextEditor
placeholder="Start writing your content..."
onChange={handleChange}
initialValue={content}
showBorder={true} // Optional: control border visibility
/>
</div>
);
}
export default App;Control the editor's border appearance with the showBorder prop:
// Default - with border (backward compatible)
<ContentfulRichTextEditor />
// Borderless editor for custom layouts
<ContentfulRichTextEditor
showBorder={false}
className="my-custom-editor"
/>
// Themed borderless editor
<ContentfulRichTextEditor
showBorder={false}
theme="minimal"
/>/* Custom styling for borderless editor */
.my-custom-editor {
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
border-radius: 8px;
}
.my-custom-editor .contentful-toolbar {
background: linear-gradient(45deg, #667eea, #764ba2);
}- Text Formatting: Bold, italic, underline
- Headings: H1 through H6
- Lists: Ordered and unordered lists
- Links: Hyperlinks with URL validation
- Tables: Full table support with headers
- Quotes: Blockquotes
- Embedded Content: Callbacks for Contentful entries and assets
- Undo/Redo: Full history support
import { ContentfulRichTextEditor } from '@crashbytes/contentful-richtext-editor';
import '@crashbytes/contentful-richtext-editor/dist/index.css';
function ContentfulEditor() {
const handleEmbedEntry = async () => {
// Your logic to select a Contentful entry
const entry = await openEntrySelector();
return entry;
};
const handleEmbedAsset = async () => {
// Your logic to select a Contentful asset
const asset = await openAssetSelector();
return asset;
};
return (
<ContentfulRichTextEditor
placeholder="Write your travel tip..."
onChange={(doc) => saveToContentful(doc)}
onEmbedEntry={handleEmbedEntry}
onEmbedAsset={handleEmbedAsset}
theme="contentful"
showBorder={true}
/>
);
}<ContentfulRichTextEditor
placeholder="Simple editor..."
disabledFeatures={['table', 'embed', 'quote']}
theme="minimal"
readonly={false}
showBorder={false}
onChange={handleChange}
/>| Prop | Type | Default | Description |
|---|---|---|---|
showBorder |
boolean |
true |
Control editor border visibility (New in v2.0.4) |
initialValue |
Document |
undefined |
Initial Contentful rich text document |
onChange |
(document: Document) => void |
undefined |
Callback when content changes |
onEmbedEntry |
() => Promise<any> | void |
undefined |
Callback for embedding Contentful entries |
onEmbedAsset |
() => Promise<any> | void |
undefined |
Callback for embedding Contentful assets |
onEmbedInlineEntry |
() => Promise<any> | void |
undefined |
Callback for embedding inline entries |
placeholder |
string |
'Start writing...' |
Placeholder text |
readonly |
boolean |
false |
Whether editor is read-only |
className |
string |
'' |
Additional CSS classes |
theme |
'default' | 'minimal' | 'contentful' |
'contentful' |
Visual theme |
disabledFeatures |
Array<string> |
[] |
Features to disable |
availableHeadings |
Array<1 | 2 | 3 | 4 | 5 | 6> |
[1,2,3,4,5,6] |
Available heading levels |
availableMarks |
Array<'bold' | 'italic' | 'underline'> |
['bold','italic','underline'] |
Available text formatting |
You can disable specific features by passing them in the disabledFeatures array:
'bold'- Bold text formatting'italic'- Italic text formatting'underline'- Underline text formatting'link'- Hyperlinks'lists'- Ordered and unordered lists'headings'- All heading levels'quote'- Blockquotes'table'- Tables'embed'- Embedded content
import {
contentfulToTiptap,
tiptapToContentful,
validateContentfulDocument,
createEmptyDocument,
extractPlainText,
countWords,
findEmbeddedContent
} from '@crashbytes/contentful-richtext-editor';
// Convert between formats
const tiptapJson = contentfulToTiptap(contentfulDocument);
const contentfulDoc = tiptapToContentful(tiptapJson);
// Validation and utilities
const isValid = validateContentfulDocument(someDocument);
const emptyDoc = createEmptyDocument();
const plainText = extractPlainText(document);
const wordCount = countWords(document);
const embedded = findEmbeddedContent(document);The editor comes with default styles that match Contentful's design. Import the CSS:
import '@crashbytes/contentful-richtext-editor/dist/index.css';You can override the default styles by targeting the CSS classes:
.contentful-editor {
border: 2px solid #your-color;
}
.contentful-toolbar {
background: #your-background;
}
.contentful-editor-content {
font-family: 'Your Font', sans-serif;
}
/* Borderless editor styling */
.contentful-editor--borderless {
border: none;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}Contentful (default) Matches Contentful's native editor appearance.
Minimal
Clean, minimal design with reduced visual elements.
Default Standard rich text editor appearance with serif fonts.
// pages/editor.tsx or app/editor/page.tsx
import dynamic from 'next/dynamic';
const ContentfulEditor = dynamic(
() => import('@crashbytes/contentful-richtext-editor').then(mod => mod.ContentfulRichTextEditor),
{ ssr: false }
);
export default function EditorPage() {
return (
<div>
<ContentfulEditor
placeholder="Write something amazing..."
onChange={(doc) => console.log(doc)}
showBorder={false}
/>
</div>
);
}This package is written in TypeScript and includes full type definitions. All Contentful rich text types are re-exported for convenience:
import type {
Document,
Block,
Inline,
Text,
ContentfulRichTextEditorProps
} from '@crashbytes/contentful-richtext-editor';- Chrome 80+
- Firefox 78+
- Safari 13+
- Edge 80+
No breaking changes! Simply update and optionally use the new showBorder prop:
// Before
<ContentfulRichTextEditor />
// After (optional)
<ContentfulRichTextEditor showBorder={false} />Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT Β© CrashBytes
- @contentful/rich-text-react-renderer - For rendering Contentful rich text
- @contentful/rich-text-types - Contentful rich text type definitions
- @tiptap/react - The underlying editor framework
- v2.0.4 - Added optional border control with
showBorderprop - v2.0.3 - Package made publicly accessible
- v2.0.2 - Previous release
- v2.0.0 - Major feature update with automatic configuration
- v1.x - Initial releases
Made with β€οΈ for the Contentful community