npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

smartquotify

v1.1.3

Published

Convert straight quotes to smart/curly quotes — built for legal text, works everywhere

Readme

smartquotify

npm license

Convert straight quotes to smart/curly quotes. Zero dependencies. TypeScript-first. Built for legal text, works everywhere.

Lawyers hate straight quotes, but LLMs and most legal tech output them everywhere. smartquotify fixes both display and input.

Install

npm install smartquotify

What It Converts

| Input | Output | Rule | |-------|--------|------| | "hello" | “hello” | Double quotes | | 'world' | ‘world’ | Single quotes | | don't | don’t | Apostrophes | | '90s | ’90s | Abbreviated years | | the '604 patent | the ’604 patent | Patent shorthand | | 6'5" | 6′5″ | Prime marks | | O'Brien | O’Brien | Names | | (the "Seller") | (the “Seller”) | Contract terms |

Usage

Core (any JS/TS)

import { smartquotify } from 'smartquotify'

smartquotify('"Don\'t stop"')
// → “Don’t stop”

smartquotify('the \'604 patent')
// → the ’604 patent

smartquotify('6\'2"')
// → 6′2″

HTML Mode

Protects tag attributes and comments from conversion. All visible text (including inside <code> and <pre>) gets smart quotes.

smartquotify('<a href="url">"click"</a>', { html: true })
// → <a href="url">"click"</a>

smartquotify('<em>"The court held . . . that"</em>', { html: true })
// → <em>"The court held . . . that"</em>

Markdown Mode

Skips fenced code blocks, inline code, and link URLs. Link text still gets converted.

smartquotify('He said "hello" and `"code"` here.', { markdown: true })
// → He said "hello" and `"code"` here.

smartquotify('["click here"](http://example.com)', { markdown: true })
// → ["click here"](http://example.com)

Both flags can be combined: { html: true, markdown: true }.

Input Enhancement (any framework)

Attach to any <input>, <textarea>, or contenteditable element. Users type straight quotes, see smart quotes. No cursor jumping.

import { smartquotifyInput } from 'smartquotify'

const textarea = document.querySelector('textarea')
const cleanup = smartquotifyInput(textarea)

// Later, detach:
cleanup()

React (smartquotify/react)

import { useSmartQuotify, SmartText } from 'smartquotify/react'

// Hook for controlled inputs
function ChatInput() {
  const { value, onChange, ref } = useSmartQuotify('')
  return <textarea ref={ref} value={value} onChange={onChange} />
}

// Component for displaying LLM output
function Response({ text }: { text: string }) {
  return <SmartText as="p">{text}</SmartText>
}

Legal-Specific Edge Cases

This library is specifically designed for legal text. It correctly handles patterns that general-purpose smart quote libraries get wrong:

  • Patent shorthand: the '604 patentthe ’604 patent
  • Contract defined terms: (the "Seller")(the “Seller”)
  • Em dash context: the court—"in its discretion"—ruledthe court—“in its discretion”—ruled
  • Legal ellipses: "The court held . . . that"“The court held . . . that”
  • Bracketed edits: "[T]he defendant argued"“[T]he defendant argued”
  • Measurements in evidence: the 5'10" suspectthe 5′10″ suspect

API

smartquotify(text, options?)

Pure string transform. Returns a new string with smart quotes.

Options:

  • primes (boolean, default true) — Convert measurement marks to prime characters
  • html (boolean, default false) — Skip HTML tag syntax and comments; converts all visible text
  • markdown (boolean, default false) — Skip code blocks, inline code, and link URLs; converts link text

smartquotifyInput(element, options?)

Attaches live smart-quote conversion to an input element. Returns a cleanup function.

Works with <input>, <textarea>, and contenteditable elements.

useSmartQuotify(initialValue?, options?) (React)

Hook for controlled inputs. Returns { value, onChange, ref }.

<SmartText> (React)

Memoized display component. Props:

  • as — HTML element to render (default: 'span')
  • options — smartquotify options
  • children — string to convert

Design decisions

Deterministic, no LLM. Smart quote conversion is fully rule-based — it doesn't need a language model. Every input produces the same output, every time. This makes it safe for real-time input enhancement with zero latency and no API cost.

Legal text first. General-purpose smart quote libraries get legal patterns wrong: patent shorthand ('604), contract defined terms ("Seller"), measurement marks in evidence (6'2"). smartquotify handles these correctly because it was built for legal writing from the start.

Zero dependencies. The core library has no runtime dependencies. The React bindings use React as a peer dependency. Nothing else.

Input enhancement built in. Most smart quote libraries only transform static strings. smartquotify also attaches to live <input>, <textarea>, and contenteditable elements — users type straight quotes and see smart quotes, with no cursor jumping.

Development

npm install
npm test          # 74 tests
npm run typecheck
npm run build     # ESM + CJS + .d.ts

License

Apache-2.0