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

vcard-ts

v2.0.0

Published

A simple, modern TypeScript library for VCard 3.0 (RFC 2426) with browser and Node.js support

Downloads

841

Readme

vcard-ts

A simple, modern TypeScript library for creating VCard 3.0 (RFC 2426) formatted strings. Zero dependencies, fully typed, and works in both browser and Node.js environments.

Features

  • RFC 2426 Compliant - Strictly follows the VCard 3.0 specification
  • 🎯 Simple API - No complex builder patterns, just plain objects
  • 🔒 Fully Typed - Complete TypeScript type definitions
  • 📦 Zero Dependencies - Lightweight and fast
  • 🌐 Universal - Works in browser and Node.js
  • Modern - ESM + CommonJS, tree-shakeable
  • 🧪 Well Tested - Comprehensive test coverage
  • 🍏 iOS URL Labels - Supports multiple URLs with human-friendly labels in Apple Contacts

Why VCard 3.0?

While VCard 4.0 exists, as of right now 3.0 remains the most widely supported format.

Installation

npm install vcard-ts

Usage

Basic Example

import { formatVCard, type VCard } from 'vcard-ts';

const vcard: VCard = {
  version: '3.0',
  formattedName: 'John Doe',
  name: {
    familyName: 'Doe',
    givenName: 'John',
  },
};

const vcardString = formatVCard(vcard);
console.log(vcardString);

Output:

BEGIN:VCARD
VERSION:3.0
FN:John Doe
N:Doe;John;;;
END:VCARD

Character Set Support

Some legacy vCard consumers expect or require a CHARSET=... parameter on text properties.

Note: CHARSET is not defined in RFC 2426 itself; this library supports it as a legacy interoperability option.

By default, the formatter assumes UTF-8 and does not emit any CHARSET parameters.

import { formatVCard, type VCard } from 'vcard-ts';

const vcard: VCard = {
  version: '3.0',
  formattedName: 'José García',
  name: {
    familyName: 'García',
    givenName: 'José',
  },
};

const vcardString = formatVCard(vcard);
console.log(vcardString);

Output:

BEGIN:VCARD
VERSION:3.0
FN:José García
N:García;José;;;
END:VCARD

If you need legacy interoperability, you can explicitly declare a charset via formatter options:

const vcardString = formatVCard(vcard, { charset: 'ISO-8859-1' });

Photo/Logo/Sound

You can include media either as a URI reference or inline base64 data:

// URI Reference
const vcardWithPhoto: VCard = {
  version: '3.0',
  formattedName: 'Jane Smith',
  name: { familyName: 'Smith', givenName: 'Jane' },
  photo: {
    uri: 'https://example.com/photo.jpg',
    mediaType: 'JPEG',
  },
};

// Inline Base64 (must be pre-encoded)
const vcardWithInlinePhoto: VCard = {
  version: '3.0',
  formattedName: 'Jane Smith',
  name: { familyName: 'Smith', givenName: 'Jane' },
  photo: {
    value: 'base64EncodedDataHere...',
    encoding: 'b',
    mediaType: 'JPEG',
  },
};

Android / Google Contacts Import Note

Some Android/Google Contacts imports can mis-parse folded lines (RFC 2426 line folding with CRLF + space), especially for structured properties like ADR. If you see parts of the address appear as a name suffix or the address disappears, disable folding:

import { formatVCard, type VCard } from 'vcard-ts';

const vcard: VCard = {
  version: '3.0',
  formattedName: 'Jane Smith',
  name: { familyName: 'Smith', givenName: 'Jane' },
  addresses: [
    {
      street: '100 Tech Plaza',
      locality: 'San Francisco',
      region: 'CA',
      postalCode: '94105',
      country: 'United States of America',
      types: ['work'],
    },
  ],
};

// Keeps ADR on a single line (no folded continuations)
const vcardString = formatVCard(vcard, { foldLines: false });

Special Characters

The library automatically escapes special characters according to RFC 2426:

const vcard: VCard = {
  version: '3.0',
  formattedName: 'Test; User, with\\special chars',
  name: {
    familyName: 'User',
    givenName: 'Test',
  },
  note: 'Line 1\nLine 2',
};

// Special characters are automatically escaped:
// ; -> \;
// , -> \,
// \ -> \\
// newline -> \n

Multiple URLs + iOS Labels

Many consumers (including iOS Contacts) support multiple URL entries but won’t display a meaningful label unless you use Apple’s extension fields.

This library supports that via urls, emitting itemN.URL + itemN.X-ABLabel. The item1., item2., etc. prefix is the vCard group syntax: it scopes multiple related lines under the same group name. So that item1.X-ABLabel can be associated with item1.URL.

The X-ABLabel property is an Apple-specific X- extension used by iOS Contacts to display a human-friendly label for the preceding itemN.URL field (e.g. “LinkedIn”, “Website”). This is usually not supported on Android.

import { formatVCard, type VCard } from 'vcard-ts';

const vcard: VCard = {
  version: '3.0',
  formattedName: 'Michael Wolz',
  name: { familyName: 'Wolz', givenName: 'Michael' },
  urls: [
    { value: 'https://www.linkedin.com/in/michaelwolz', type: 'LinkedIn' },
    { value: 'https://michaelwolz.de', type: 'Website' },
  ],
};

console.log(formatVCard(vcard));

Output (excerpt):

item1.URL:https://www.linkedin.com/in/michaelwolz
item1.X-ABLabel:LinkedIn
item2.URL:https://michaelwolz.de
item2.X-ABLabel:Website

Notes:

  • iOS: shows both URLs and the labels.
  • Android: typically shows both URLs, but often ignores the X-ABLabel labels.
  • vCard 4.0 supports richer, standardized URL typing, but vCard 3.0 tends to have broader real-world compatibility; this is a practical workaround.

API Reference

Type: VCard

The main VCard type representing a complete vCard object.

Required Fields:

  • version: '3.0' - Must be "3.0"
  • formattedName: string - Formatted name (FN property)
  • name: Name - Structured name (N property)

Optional Fields:

See the TypeScript definitions for the complete list of optional fields including:

  • Identification: nickname, photo, birthday
  • Delivery Addressing: addresses, labels
  • Telecommunications: phones, emails, mailer
  • Geographical: timezone, geo
  • Organizational: title, role, logo, agent, organization
  • Explanatory: categories, note, productId, revision, sortString, sound, url, uid
  • URLs: url (single) and urls (multiple + optional iOS labels)
  • Security: class, key

Function: formatVCard

function formatVCard(vcard: VCard, options?: { charset?: 'UTF-8' | 'ISO-8859-1' | 'US-ASCII' }): string;

// You can also disable RFC line folding for Android/Google Contacts compatibility:
// formatVCard(vcard, { foldLines: false })

Converts a VCard object into an RFC 2426 compliant VCard 3.0 string.

Parameters:

  • vcard: VCard - The VCard object to format
  • options?: { charset?: 'UTF-8' | 'ISO-8859-1' | 'US-ASCII'; fold?: boolean } - Optional formatting options
    • charset - (Legacy) Charset to declare via CHARSET parameters on text properties. If omitted, UTF-8 is assumed and no CHARSET is emitted.
    • foldLines - Whether to apply RFC 2426 line folding (75 characters, CRLF + space). Default: true. Set to false if Android/Google Contacts mis-parses folded ADR lines.

Returns:

  • string - RFC 2426 compliant VCard string with CRLF line endings

Features:

  • Automatic text escaping for special characters
  • Line folding for lines longer than 75 characters
  • CHARSET parameters on text properties (legacy; only emitted when explicitly requested)
  • Proper formatting of all VCard 3.0 properties
  • Date/DateTime formatting

Development

# Install dependencies
npm install

# Run tests
npm test

# Run tests with coverage
npm run test:coverage

# Build the library
npm run build

# Type check
npm run typecheck

# Lint code
npm run lint

# Format code
npm run format

Browser Support

Works in all modern browsers and Node.js 16+.

Contributing

Contributions are welcome! Please ensure all tests pass and follow the existing code style.

References