@npdevind/n-editor
v1.0.3
Published
Simple React text editor using TipTap
Downloads
429
Maintainers
Readme
@npdevind/n-editor
A production-ready, fully-featured rich text editor React component built on top of TipTap. Drop it into any React project with a single import.

✨ Features
- 🖊️ Rich Text Formatting — Bold, Italic, Underline, text color picker
- 🔤 Font Family & Size — Custom dropdown selectors for Font Family and Font Size
- 📐 Text Alignment — Align Left, Center, Right, and Justify via a smart dropdown
- 🔗 Link Insertion — Insert and edit hyperlinks with a simple prompt
- 🖼️ Local Image Upload — Click the image button to pick a photo from your local file system — no URL needed!
- 📊 Configurable Tables — Open the table popover, set your Row and Column counts, and insert instantly
- 📝 Bullet Lists — Toggle bullet lists with a single click
- 🎨 Clean Modern UI — Subtle borders, rounded corners, hover states — a premium SaaS-quality look out of the box
- 🔧 Fully Customizable — Override extensions, styles, and even replace the toolbar with your own render prop
- 🔖 TypeScript First — Complete type definitions included
- ⚡ Lightweight — Peer depends on React; doesn't bundle duplicate React/ReactDOM into your app
📦 Installation
npm install @npdevind/n-editorPeer Dependency: This package requires
react >= 18to be installed in your project.
🚀 Quick Start
import { useState } from "react";
import { TextEditor } from "@npdevind/n-editor";
import "@npdevind/n-editor/style.css"; // Required for styles
export default function App() {
const [content, setContent] = useState("<p>Start typing...</p>");
return <TextEditor value={content} onChange={setContent} />;
}⚠️ Don't forget to import
'@npdevind/n-editor/style.css'in your app. Without it, the editor will have no styles.
🎛️ Props
| Prop | Type | Default | Description |
| ------------------ | ------------------------------- | ------- | ------------------------------------------------------- |
| value | string | "" | The initial HTML content of the editor |
| onChange | (html: string) => void | — | Called every time the content changes, returns raw HTML |
| className | string | "" | CSS class applied to the outer wrapper div |
| editorClassName | string | "" | CSS class applied to the inner content area |
| toolbarClassName | string | "" | CSS class applied to the toolbar |
| readOnly | boolean | false | Disables editing and hides the toolbar |
| showToolbar | boolean | true | Show or hide the default toolbar |
| renderToolbar | (editor: Editor) => ReactNode | — | Render prop to provide a completely custom toolbar |
| extensions | Extension[] | — | Override the default TipTap extensions entirely |
| editorProps | Record<string, any> | — | Extra props passed to the TipTap editorProps option |
📖 Examples
Read-Only Mode
<TextEditor
value="<p>This content is <strong>read-only</strong>.</p>"
readOnly={true}
/>Custom Styling
<TextEditor
value={content}
onChange={setContent}
className="my-outer-wrapper"
editorClassName="my-content-area"
/>/* In your CSS file */
.my-outer-wrapper {
max-width: 800px;
margin: 0 auto;
}
.my-content-area {
min-height: 400px;
font-family: "Georgia", serif;
}Custom Toolbar with renderToolbar
You can replace the entire toolbar using the renderToolbar render prop. It receives the TipTap Editor instance directly:
import { TextEditor } from "@npdevind/n-editor";
import "@npdevind/n-editor/style.css";
<TextEditor
value={content}
onChange={setContent}
renderToolbar={(editor) => (
<div className="my-toolbar">
<button onClick={() => editor.chain().focus().toggleBold().run()}>
Bold
</button>
<button onClick={() => editor.chain().focus().toggleItalic().run()}>
Italic
</button>
</div>
)}
/>;Programmatic Control via ref
import { useRef } from "react";
import { TextEditor, TextEditorRef } from "@npdevind/n-editor";
import "@npdevind/n-editor/style.css";
export default function App() {
const editorRef = useRef<TextEditorRef>(null);
const clearContent = () => {
editorRef.current?.editor?.commands.clearContent();
};
const getHTML = () => {
const html = editorRef.current?.editor?.getHTML();
console.log(html);
};
return (
<>
<TextEditor ref={editorRef} value="<p>Hello world</p>" />
<button onClick={clearContent}>Clear</button>
<button onClick={getHTML}>Log HTML</button>
</>
);
}🎨 Styling & Theming
All elements use prefixed CSS classes (.np-*) to avoid any conflicts with your existing styles:
| Class | Target |
| ------------------------ | ---------------------------------------------- |
| .np-editor-wrapper | The outermost container div |
| .np-editor-toolbar | The toolbar row |
| .np-editor-content | The editable content area |
| .np-toolbar-btn | Individual toolbar icon buttons |
| .np-toolbar-btn.active | Active state on toolbar buttons |
| .np-dropdown | Dropdown containers (Font, Size, Align, Table) |
| .np-divider | The thin vertical dividers in the toolbar |
You can easily override any of these in your own CSS:
/* Make the editor border blue */
.np-editor-wrapper {
border-color: #3b82f6;
}
/* Make active buttons use your brand color */
.np-toolbar-btn.active {
background-color: #dbeafe;
color: #1d4ed8;
}🛠️ Included TipTap Extensions
The following TipTap extensions are bundled by default:
StarterKit(Headings, Paragraphs, Bold, Italic, Lists, Blockquote, Code, History)UnderlineTextStyle+Color(inline text coloring)TextAlignLinkImageFontFamilyTable+TableRow+TableHeader+TableCell- Custom
FontSizeextension (inline CSS size injection)
📤 Output Format
The onChange callback returns raw HTML (standard TipTap HTML output). You can store it in your database as-is and render it back via value prop or with dangerouslySetInnerHTML.
// Rendering saved HTML content safely
<div dangerouslySetInnerHTML={{ __html: savedContent }} />🔗 Links
- NPM Package: https://www.npmjs.com/package/@npdevind/n-editor
- Built with: TipTap · Lucide React · React
📄 License
MIT © npdevind
