tiptap-editor-custom-stg
v1.0.7
Published
Custom Tiptap rich text editor with toolbar, table support, and file upload integration
Maintainers
Readme
tiptap-editor-custom-stg
Custom Tiptap rich text editor with toolbar, table support, and file upload integration.
Features
- 📝 Rich text editing powered by Tiptap
- 🎨 Toolbar with font family, size, text/background colors
- 📊 Table support (insert, resize, merge/split cells)
- 🖼️ Image upload (click or paste screenshot)
- 📎 File attachment support
- 🔗 Link insert/edit
- 🎯 Read-only mode
- ⚡ Full TypeScript support
For Users
Installation
npm install tiptap-editor-custom-stgThen install the required peer dependencies:
npm install react react-dom \
@tiptap/react @tiptap/core @tiptap/pm \
@tiptap/starter-kit \
@tiptap/extension-link \
@tiptap/extension-underline \
@tiptap/extension-image \
@tiptap/extension-text-style \
@tiptap/extension-color \
@tiptap/extension-font-family \
@tiptap/extension-superscript \
@tiptap/extension-subscript \
@tiptap/extension-text-align \
@tiptap/extension-placeholder \
@tiptap/extension-table \
@tiptap/extension-table-row \
@tiptap/extension-table-cell \
@tiptap/extension-table-headerBasic Usage
import { TiptapEditor } from 'tiptap-editor-custom-stg';
import 'tiptap-editor-custom-stg/styles'; // required
function MyComponent() {
const [content, setContent] = React.useState('<p>Hello World!</p>');
return (
<TiptapEditor
elementId='my-editor'
content={content}
editMode={true}
docNum='DOC-001'
placeholder='Start typing...'
toolbarConfig={{
groups: ['history', 'font', 'fontSize', 'textColor', 'list', 'link', 'insert'],
showDividers: true,
}}
receiveData={(id, html) => setContent(html)}
onUploadFile={async (file, docNum) => {
const url = await uploadToYourStorage(file, docNum);
return url;
}}
onAlert={(msg) => alert(msg)}
onLoadingChange={(isLoading) => setLoading(isLoading)}
/>
);
}Props
| Prop | Type | Required | Default | Description |
| -------------------- | ----------------------------------------------------- | -------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| elementId | string | ✅ | — | Unique ID for the editor instance |
| content | string | ✅ | — | HTML content |
| editMode | boolean | ✅ | — | true = editable, false = read-only |
| docNum | string | ✅ | — | Document number passed to onUploadFile |
| receiveData | (id, html) => void | — | — | Called on every content change |
| receiveStatus | (id, loading) => void | — | — | Called when per-editor upload status changes |
| onUploadFile | (file, docNum) => Promise<string> | — | — | Upload handler, must return the file URL |
| onAlert | (message) => void | — | window.alert | Custom alert/notification function |
| onLoadingChange | (isLoading) => void | — | — | Global loading state callback |
| onRegisterReset | (callback) => () => void | — | — | Register a reset callback, returns cleanup fn |
| placeholder | string | — | 'Start typing...' | Editor placeholder text. This value is passed into Tiptap's Placeholder extension and is shown when the editor is empty |
| toolbarConfig | { groups?: ToolbarGroup[]; showDividers?: boolean } | — | default toolbar config | Customize which toolbar groups are shown and whether dividers are rendered |
| customValidationFn | (files: File[]) => Promise<boolean> | — | — | Custom async function to validate selected files before upload. Return true to proceed or false to abort. |
Styling
Styles are shipped as a separate CSS file. Import it once in your app:
import 'tiptap-editor-custom-stg/styles';To override default styles, target these CSS classes:
.tiptap-editor-wrapper {
/* outer container */
}
.tiptap-toolbar {
/* toolbar */
}
.ProseMirror {
/* editor content area */
}Toolbar Configuration
Use toolbarConfig to control which toolbar groups are displayed and whether dividers appear between them.
<TiptapEditor
elementId='my-editor'
content={content}
editMode={true}
docNum='DOC-001'
toolbarConfig={{
groups: ['history', 'font', 'fontSize', 'textColor', 'list', 'link', 'insert'],
showDividers: true,
}}
/>Available toolbar groups:
historyfontfontSizetextColorhighlightlistalignmenttableinlinelinkinsert
Default toolbar groups:
['history', 'font', 'fontSize', 'textColor', 'highlight', 'list', 'alignment', 'table', 'inline', 'link', 'insert'];Example: minimal toolbar without dividers
<TiptapEditor
elementId='my-editor'
content={content}
editMode={true}
docNum='DOC-001'
toolbarConfig={{
groups: ['history', 'inline', 'link'],
showDividers: false,
}}
/>Placeholder
You can customize the empty-state placeholder text with the placeholder prop:
<TiptapEditor elementId='my-editor' content='' editMode={true} docNum='DOC-001' placeholder='Start typing...' />The placeholder is driven by Tiptap's Placeholder extension configuration, so the placeholder prop is the source of truth for the text shown in the editor.
Content Reset
Use onRegisterReset to let a parent component reset the editor content programmatically:
const resetRef = React.useRef<((content: string) => void) | null>(null);
<TiptapEditor
onRegisterReset={(callback) => {
resetRef.current = callback;
return () => {
resetRef.current = null;
};
}}
/>;
// Reset from anywhere:
resetRef.current?.('<p>New content</p>');For Developers
Project Structure
tiptap-editor-custom-stg/
├── src/
│ ├── index.ts # public exports
│ ├── TiptapEditor.tsx # main component
│ ├── ToolbarGroups.tsx # toolbar sub-components
│ ├── Icons.tsx # SVG icons
│ ├── extensions.ts # Tiptap extension factory (exports createTiptapExtensions)
│ ├── fontSize.ts # custom FontSize extension
│ ├── backgroundColor.ts # custom BackgroundColor extension
│ ├── constants.ts # colors, fonts, sizes
│ ├── types.ts # TypeScript types
│ ├── utils.ts # upload helper
│ ├── tiptap.scss # editor styles
│ └── styles.d.ts # CSS type declaration
├── dist/ # build output (generated)
├── package.json
├── tsconfig.json
└── tsup.config.tsBuild
npm install
npm run buildThis runs two steps:
build:js— compiles TypeScript via tsup →dist/index.js,dist/index.mjs,dist/index.d.tsbuild:css— compiles SCSS via sass →dist/index.css, copiesdist/styles.d.ts
Local Testing (without publishing)
Use npm pack to create a local tarball and install it directly into your project.
npm pack creates a local .tgz package archive using npm's publish rules. In practice, it lets you verify and install the same package contents that would be published to npm, without actually publishing.
For this project, because package.json includes "files": ["dist"], the packed tarball mainly contains:
dist/**package.jsonREADME.mdLICENSE(if present)
So npm pack is not packing the entire repository by default. It is packing the publishable package contents.
# 1. Build and pack
cd tiptap-editor-custom-stg
npm run build
npm pack
或者: npm run build && npm pack
# Creates: tiptap-editor-custom-stg-1.0.0.tgz
# 2. Install into your project
cd ../your-project
npm install ../tiptap-editor-custom-stg/tiptap-editor-custom-stg-1.0.0.tgzAfter making code changes, rebuild and reinstall:
cd tiptap-editor-custom-stg
npm run build && npm pack
cd ../your-project
npm install ../tiptap-editor-custom-stg/tiptap-editor-custom-stg-1.0.0.tgz --forcePublishing to npm
npm login
npm publishAfter publishing, install normally:
npm install tiptap-editor-custom-stgLicense
MIT
