JSPM

citestyle

1.0.1
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 1
  • Score
    100M100P100Q53415F
  • License MIT

Citation formatting for the web — compile CSL styles into lightweight JavaScript. Structured output (HTML, text, parts, links) from any of 10,000+ citation styles in ~9-13KB.

Package Exports

  • citestyle
  • citestyle/styles/ama
  • citestyle/styles/apa
  • citestyle/styles/chicago-author-date
  • citestyle/styles/harvard
  • citestyle/styles/ieee
  • citestyle/styles/mla
  • citestyle/styles/nature
  • citestyle/styles/science
  • citestyle/styles/vancouver

Readme

Citestyle

Citation formatting for the web. Format references in any of 10,000+ citation styles with structured, web-native output — semantic HTML, decomposed parts, extracted links, and plain text — all from a ~9KB runtime.

npm install citestyle
import { format } from 'citestyle'
import * as apa from 'citestyle/styles/apa'

const entry = format(apa, {
  type: 'article-journal',
  title: 'Structured citation output for the web',
  author: [{ family: 'Smith', given: 'J. A.' }, { family: 'Doe', given: 'Jane' }],
  issued: { 'date-parts': [[2024]] },
  'container-title': 'Journal of Digital Publishing',
  volume: '8',
  page: '123-145',
  DOI: '10.1234/jdp.2024.001'
})

entry.text   // Smith, J. A., & Doe, J. (2024). Structured citation output ...
entry.html   // Semantic HTML with per-field CSS classes and clickable DOI links
entry.parts  // { authors, year, title, container, volume, pages, doi, ... }
entry.links  // { doi: 'https://doi.org/10.1234/jdp.2024.001' }

One function call, four representations. Every formatted entry gives you:

  • html — Semantic HTML where every field (.csl-author, .csl-title, .csl-container) is a real element you can style with CSS. DOIs and URLs become clickable links automatically.
  • text — Clean plain text for copy-paste, clipboard, and accessibility.
  • parts — Decomposed fields (authors, year, title, container, doi, …) for building publication cards, research profiles, CVs, or any custom layout.
  • links — Extracted DOIs, URLs, and PDFs for linking without post-processing.
<!-- entry.html -->
<span class="csl-entry">
  <span class="csl-author">Smith, J. A., &amp; Doe, J.</span>
  <span class="csl-year">(2024)</span>.
  <span class="csl-title">Structured citation output for the web</span>.
  <i class="csl-container">Journal of Digital Publishing</i>,
  <span class="csl-volume">8</span>, <span class="csl-pages">123–145</span>.
  <a class="csl-doi" href="https://doi.org/10.1234/jdp.2024.001">https://doi.org/…</a>
</span>

Existing citation processors return flat strings — you get a blob of text and have to regex out the parts. Citestyle gives you structure from the start.

How it works

Most citation formatters ship a runtime interpreter that parses style definitions on every page load. Citestyle takes a different approach: it compiles Citation Style Language (CSL) definitions into optimized JavaScript at build time. The style becomes the code — no interpreter, no XML parsing at runtime.

The same approach behind Tailwind CSS (utility classes → optimized CSS) and GraphQL codegen (schemas → typed runtime code), applied to citation formatting.

Standard styles. The compiler reads standard .csl files from the official CSL repository — the same 10,000+ community-maintained styles that Zotero, Mendeley, and every other reference manager uses. Your institution's custom style, an obscure journal format — if it's valid CSL, it compiles.

Tree-shaking at two levels. Each compiled style is a standalone ES module. Import APA and not MLA → MLA is never in your bundle. But it goes deeper: each compiled style only imports the specific core helpers it uses. A style with no date formatting doesn't pull in formatDate. An interpreter can't do this — it must ship the entire formatting engine because it doesn't know which style will be loaded at runtime. The shared runtime is ~6-8KB; each compiled style adds ~3-5KB. Your first style ships in ~9-13KB total.

Locale terms inlined as constants. An interpreter loads locale XML (~20KB) as a separate file at runtime — month names, ordinal suffixes, "et al.", "and", punctuation rules. Citestyle resolves all locale terms at compile time and inlines them as string constants. No runtime locale loading, no extra file to fetch. A compiled style for en-US has the terms literally in the code.

Pure functions. format(style, item) has no side effects, no global state, no initialization step. Same input, same output. Works in browsers, Node, edge functions, workers, SSR — anywhere JavaScript runs. The registry is the only stateful piece, and it's opt-in for when you need cross-reference features.

Null safety from group suppression. Real-world citation data is messy — missing DOIs, no volume number, no editor. CSL handles this through group suppression: if every variable a group references is empty, the entire group — including its delimiters and surrounding punctuation — is suppressed. No dangling commas, no orphaned parentheses, no "undefined" in output. The compiler emits the right conditional structure so this works automatically for any data shape.

Debuggable output. The compiled JavaScript is readable. When formatting looks wrong, you can open the compiled file and trace exactly which CSL rule produced which output. Stack traces point to the actual formatting logic, not into an XML interpreter.

Quick start

Format one reference

import { format } from 'citestyle'
import * as apa from 'citestyle/styles/apa'

const entry = format(apa, item)
// → { html, text, parts, links }

Format a list

Sort, number, and format multiple items in one call:

import { formatAll } from 'citestyle'
import * as ieee from 'citestyle/styles/ieee'

const entries = formatAll(ieee, items)
// Sorted per IEEE rules, citation numbers assigned
// → [{ html, text, parts, links }, ...]

Format inline citations

import { formatCitation } from 'citestyle'
import * as apa from 'citestyle/styles/apa'

const cite = formatCitation(apa, [
  { item: smithItem, locator: '42', label: 'page' }
])
// → { html: '(Smith, 2024, p. 42)', text: '(Smith, 2024, p. 42)' }

Documents with cross-references

When citations interact across a document — year-suffix disambiguation (2024a, 2024b), name disambiguation, cite collapsing — use a registry:

import { createRegistry } from 'citestyle'
import * as apa from 'citestyle/styles/apa'

const registry = createRegistry(apa)
registry.addItems(references)

const entries = registry.getBibliography()   // sorted, disambiguated
const cite = registry.cite([{ id: 'smith2024' }, { id: 'jones2023' }])

The registry handles year-suffix assignment, name disambiguation (5 rules), bibliography sorting, citation numbering for numeric styles, cite collapsing ([1-3] instead of [1, 2, 3]), and subsequent-author-substitute. When you don't need these features, format() and formatAll() are simpler.

Import from BibTeX

import { parseBibtex, format } from 'citestyle'
import * as apa from 'citestyle/styles/apa'

const items = parseBibtex(bibtexString)
const entry = format(apa, items[0])

Copy citation buttons

The separate text and html outputs map directly to the Clipboard API — paste into Word or Google Docs with formatting intact:

import { format, exportBibtex } from 'citestyle'
import * as apa from 'citestyle/styles/apa'

const entry = format(apa, item)

// Copy as rich text (pastes with italic titles, clickable DOIs)
navigator.clipboard.write([new ClipboardItem({
  'text/html': new Blob([entry.html], { type: 'text/html' }),
  'text/plain': new Blob([entry.text], { type: 'text/plain' }),
})])

// Copy as BibTeX
navigator.clipboard.writeText(exportBibtex([item]))

Pre-compiled styles

Nine widely used styles ship pre-compiled:

import * as apa from 'citestyle/styles/apa'                    // APA 7th edition
import * as mla from 'citestyle/styles/mla'                    // MLA 9th edition
import * as chicago from 'citestyle/styles/chicago-author-date' // Chicago 17th (author-date)
import * as ieee from 'citestyle/styles/ieee'                  // IEEE
import * as vancouver from 'citestyle/styles/vancouver'        // Vancouver
import * as harvard from 'citestyle/styles/harvard'            // Harvard (Cite Them Right)
import * as ama from 'citestyle/styles/ama'                    // AMA 11th edition
import * as nature from 'citestyle/styles/nature'              // Nature
import * as science from 'citestyle/styles/science'            // Science (AAAS)

Need a different style? Compile any .csl file:

npm install -D @citestyle/compiler
npx citestyle compile chicago-fullnote-bibliography.csl -o chicago-notes.js
import { format } from 'citestyle'
import * as chicagoNotes from './chicago-notes.js'
const entry = format(chicagoNotes, item)

Testing

Citestyle is tested against the official CSL test suite — 66 fixtures covering the spec's formatting constructs (names, dates, conditionals, groups, sorting, text-case, disambiguation, collapsing). Beyond the test suite, 44 real-world styles have been compiled and stress-tested against reference data, spanning disciplines from psychology (APA) to law (Bluebook) to medicine (Vancouver, BMJ, AMA, PLOS) to chemistry (ACS) to German (DGPs) and Portuguese (ABNT) academic conventions.

420 automated tests cover the full API surface: the compiler, the core formatting engine, the citation registry, and the BibTeX and RIS parsers.

CSL spec coverage is comprehensive for web use cases — the complete rendering model (text, macros, conditionals, groups with suppression, names with et-al and particles, dates with ranges and seasons, numbers, labels, formatting, affixes, text-case with nocase protection, sorting, page ranges), plus cross-reference features (year-suffix disambiguation, name disambiguation with 5 rules, cite collapsing, subsequent-author substitute). Footnote-centric features (ibid, subsequent position) are deferred — they target print and word-processor workflows, not the web.

How it compares

citeproc-js citeproc-rs Citation.js Citestyle
Architecture Runtime interpreter WASM interpreter Runtime interpreter Build-time compiler
Bundle ~120KB + locale XML ~200KB+ WASM ~50KB + deps ~9-13KB
Output Flat string Flat string Flat string HTML + text + parts + links
Auto-linking No No No DOIs and URLs
CSS classes No No No Per-field
Tree-shakable No No Partially Yes
TypeScript No N/A Partial Full

Packages

citestyle bundles the common use case: core runtime, registry, pre-compiled styles, and BibTeX parsing. For finer control, install scoped packages directly:

Package What it does When to install separately
@citestyle/core Shared formatting runtime (~6-8KB) Building a custom formatter on the low-level API
@citestyle/registry Citation state (~5-8KB) Need the registry without BibTeX parsing
@citestyle/styles 9 pre-compiled styles (~3-5KB each) Only need styles + core, nothing else
@citestyle/bibtex BibTeX ↔ CSL-JSON Only need BibTeX conversion
@citestyle/ris RIS ↔ CSL-JSON Working with PubMed/RIS data
@citestyle/compiler CSL XML → JS compiler Compiling custom .csl files
@citestyle/types TypeScript type definitions Type-only imports for TS projects

Architecture

┌─────────────────────────────────────────────────────┐
│                    BUILD TIME                        │
│                                                     │
│  apa.csl ──→ Citestyle Compiler ──→ apa.js (~3-5KB) │
│  Locale terms resolved and inlined as constants     │
└─────────────────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────┐
│                     RUNTIME                         │
│                                                     │
│  @citestyle/core (~6-8KB)                           │
│  Names · dates · text-case · numbers · HTML         │
│       ▲                       ▲                     │
│       │                       │                     │
│  Compiled Style          Registry                   │
│  (imports core)    (year-suffix, sort)               │
│       │                       │                     │
│  CSL-JSON ──→ { html, text, parts, links }          │
└─────────────────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────┐
│                    I/O LAYER                         │
│                                                     │
│  @citestyle/bibtex          @citestyle/ris          │
│  BibTeX ↔ CSL-JSON          RIS ↔ CSL-JSON          │
└─────────────────────────────────────────────────────┘

License

MIT