DEV Community

Cover image for The libraries I actually reach for — and the rule I use to decide
Dimon
Dimon

Posted on • Originally published at dimonb19a.hashnode.dev

The libraries I actually reach for — and the rule I use to decide

My last two posts were about not installing things the browser already gives you — native elements over libraries. But that's only half a rule, and leaving it there would be dishonest, because I install plenty of libraries. The point was never "zero dependencies." It was "no redundant ones."

So here's the other half: the libraries I reach for without a second thought, and the simple rule I use to decide.


The rule

A library earns a place in my project when:

  1. It solves something the platform genuinely doesn't — or doesn't do safely.
  2. It stays focused: one job, not a framework trying to take over the app.
  3. It's something I'd get wrong, or burn weeks on, if I built it myself. If the browser already ships it, I skip it (that was posts 1 and 2). If it fails one of those three, I skip it too. What's left is worth installing — grouped here by the kind of hard problem each one solves.

"Don't DIY this — you'll get it wrong"

sanitize-html — safe HTML. The moment you render HTML you didn't write — user comments, markdown, anything from an API — you're one mistake away from an XSS hole. Sanitizing HTML correctly is a security discipline, not a weekend regex. The platform ships no sanitizer, and "I'll just strip <script> tags" is exactly how people get breached. I never roll this myself.

zod — runtime validation. TypeScript is great, but it vanishes at runtime. The moment data crosses a boundary you don't control — an API response, a form submission, an LLM's output — TypeScript has already stopped helping. zod validates the actual value at the moment it arrives:

const User = z.object({ name: z.string(), age: z.number() });
const result = User.safeParse(await response.json());
if (!result.success) {
  // handle bad data here — instead of crashing three functions
}
Enter fullscreen mode Exit fullscreen mode

TypeScript checks at compile time. zod checks at the time that actually matters.


"Deceptively hard math"

Floating UI — positioning. I mentioned this last post. The browser now gives you the behavior of a popover for free (top layer, light-dismiss, Esc). What it doesn't reliably give you yet is the placement — anchoring a panel to its trigger and flipping it when it would fall off a screen edge. CSS anchor positioning is landing for this, but support is still uneven, so for now I let Floating UI do the collision math. "Position a box near another box" sounds trivial until you handle every viewport edge, scroll container, and overflow. It isn't trivial. This is a rabbit hole worth paying someone else to have already fallen down.


"Solved and tedious — just use the good one"

marked — markdown to HTML. A markdown parser is a real project with a real spec. There's a fast, battle-tested one. I use it and move on — then hand its output straight to sanitize-html, because parsing and sanitizing are two different jobs and you need both:

import { marked } from 'marked';
import sanitizeHtml from 'sanitize-html';

const safe = sanitizeHtml(marked.parse(userMarkdown));
Enter fullscreen mode Exit fullscreen mode

Lucide — icons. A consistent, maintained, open-source icon set beats hand-drawing SVGs or gluing together a mismatched pile from five different sources. Icons are a solved problem; consistency is the hard part, and that's exactly what a good icon set gives you.

Bonus — fast-average-color. The platonic example of a library worth installing: it does one tiny thing — pull the dominant color out of an image — in a few kilobytes. No framework, no lock-in, no ambition beyond its single job. That's the shape of a dependency I never regret.


The line

Here's what I want you to notice: the judgment is identical in both directions. The same instinct that installs Floating UI for positioning is the one that refuses a modal library because <dialog> already exists. One rule, applied both ways — install for the hard problem the platform doesn't own, skip for the thing it already ships.

The question was never "library or no library." It's "is this a hard problem the platform doesn't solve — safely, and on its own?" Answer that honestly each time, and your dependency list stays short and you stop reinventing wheels you'd only build worse.

That's the whole series in one line: use the platform for what it's good at, and pay for help only where it genuinely earns it.

Top comments (0)