rich-text-lite
v7.0.32
Published
A lightweight, customizable rich text editor React component
Maintainers
Readme
rich-text-lite
A lightweight, zero-dependency (besides React) rich text editor React component with a fully customizable toolbar.
Table of Contents
- Installation
- Quick Start
- Props
- Editor Events
- Features
- Toolbar Configuration
- Toolbar Buttons Reference
- CSP / Nonce Support
- Styling & CSS Customization
- Output Format
- Development
Installation
npm install rich-text-liteQuick Start
import { useState } from "react";
import { RichTextEditor } from "rich-text-lite";
import "rich-text-lite/dist/style.css";
function App() {
const [html, setHtml] = useState("");
return (
<RichTextEditor
value={html}
onChange={setHtml}
/>
);
}Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| value | string | "" | HTML content for the editor |
| onChange | (html: string) => void | — | Called with the updated HTML string on each edit |
| onEditorChange | (event: React.FormEvent<HTMLDivElement>, html: string) => void | — | Called on editor input with both the native React event and latest HTML |
| onFocus | (event: React.FocusEvent<HTMLDivElement>) => void | — | Called when the editor receives focus |
| onCopy | (event: React.ClipboardEvent<HTMLDivElement>) => void | — | Called when content is copied from inside the editor |
| onBlur | (event: React.FocusEvent<HTMLDivElement>) => void | — | Called when the editor loses focus |
| onKeyDown | (event: React.KeyboardEvent<HTMLDivElement>) => void | — | Called on keydown inside the editor (after internal shortcuts are handled) |
| onKeyPress | (event: React.KeyboardEvent<HTMLDivElement>) => void | — | Called on keypress inside the editor |
| onSelect | (event: React.SyntheticEvent<HTMLDivElement>) => void | — | Called when a selection event is fired by the editor element |
| getEditorHTML | (getter: () => string) => void | — | Called with a getter function that returns the latest editor HTML on demand |
| isNonceEnabled | boolean | false | Whether to add a nonce attribute to injected <style> tags (for CSP) |
| nonceValue | string | "" | The nonce value to use when isNonceEnabled is true |
| nonceHeaders | string | "" | CSP policy string applied to the nonce meta tag when isNonceEnabled is true |
| placeholder | string | "Start typing..." | Placeholder text shown when editor is empty |
| disabled | boolean | false | Disables toolbar actions and makes the visual/code editor read-only |
| cleanPaste | boolean | true | Sanitizes pasted HTML while keeping common rich text tags |
| tabIndex | number | 0 | Tab index applied to the editor area and every toolbar / table-action button, ensuring a consistent focus order. Pass -1 to remove the entire editor UI from the tab order |
| toolbarConfig.editor.placeholder | string | "Start typing..." | Editor placeholder from config JSON (overrides default placeholder) |
| toolbarConfig.editor.events | object | {} | Alternate place to provide editor events (onChange, onFocus, onCopy, onBlur, onKeyDown, onKeyPress, onSelect) |
| toolbarConfig.selectComponent | React.ComponentType | built-in button dropdown | Custom UI component for toolbar dropdowns (heading, font, size, line-height) |
| toolbarConfig.selectOptionComponent | React.ComponentType | built-in <option> | Option item component for selectComponent (e.g. MUI MenuItem) |
| toolbarConfig.dialogComponent | React.ComponentType | built-in Material UI Dialog | Custom UI component for the link dialog wrapper |
| toolbarConfig.colorPickerComponent | React.ComponentType | built-in swatch + hex/RGB grid | Fully replaces the built-in color picker UI in all four pickers. The component must call onChange(hex) with a valid hex string — this is the consumer's responsibility. toolbarConfig.colors is not required when this is used. See Custom Color Picker UI |
| toolbarConfig.lineHeight.values | Array<string\|number\|{ value, label }> | ['1', '1.15', '1.5', '1.75', '2'] | Configurable values for the line-height dropdown |
| toolbarConfig.font.options | Array<string\|{ value, label }> | Sans Serif, Serif, Monospace | Configurable font-family options for the font dropdown |
| toolbarConfig.size.options | Array<string\|number\|{ value, label }> | 10px–30px in 2px steps | Configurable font-size values for the size dropdown |
| toolbarConfig.colors | Array<string> | built-in 35-color palette | Custom color palette for all color pickers. Each entry must be a valid 3- or 6-digit hex string (e.g. "#fff" or "#ffffff"). Falls back to the built-in palette when omitted, empty, or all entries are invalid |
| toolbarConfig.defaultFontColor | string | "#000000" | Initial color shown in the font-color picker (6-digit hex, e.g. "#ff0000"). Falls back to #000000 when omitted or invalid |
| toolbarConfig.defaultBgColor | string | "#ffff00" | Initial color shown in the background-color picker (6-digit hex). Falls back to #ffff00 when omitted or invalid |
| toolbarConfig.defaultCellBorderColor | string | "#d6dde5" | Default border color in the cell-properties popup when the cell has no explicit border color |
| toolbarConfig.defaultCellBgColor | string | "#ffffff" | Default background color in the cell-properties picker when the cell has no background set |
| toolbarConfig.defaultTableBorderColor | string | "#d6dde5" | Default border color in the table-properties popup |
| toolbarConfig.defaultTableBgColor | string | "#ffffff" | Default background color in the table-properties picker |
| toolbarConfig.defaultTableFontColor | string | "#000000" | Default font color in the table-properties popup |
| toolbarConfig.linkConfig | object | {} | Configures link dialog fields and link-hover quick action popup |
| toolbarConfig.charCount | object | {} | Configures the character count footer (see Character Count Footer) |
| toolbarConfig.charCount.visible | boolean | true | Show or hide the character count footer |
| toolbarConfig.charCount.label | string | "Characters" | Custom label prefix displayed before the count |
| toolbarConfig | object | {} | Configuration object for customizing the toolbar (see below) |
Editor Events
You can subscribe to editor events using either top-level props or toolbarConfig.editor.events.
Top-level props take precedence when both are provided.
<RichTextEditor
value={html}
onChange={(nextHtml) => setHtml(nextHtml)}
onEditorChange={(event, nextHtml) => {
// event target + latest HTML in one callback
console.log("changed", nextHtml);
}}
onFocus={() => console.log("focus")}
onCopy={(e) => console.log("copied", e.clipboardData)}
onBlur={() => console.log("blur")}
onKeyDown={(e) => console.log("keydown", e.key)}
onKeyPress={(e) => console.log("keypress", e.key)}
onSelect={() => console.log("select")}
toolbarConfig={{
editor: {
events: {
// Used only when corresponding top-level prop is not provided
onFocus: () => console.log("focus from config"),
onCopy: (e) => console.log("copied from config", e.type),
},
},
}}
/>import { useRef } from "react";
const getHtmlRef = useRef(() => "");
<RichTextEditor
value={html}
onChange={setHtml}
getEditorHTML={(getter) => {
getHtmlRef.current = getter;
}}
/>
// Call this whenever you need current editor HTML
const latestHtml = getHtmlRef.current();Notes:
onChangeremains the HTML-first callback:(html) => voidonEditorChangeis event-first and also provides HTML:(event, html) => voidonCopyreceives the React clipboard event for copy actions triggered inside the editoronKeyDownstill includes built-in undo/redo shortcut handling by the editor
Features
| Feature | Description |
|---------|-------------|
| Headings | Normal, H1, H2, H3, H4 |
| Font Family | Sans Serif, Serif, Monospace by default; fully configurable via toolbarConfig.font.options |
| Font Size | 10px–30px (2px increments) by default; fully configurable via toolbarConfig.size.options |
| Line Height | Dropdown with configurable values from toolbarConfig.lineHeight.values |
| Bold | Toggle bold |
| Italic | Toggle italic |
| Underline | Toggle underline |
| Strikethrough | Toggle strikethrough |
| Superscript | Toggle superscript |
| Subscript | Toggle subscript |
| Text Color | Color palette (configurable via toolbarConfig.colors) + custom hex + custom RGB input |
| Background Color | Color palette (configurable via toolbarConfig.colors) + custom hex + custom RGB input |
| Hyperlinks | Insert, edit, and remove links (opens in new tab) |
| Bullet List | Unordered list with style options: disc, circle, square |
| Numbered List | Ordered list with style options: decimal, upper-roman, lower-roman, lower-latin, upper-latin, lower-greek |
| Alignment | Align left, center, right, or justify |
| Indent / Outdent | Increase or decrease indentation |
| Text Direction | Toggle LTR / RTL |
| Insert Line | Inserts a horizontal rule (<hr>) |
| Undo / Redo | Toolbar buttons + keyboard shortcuts (Ctrl/Cmd+Z, Ctrl+Y, Cmd/Ctrl+Shift+Z) |
| Clear Formatting | Removes inline formatting from selected content |
| Clean Paste | Removes unsafe/noisy pasted markup while preserving common rich text |
| Character Count | Footer bar showing total plain-text character count, updated live. Configurable via toolbarConfig.charCount |
| Table Tab Navigation | Inside a table, Tab moves to the next cell; Shift+Tab moves to the previous cell. Pressing Tab on the last cell of the last row automatically inserts a new row |
| WCAG 2.1 AA / NVDA | Full role, aria-label, aria-pressed, aria-expanded, aria-live coverage; consistent tabIndex across all interactive elements |
Toolbar Configuration
All toolbar customization is done through the toolbarConfig prop.
<RichTextEditor
value={html}
onChange={setHtml}
toolbarConfig={{
font: {
options: [
{ value: "", label: "Sans Serif" },
{ value: "serif", label: "Serif" },
{ value: "monospace", label: "Monospace" },
{ value: "Arial, sans-serif", label: "Arial" },
{ value: "Georgia, serif", label: "Georgia" },
],
},
size: {
options: [
{ value: "12", label: "12px" },
{ value: "14", label: "14px" },
{ value: "16", label: "16px" },
{ value: "18", label: "18px" },
{ value: "24", label: "24px" },
{ value: "32", label: "32px" },
],
},
lineHeight: {
values: [
"1",
{ value: "1.2", label: "Normal" },
{ value: "1.5", label: "Comfortable" },
{ value: "2", label: "Double" },
],
},
tooltipComponent: MyTooltip, // optional custom tooltip
options: {
bold: { visible: true, tooltip: "Bold (Ctrl+B)", icon: <MyBoldIcon /> },
italic: { visible: false }, // hides the italic button
// ... other buttons
},
}}
/>Font Family Options
Configure the font-family dropdown options via toolbarConfig.font.options. Each entry can be a plain string (used as both value and label) or an object with value and label. The value must be a valid CSS font-family string. Falls back to the built-in list if omitted.
toolbarConfig={{
font: {
options: [
{ value: "", label: "Sans Serif" }, // empty value = browser default
{ value: "serif", label: "Serif" },
{ value: "monospace", label: "Monospace" },
{ value: "Arial, sans-serif", label: "Arial" },
{ value: "Georgia, serif", label: "Georgia" },
"Courier New", // plain string shorthand
],
},
}}Custom font families are injected into the CSS sheet on first use — no extra stylesheet setup needed.
Font Size Options
Configure the font-size dropdown options via toolbarConfig.size.options. Each entry can be a plain number/string (pixel value) or an object with value and label. Falls back to the built-in 10–30px range if omitted.
toolbarConfig={{
size: {
options: [
{ value: "12", label: "Small" },
{ value: "14", label: "Normal" },
{ value: "18", label: "Large" },
{ value: "24", label: "X-Large" },
32, // plain number shorthand
],
},
}}A "Default" option (empty value) that resets font size is always prepended automatically.
Line Height Options
Configure the line-height dropdown options via toolbarConfig.lineHeight.values. See the quick-start example above for the same pattern.
Custom Color Palette
Replace the built-in 35-color palette with your own set of hex colors via toolbarConfig.colors. The same palette is used in the font color picker, background color picker, cell properties panel, and table properties panel.
<RichTextEditor
value={html}
onChange={setHtml}
toolbarConfig={{
colors: [
"#000000", "#ffffff", "#e60000", "#ff9900",
"#ffff00", "#008a00", "#0066cc", "#9933ff",
"#f06666", "#ffc266", "#ffff66", "#66b966",
"#66a3e0", "#c285ff", "#444444", "#888888",
],
}}
/>Rules:
- Each entry must be a valid 3- or 6-digit hex string (e.g.
"#fff"or"#ffffff"). Invalid entries are silently ignored. - Falls back to the built-in 35-color palette when the array is omitted, empty, or contains no valid entries.
- The hex/RGB custom color inputs remain available below the palette regardless of this setting.
- Custom palette colors are injected into the editor's dynamic CSS stylesheet automatically — no extra stylesheet setup required.
- The picker grid column count adapts automatically: up to 7 columns for larger palettes, fewer for smaller ones.
Custom Color Picker UI
Replace the entire built-in swatch + hex/RGB picker UI with your own component via toolbarConfig.colorPickerComponent. When provided it replaces the picker in all four locations: font color, background color, cell properties, and table properties panels.
function MyColorPicker({ color, onChange, onClose, colors }) {
return (
<div style={{ padding: 8, background: "#fff", border: "1px solid #ccc", borderRadius: 8 }}>
<div style={{ display: "flex", flexWrap: "wrap", gap: 4, marginBottom: 8 }}>
{/* use the passed palette, or your own hardcoded set */}
{colors.map((hex) => (
<button
key={hex}
style={{ width: 24, height: 24, background: hex, border: "1px solid #999", borderRadius: 3, cursor: "pointer" }}
onClick={() => onChange(hex)}
/>
))}
</div>
<button onClick={onClose}>Cancel</button>
</div>
);
}
<RichTextEditor
value={html}
onChange={setHtml}
toolbarConfig={{
colorPickerComponent: MyColorPicker,
}}
/>Props received by the component:
| Prop | Type | Description |
|------|------|-------------|
| color | string | Currently active hex color for this picker context |
| onChange | (hex: string) => void | Call with a valid hex string (e.g. "#ff0000") to apply the color and close the picker |
| onClose | () => void | Call to close the picker without applying any color |
| colors | string[] | Resolved palette from toolbarConfig.colors or the built-in default — provided as a convenience; the component may use or ignore it |
Notes:
toolbarConfig.colorsis not required when supplyingcolorPickerComponent. The two props are independent — you can use either, both, or neither.- Calling
onChange(hex)correctly is the consumer's responsibility. Pass a well-formed hex string such as"#rrggbb"or"#rgb". Passing an invalid value will produce no visible color in the editor output. - The component is rendered inside a positioned
.rte-color-picker-customwrapper that anchors it below the toolbar color button. The component controls its own dimensions and inner layout.
Hiding Buttons
Set visible: false on any button to hide it:
toolbarConfig={{
options: {
strikethrough: { visible: false },
direction: { visible: false },
}
}}Custom Tooltips
Override the tooltip text for any button:
toolbarConfig={{
options: {
bold: { tooltip: "Make Bold (Ctrl+B)" },
link: { tooltip: "Add Hyperlink" },
}
}}Custom Icons
Pass any React element as the icon for a button:
import { FaBold, FaItalic } from "react-icons/fa";
toolbarConfig={{
options: {
bold: { icon: <FaBold /> },
italic: { icon: <FaItalic /> },
}
}}For dropdown controls (heading, font, size, lineHeight), if an icon is provided then the trigger shows icon-only mode.
You can control trigger width with width in the same option object.
toolbarConfig={{
options: {
heading: { icon: <span>H</span>, width: 42 },
font: { icon: <span>F</span>, width: 40 },
size: { icon: <span>T</span>, width: 38 },
lineHeight: { icon: <span>LH</span>, width: 46 },
table: {
tableActions: {
rowActions: { icon: <span>R</span>, tooltip: "Row Actions", width: 40 },
columnActions: { icon: <span>C</span>, tooltip: "Column Actions", width: 40 },
deleteTable: { icon: <span>Del</span>, tooltip: "Delete Table" },
},
},
}
}}Table Action Popup Config
When you click a table cell, a compact table action popup appears in the editor.
These actions are configurable through toolbarConfig.options.table.tableActions and follow the same pattern as toolbar buttons.
Supported keys:
cellActions(alias:tableCellActions) - cell action dropdown triggercellStyleActions(aliases:tableCellStyleActions,cellStyles) - cell style dropdown triggercellProperties(alias:tableCellProperties) - cell properties popup triggertableProperties(alias:tableStyleProperties) - table properties popup triggerverticalAlign(aliases:tableVerticalAlignActions,tableVerticalAlign) - vertical align dropdown triggerhorizontalAlign(aliases:tableHorizontalAlignActions,tableHorizontalAlign) - horizontal align dropdown triggerrowActions(alias:tableRowActions) — row action dropdown triggercolumnActions(alias:tableColumnActions) — column action dropdown triggerdeleteTable(alias:tableDelete) — delete table button
Each key accepts:
{
visible?: boolean; // default: true
tooltip?: string; // custom tooltip
icon?: ReactNode; // custom icon
width?: number; // icon trigger width in px (dropdown triggers)
}Example:
toolbarConfig={{
options: {
table: {
tableActions: {
cellActions: {
visible: true,
tooltip: "Cell Actions",
icon: <MyCellIcon />,
width: 42,
},
cellStyleActions: {
visible: true,
tooltip: "Cell Style Actions",
icon: <MyCellStyleIcon />,
width: 42,
},
cellProperties: {
visible: true,
tooltip: "Cell Properties",
icon: <MyCellPropertiesIcon />,
panel: {N
fields: {
borderStyle: {
visible: true,
options: ["solid", "inset", "dashed", "double"],
},
borderColor: { visible: true },
borderWidth: { visible: true, min: 0, max: 10 },
backgroundColor: { visible: true },
},
},
},
tableProperties: {
visible: true,
tooltip: "Table Properties",
icon: <MyTablePropertiesIcon />,
panel: {
fields: {
borderStyle: {
visible: true,
options: ["solid", "inset", "dashed", "double"],
},
borderColor: { visible: true },
borderWidth: { visible: true, min: 0, max: 10 },
backgroundColor: { visible: true },
fontColor: { visible: true },
align: { visible: true, options: ["left", "center", "right"] },
},
},
},
verticalAlign: {
visible: true,
tooltip: "Vertical Align",
icon: <MyVerticalAlignIcon />,
width: 42,
},
horizontalAlign: {
visible: true,
tooltip: "Horizontal Align",
icon: <MyHorizontalAlignIcon />,
width: 42,
},
rowActions: {
visible: true,
tooltip: "Row Actions",
icon: <MyRowIcon />,
width: 42,
},
columnActions: {
visible: true,
tooltip: "Column Actions",
icon: <MyColumnIcon />,
width: 42,
},
deleteTable: {
visible: true,
tooltip: "Delete Table",
icon: <MyDeleteIcon />,
},
},
},
},
}}Custom Tooltip Component
Replace the built-in tooltip with your own component (e.g., Material UI Tooltip, Radix Tooltip, etc.). Your component must accept title and children props:
import { Tooltip as MuiTooltip } from "@mui/material";
function MyTooltip({ title, children }) {
return (
<MuiTooltip title={title} arrow placement="top">
{children}
</MuiTooltip>
);
}
<RichTextEditor
value={html}
onChange={setHtml}
toolbarConfig={{
tooltipComponent: MyTooltip,
}}
/>The custom component receives these props:
| Prop | Type | Description |
|------|------|-------------|
| title | string | The tooltip text |
| children | ReactNode | The button element to wrap |
| arrow | boolean | Always true (hint for arrow display) |
| placement | string | Always "top" |
Custom Select Component (Dropdown UI)
You can replace the built-in button dropdown controls (heading, font, size, line-height) with your own UI component.
Your component receives these props:
classNamevalueonChangeonBlurdisabledoptions(array of{ value, label, disabled?, hidden? })icon(icon configured intoolbarConfig.optionsfor that dropdown)tooltip(resolved tooltip text for that dropdown)iconOnly(boolean, true when icon-mode trigger is active)triggerWidth(resolved icon-mode width in px)children(native<option>elements for compatibility)
Example:
function MySelect({ className, value, onChange, disabled, options }) {
return (
<select
className={className}
value={value}
onChange={(e) => onChange(e)}
disabled={disabled}
>
{options.map((opt) => (
<option key={opt.value} value={opt.value} disabled={opt.disabled} hidden={opt.hidden}>
{opt.label}
</option>
))}
</select>
);
}
<RichTextEditor
value={html}
onChange={setHtml}
toolbarConfig={{
selectComponent: MySelect,
}}
/>For MUI Select, MenuItem is auto-used by default. You can still override with selectOptionComponent if needed:
import Select from "@mui/material/Select";
import MenuItem from "@mui/material/MenuItem";
<RichTextEditor
value={html}
onChange={setHtml}
toolbarConfig={{
selectComponent: Select,
selectOptionComponent: MenuItem,
}}
/>Custom Dialog Component
You can replace the default link dialog wrapper by passing toolbarConfig.dialogComponent.
Your dialog component receives these props:
openonCloseclassNamepaperClassNametitlechildren
Example:
function MyDialog({ open, onClose, className, children }) {
if (!open) return null;
return (
<div className={className} role="dialog" aria-modal="true">
<div className="my-dialog-backdrop" onClick={onClose} />
<div className="my-dialog-panel">{children}</div>
</div>
);
}
<RichTextEditor
value={html}
onChange={setHtml}
toolbarConfig={{
dialogComponent: MyDialog,
}}
/>Link Config (Dialog + Hover Popup)
The link system supports extra fields in the insert/edit dialog:
- Text to display
- Title
- Open in new window
- Download link
It also supports a hover quick-action popup on links (enabled by default) with:
- Edit
- Copy
- Preview
- Unlink
All of this is configurable through toolbarConfig.linkConfig:
<RichTextEditor
value={html}
onChange={setHtml}
toolbarConfig={{
editor: {
placeholder: "Write your content here...",
},
linkConfig: {
dialog: {
text: {
title: "Insert Link",
urlLabel: "URL",
urlPlaceholder: "Enter URL...",
textLabel: "Text To Display",
textPlaceholder: "Displayed text",
titleLabel: "Title",
titlePlaceholder: "Tooltip title",
openInNewWindowLabel: "Open In New Window",
downloadLabel: "Download Link",
},
fields: {
text: { visible: true },
title: { visible: true },
openInNewWindow: { visible: true },
download: { visible: true },
},
actions: {
apply: {
visible: true,
icon: "✓",
label: "Apply",
tooltip: "Apply Link",
showLabel: false,
},
copy: {
visible: true,
icon: "⎘",
label: "Copy",
tooltip: "Copy Link",
showLabel: false,
},
preview: {
visible: true,
icon: "↗",
label: "Preview",
tooltip: "Open Link",
showLabel: false,
},
unlink: {
visible: true,
icon: "✕",
label: "Unlink",
tooltip: "Remove Link",
showLabel: false,
},
},
},
hoverPopup: {
enabled: true,
actions: {
edit: { visible: true, icon: "✎", label: "Edit", tooltip: "Edit Link", showLabel: false },
copy: { visible: true, icon: "⎘", label: "Copy", tooltip: "Copy Link", showLabel: false },
preview: { visible: true, icon: "↗", label: "Preview", tooltip: "Open Link", showLabel: false },
unlink: { visible: true, icon: "✕", label: "Unlink", tooltip: "Remove Link", showLabel: false },
},
},
},
}}
/>Defaults are applied automatically when any of these properties are omitted.
To disable link hover popup globally:
Character Count Footer
A character count footer is shown below the editor by default. It counts plain-text characters (HTML markup is excluded). The counter updates live as the user types, pastes, or undoes/redoes content.
// Shown by default — no config needed
<RichTextEditor value={html} onChange={setHtml} />Hide it via toolbarConfig.charCount.visible:
<RichTextEditor
value={html}
onChange={setHtml}
toolbarConfig={{
charCount: {
visible: false,
},
}}
/>Customize the label prefix:
toolbarConfig={{
charCount: {
visible: true,
label: "Chars", // renders: "Chars: 42"
},
}}| Option | Type | Default | Description |
|--------|------|---------|-------------|
| visible | boolean | true | Show or hide the character count footer |
| label | string | "Characters" | Prefix text rendered before the count number |
To disable link hover popup globally:
toolbarConfig={{
linkConfig: {
hoverPopup: {
enabled: false,
},
},
}}Toolbar Buttons Reference
These are the keys you can use inside toolbarConfig.options:
| Key | Default Tooltip | Description |
|-----|-----------------|-------------|
| bold | "Bold" | Bold button |
| italic | "Italic" | Italic button |
| underline | "Underline" | Underline button |
| strikethrough | "Strikethrough" | Strikethrough button |
| superscript | "Superscript" | Superscript button |
| subscript | "Subscript" | Subscript button |
| link | "Insert Link" | Link button |
| fontColor | "Text Color" | Font color picker button |
| bgColor | "Background Color" | Background color picker button |
| heading | "Headings" | Heading dropdown |
| font | "Font Family" | Font-family dropdown |
| size | "Font Size" | Font-size dropdown |
| lineHeight | "Line Height" | Line-height dropdown |
| bulletList | "Unordered List" | Unordered list style selector (disc/circle/square) |
| numberedList | "Ordered List" | Ordered list style selector (decimal, upper-roman, lower-roman, lower-latin, upper-latin, lower-greek) |
| alignLeft | "Align Left" | Align text left |
| alignCenter | "Align Center" | Align text center |
| alignRight | "Align Right" | Align text right |
| alignJustify | "Align Justify" | Justify text |
| decreaseIndent | "Decrease Indent" | Outdent button |
| increaseIndent | "Increase Indent" | Indent button |
| direction | "Switch to Right-to-Left" | Text direction toggle |
| insertLine | "Insert Line" | Insert horizontal rule (<hr>) |
| undo | "Undo" | Undo button |
| redo | "Redo" | Redo button |
| clearFormatting | "Clear Formatting" | Remove formatting button |
Each key accepts:
{
visible?: boolean; // default: true — set false to hide
tooltip?: string; // override default tooltip text
icon?: ReactNode; // override default icon/label
width?: number; // icon-mode trigger width in px (for heading/font/size/lineHeight)
}Table Hover Action Keys
Configure table hover popup actions using toolbarConfig.options.table.tableActions.
| Key | Default Tooltip | Description |
|-----|-----------------|-------------|
| cellActions | "Cell Actions" | Table cell actions dropdown trigger (alias: tableCellActions) |
| cellStyleActions | "Cell Style Actions" | Table cell style dropdown trigger (aliases: tableCellStyleActions, cellStyles) |
| cellProperties | "Cell Properties" | Table cell properties popup trigger (alias: tableCellProperties) |
| verticalAlign | "Vertical Align" | Table vertical align dropdown trigger (aliases: tableVerticalAlignActions, tableVerticalAlign) |
| horizontalAlign | "Horizontal Align" | Table horizontal align dropdown trigger (aliases: tableHorizontalAlignActions, tableHorizontalAlign) |
| rowActions | "Row Actions" | Table row actions dropdown trigger (alias: tableRowActions) |
| columnActions | "Column Actions" | Table column actions dropdown trigger (alias: tableColumnActions) |
| deleteTable | "Delete Table" | Delete table action button (alias: tableDelete) |
cellStyleActions dropdown options:
Highlighted: applies1px solid redborder to active/selected cells; selecting again resets the borderThick: applies1px double redborder to active/selected cells; selecting again resets the border
Each key accepts:
{
visible?: boolean; // default: true
tooltip?: string; // override default tooltip text
icon?: ReactNode; // override default icon/label
width?: number; // icon-mode trigger width in px (dropdown triggers)
panel?: {
fields?: {
borderStyle?: { visible?: boolean; options?: string[] }; // alias: borderType
borderColor?: { visible?: boolean };
borderWidth?: { visible?: boolean; min?: number; max?: number };
backgroundColor?: { visible?: boolean };
fontColor?: { visible?: boolean };
bold?: { visible?: boolean };
italic?: { visible?: boolean };
underline?: { visible?: boolean };
strikeThrough?: { visible?: boolean }; // alias: strikethrough
};
};
}CSP / Nonce Support
The editor injects a <style> tag at runtime for dynamic color/font classes. If your app uses a Content Security Policy, pass a nonce:
<RichTextEditor
value={html}
onChange={setHtml}
isNonceEnabled={true}
nonceValue="abc123"
nonceHeaders="style-src 'self' 'nonce-abc123';"
/>This adds nonce="abc123" to the injected style element.
Use nonceHeaders when you also want to pass the CSP policy string used by your app.
Styling & CSS Customization
Import the required stylesheet:
import "rich-text-lite/dist/style.css";Key CSS Classes
| Class | Element |
|-------|---------|
| .rte-container | Outermost wrapper |
| .rte-toolbar | Toolbar row |
| .rte-editor | The contentEditable area |
| .rte-btn | All toolbar buttons |
| .rte-btn-active | Active/toggled toolbar button |
| .rte-select | Dropdown selects (heading, font, size) |
| .rte-color-picker | Color picker popup |
| .rte-link-popup | Link insertion popup |
| .rte-footer | Character count footer bar |
| .rte-char-count | Character count text span inside the footer |
| .rte-sr-only | Visually-hidden utility class (screen-reader only content) |
Overriding Styles
You can override any class in your own CSS:
/* Change editor min-height */
.rte-editor {
min-height: 300px;
}
/* Change toolbar background */
.rte-toolbar {
background: #f5f5f5;
}
/* Change active button color */
.rte-btn-active {
background: #dbeafe;
color: #1d4ed8;
}
/* Style the dropdowns */
.rte-select {
border-radius: 4px;
font-size: 13px;
}Output Format
The onChange callback receives raw HTML from the contentEditable area. Example output:
<p><b>Hello</b> <span style="font-size: 20px">world</span></p>
<h3>A heading</h3>
<ul><li>Item one</li><li>Item two</li></ul>You can render this HTML anywhere using dangerouslySetInnerHTML or a sanitizer like DOMPurify.
Development
git clone <repo-url>
cd newgen-rich-text-editor
npm install
npm run devStarts a dev server at http://localhost:5173 with a demo page.
Build
npm run buildOutputs to dist/:
rich-text-lite.es.js— ES modulerich-text-lite.umd.js— UMD bundlestyle.css— Required styles
License
MIT
