This content originally appeared on DEV Community and was authored by Shaishav Patel
Most Lorem Ipsum generators use an npm package that's overkill for what is essentially random word sampling. Here's how the Lorem Ipsum Generator is built — zero dependencies, three output modes, copy-to-clipboard.
The Word Pool
Classic Lorem Ipsum comes from Cicero's "de Finibus Bonorum et Malorum". The tool uses the canonical word set:
const WORDS = [
"lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit",
"sed", "do", "eiusmod", "tempor", "incididunt", "ut", "labore", "et", "dolore",
"magna", "aliqua", "ut", "enim", "ad", "minim", "veniam", "quis", "nostrud",
"exercitation", "ullamco", "laboris", "nisi", "ut", "aliquip", "ex", "ea",
"commodo", "consequat", "duis", "aute", "irure", "dolor", "in", "reprehenderit",
"in", "voluptate", "velit", "esse", "cillum", "dolore", "eu", "fugiat", "nulla",
"pariatur", "excepteur", "sint", "occaecat", "cupidatat", "non", "proident",
"sunt", "in", "culpa", "qui", "officia", "deserunt", "mollit", "anim", "id",
"est", "laborum"
];
69 words. Repeated sampling with Math.random() produces varied output without exhausting the pool.
State
type OutputType = "paragraphs" | "sentences" | "words";
const [count, setCount] = useState(3);
const [type, setType] = useState<OutputType>("paragraphs");
const [text, setText] = useState("");
const [copied, setCopied] = useState(false);
count is the number of units to generate (3 paragraphs, 5 sentences, 100 words, etc.).
Sentence Generation
A sentence is 5–14 random words, first word capitalized, ending with a period:
function generateSentence(): string {
const length = Math.floor(Math.random() * 10) + 5; // 5–14 words
let sentence = "";
for (let i = 0; i < length; i++) {
const word = WORDS[Math.floor(Math.random() * WORDS.length)];
const isFirst = i === 0;
const isLast = i === length - 1;
sentence += (isFirst
? word.charAt(0).toUpperCase() + word.slice(1)
: word
) + (isLast ? "." : " ");
}
return sentence;
}
Result: "Lorem ipsum dolor sit amet consectetur adipiscing elit sed do."
Paragraph Generation
A paragraph is 3–7 sentences joined with spaces:
function generateParagraph(): string {
const sentenceCount = Math.floor(Math.random() * 5) + 3; // 3–7 sentences
let paragraph = "";
for (let i = 0; i < sentenceCount; i++) {
paragraph += generateSentence() + " ";
}
return paragraph.trim();
}
The Generate Function
Three modes, one function:
function generate() {
let result = "";
if (type === "words") {
const words: string[] = [];
for (let i = 0; i < count; i++) {
words.push(WORDS[Math.floor(Math.random() * WORDS.length)]);
}
result = words.join(" ");
} else if (type === "sentences") {
for (let i = 0; i < count; i++) {
result += generateSentence() + " ";
}
} else { // paragraphs
for (let i = 0; i < count; i++) {
result += generateParagraph() + "\n\n";
}
}
setText(result.trim());
setCopied(false);
}
Paragraphs are separated with \n\n — when displayed in a <textarea> or <pre>, this renders as blank lines between them.
Auto-Generate on Mount
Generate text immediately when the component first renders so users see output without clicking anything:
// Generate initial text — runs once on mount
if (!text) generate();
This is intentionally simple (not inside a useEffect) since generate is a pure function with no side effects and we only need it once. An alternative is:
useEffect(() => {
generate();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // intentional empty deps — generate once on mount
Regenerate on Setting Change
When the user changes type or count, regenerate automatically:
useEffect(() => {
generate();
}, [type, count]);
No "Generate" button required — the output updates as you adjust the sliders.
Copy to Clipboard
async function copyToClipboard() {
try {
await navigator.clipboard.writeText(text);
} catch {
// Fallback for older browsers
const el = document.createElement("textarea");
el.value = text;
document.body.appendChild(el);
el.select();
document.execCommand("copy");
document.body.removeChild(el);
}
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}
Button toggles between "Copy" and "Copied!" for 2 seconds.
The UI
return (
<div className="mx-auto max-w-4xl space-y-8">
{/* Controls */}
<div className="flex flex-col gap-6 sm:flex-row sm:items-end">
{/* Output type */}
<div className="space-y-2">
<label className="text-sm font-medium text-zinc-500">Type</label>
<div className="flex gap-2">
{(["paragraphs", "sentences", "words"] as OutputType[]).map(t => (
<button
key={t}
onClick={() => setType(t)}
className={`px-4 py-2 rounded-lg text-sm font-medium capitalize transition-colors ${
type === t
? "bg-violet-600 text-white"
: "bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400"
}`}
>
{t}
</button>
))}
</div>
</div>
{/* Count slider */}
<div className="space-y-2 flex-1">
<label className="text-sm font-medium text-zinc-500">
Count: {count}
</label>
<input
type="range"
min={1}
max={type === "words" ? 200 : type === "sentences" ? 20 : 10}
value={count}
onChange={e => setCount(Number(e.target.value))}
className="w-full"
/>
</div>
{/* Regenerate button */}
<button onClick={generate} className="flex items-center gap-2 ...">
<RefreshCw className="h-4 w-4" /> Regenerate
</button>
</div>
{/* Output */}
<div className="relative">
<textarea
value={text}
readOnly
rows={12}
className="w-full font-mono text-sm ..."
/>
<button
onClick={copyToClipboard}
className="absolute top-3 right-3 ..."
>
{copied ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
{copied ? "Copied!" : "Copy"}
</button>
</div>
</div>
);
The Full Picture
The whole component is ~110 lines. No npm package, no API call, no seed-based deterministic output (which is unnecessary for placeholder text). Random sampling from a 69-word pool is sufficient — users want varied placeholder text, not reproducible results.
The max range for the slider scales by type: 200 words, 20 sentences, 10 paragraphs. These limits match what's practical — 10 paragraphs is already ~500 words of placeholder text.
Try it: Lorem Ipsum Generator → ultimatetools.io
This content originally appeared on DEV Community and was authored by Shaishav Patel
Shaishav Patel | Sciencx (2026-04-07T01:38:16+00:00) Building a Lorem Ipsum Generator in React — No Library, Custom Word Pool, Paragraphs/Sentences/Words. Retrieved from https://www.scien.cx/2026/04/07/building-a-lorem-ipsum-generator-in-react-no-library-custom-word-pool-paragraphs-sentences-words/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.