Overview
The getPlainText method extracts plain text content from the editor, stripping all formatting, structure, and metadata. It’s useful for character counts, search indexing, or plain text exports.
Usage
import { useYooptaEditor } from '@yoopta/editor';
function CharacterCount() {
const editor = useYooptaEditor();
const text = editor.getPlainText(editor.children);
return <div>{text.length} characters</div>;
}
Signature
function getPlainText(
editor: YooEditor,
content: YooptaContentValue
): string
Parameters
The editor instance (automatically provided when called as editor.getPlainText())
content
YooptaContentValue
required
The content to convert to plain text. Typically editor.children for current content.
Returns
string - Plain text representation with all formatting removed
How It Works
Under the hood, getPlainText converts content to HTML first, then extracts the text:
export function getPlainText(editor: YooEditor, content: YooptaContentValue) {
const htmlString = getHTML(editor, content);
const div = document.createElement('div');
div.innerHTML = htmlString;
return div.innerText;
}
This approach:
- Uses browser’s native text extraction
- Preserves line breaks and spacing
- Removes all HTML tags and attributes
- Handles special characters correctly
Examples
Character Counter
function CharacterCounter() {
const editor = useYooptaEditor();
const [count, setCount] = useState(0);
useEffect(() => {
const handleChange = () => {
const text = editor.getPlainText(editor.children);
setCount(text.length);
};
handleChange(); // Initial count
editor.on('change', handleChange);
return () => editor.off('change', handleChange);
}, [editor]);
return (
<div className="character-count">
{count.toLocaleString()} characters
</div>
);
}
Word Counter
function WordCounter() {
const editor = useYooptaEditor();
const [wordCount, setWordCount] = useState(0);
useEffect(() => {
const handleChange = () => {
const text = editor.getPlainText(editor.children);
const words = text.trim().split(/\s+/).filter(Boolean);
setWordCount(words.length);
};
handleChange();
editor.on('change', handleChange);
return () => editor.off('change', handleChange);
}, [editor]);
return <div>{wordCount} words</div>;
}
Reading Time Estimate
function ReadingTime() {
const editor = useYooptaEditor();
const [minutes, setMinutes] = useState(0);
useEffect(() => {
const handleChange = () => {
const text = editor.getPlainText(editor.children);
const words = text.trim().split(/\s+/).filter(Boolean).length;
const wordsPerMinute = 200;
const readingMinutes = Math.ceil(words / wordsPerMinute);
setMinutes(readingMinutes);
};
handleChange();
editor.on('change', handleChange);
return () => editor.off('change', handleChange);
}, [editor]);
return (
<div className="reading-time">
{minutes} min read
</div>
);
}
Copy Plain Text
function CopyPlainTextButton() {
const editor = useYooptaEditor();
const [copied, setCopied] = useState(false);
const handleCopy = async () => {
const text = editor.getPlainText(editor.children);
await navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<button onClick={handleCopy}>
{copied ? '✓ Copied' : 'Copy Text'}
</button>
);
}
Search/Filter Content
function SearchableContent() {
const editor = useYooptaEditor();
const [searchTerm, setSearchTerm] = useState('');
const [matches, setMatches] = useState(0);
useEffect(() => {
if (!searchTerm) {
setMatches(0);
return;
}
const text = editor.getPlainText(editor.children);
const regex = new RegExp(searchTerm, 'gi');
const found = text.match(regex);
setMatches(found ? found.length : 0);
}, [searchTerm, editor.children]);
return (
<div>
<input
type="text"
placeholder="Search content..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
{searchTerm && <p>{matches} matches found</p>}
</div>
);
}
Export to Text File
function ExportTextButton() {
const editor = useYooptaEditor();
const handleExport = () => {
const text = editor.getPlainText(editor.children);
const blob = new Blob([text], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'document.txt';
link.click();
URL.revokeObjectURL(url);
};
return <button onClick={handleExport}>Download as Text</button>;
}
Content Length Validator
function ContentLengthValidator({ maxLength = 1000 }) {
const editor = useYooptaEditor();
const [length, setLength] = useState(0);
const [isValid, setIsValid] = useState(true);
useEffect(() => {
const handleChange = () => {
const text = editor.getPlainText(editor.children);
const currentLength = text.length;
setLength(currentLength);
setIsValid(currentLength <= maxLength);
};
handleChange();
editor.on('change', handleChange);
return () => editor.off('change', handleChange);
}, [editor, maxLength]);
return (
<div className={isValid ? 'valid' : 'invalid'}>
{length} / {maxLength} characters
{!isValid && <span> (exceeds limit)</span>}
</div>
);
}
Analytics Tracking
function ContentAnalytics() {
const editor = useYooptaEditor();
useEffect(() => {
const handleChange = () => {
const text = editor.getPlainText(editor.children);
// Track metrics
analytics.track('content_updated', {
characterCount: text.length,
wordCount: text.split(/\s+/).filter(Boolean).length,
timestamp: Date.now(),
});
};
editor.on('change', handleChange);
return () => editor.off('change', handleChange);
}, [editor]);
return null;
}
Preview Excerpt
function ContentExcerpt({ maxLength = 200 }) {
const editor = useYooptaEditor();
const [excerpt, setExcerpt] = useState('');
useEffect(() => {
const handleChange = () => {
const text = editor.getPlainText(editor.children);
const truncated = text.length > maxLength
? text.substring(0, maxLength) + '...'
: text;
setExcerpt(truncated);
};
handleChange();
editor.on('change', handleChange);
return () => editor.off('change', handleChange);
}, [editor, maxLength]);
return (
<div className="excerpt">
<h4>Preview</h4>
<p>{excerpt}</p>
</div>
);
}
Use Cases
- Character/Word Counting: Display document statistics
- Reading Time: Estimate how long content takes to read
- Search Indexing: Index content for search functionality
- Validation: Check content length limits
- Analytics: Track content metrics
- Plain Text Export: Download as .txt file
- Clipboard: Copy unformatted text
- Previews: Generate text excerpts
- SEO: Extract meta descriptions
- Accessibility: Provide text alternatives
What Gets Removed
The plain text extraction removes:
- ✗ All HTML tags
- ✗ Text formatting (bold, italic, etc.)
- ✗ Links (keeps link text, removes URLs)
- ✗ Images (removes entirely)
- ✗ Block structure
- ✗ Metadata (alignment, depth, etc.)
- ✗ Embeds and void elements
What’s preserved:
- ✓ Text content
- ✓ Line breaks (from block separation)
- ✓ Spacing
Since getPlainText creates HTML first then extracts text:
- May be slower for very large documents
- Creates temporary DOM elements
- Consider caching for frequently accessed values
- Use debouncing for live counters
// Debounced counter
function DebouncedCounter() {
const editor = useYooptaEditor();
const [count, setCount] = useState(0);
useEffect(() => {
const handleChange = debounce(() => {
const text = editor.getPlainText(editor.children);
setCount(text.length);
}, 300);
editor.on('change', handleChange);
return () => editor.off('change', handleChange);
}, [editor]);
return <div>{count} characters</div>;
}
See Also