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

@tpmjs/tools-html-to-markdown

v0.1.0

Published

Convert HTML to markdown using turndown

Readme

@tpmjs/tools-html-to-markdown

Convert HTML to markdown using turndown.

Installation

npm install @tpmjs/tools-html-to-markdown
# or
pnpm add @tpmjs/tools-html-to-markdown
# or
yarn add @tpmjs/tools-html-to-markdown

Usage

With Vercel AI SDK

import { htmlToMarkdownTool } from '@tpmjs/tools-html-to-markdown';
import { generateText } from 'ai';

const result = await generateText({
  model: yourModel,
  tools: {
    htmlToMarkdown: htmlToMarkdownTool,
  },
  prompt: 'Convert this HTML to markdown',
});

Direct Usage

import { htmlToMarkdownTool } from '@tpmjs/tools-html-to-markdown';

const result = await htmlToMarkdownTool.execute({
  html: '<h1>Hello World</h1><p>This is a <strong>test</strong>.</p>',
});

console.log(result.markdown);
// # Hello World
//
// This is a **test**.

console.log(result);
// {
//   markdown: '# Hello World\n\nThis is a **test**.',
//   wordCount: 6
// }

Features

  • Comprehensive Conversion - Supports headings, lists, links, images, code blocks, tables, and more
  • Customizable Output - Configure heading style and list markers
  • Word Count - Automatically counts words in the output
  • Smart Formatting - Preserves semantic meaning while creating clean markdown
  • Error Handling - Graceful error messages for invalid HTML

Parameters

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | html | string | Yes | The HTML string to convert | | options | ConversionOptions | No | Formatting options |

ConversionOptions

{
  headingStyle?: 'setext' | 'atx';      // Default: 'atx'
  bulletListMarker?: '-' | '*' | '+';   // Default: '-'
}

Heading Styles:

  • atx: Uses # prefix (e.g., # Heading)
  • setext: Uses underlines (e.g., Heading\n=======)

Returns

{
  markdown: string;    // The converted markdown
  wordCount: number;   // Number of words in the markdown
}

Examples

Basic Conversion

const result = await htmlToMarkdownTool.execute({
  html: '<h1>Title</h1><p>Paragraph text.</p>',
});

console.log(result.markdown);
// # Title
//
// Paragraph text.

console.log(result.wordCount);
// 3

Convert Links

const result = await htmlToMarkdownTool.execute({
  html: '<a href="https://example.com">Click here</a> for more info.',
});

console.log(result.markdown);
// [Click here](https://example.com) for more info.

Convert Lists

const result = await htmlToMarkdownTool.execute({
  html: `
    <ul>
      <li>First item</li>
      <li>Second item</li>
      <li>Third item</li>
    </ul>
  `,
});

console.log(result.markdown);
// - First item
// - Second item
// - Third item

Custom List Marker

const result = await htmlToMarkdownTool.execute({
  html: '<ul><li>Item 1</li><li>Item 2</li></ul>',
  options: {
    bulletListMarker: '*',
  },
});

console.log(result.markdown);
// * Item 1
// * Item 2

Setext Heading Style

const result = await htmlToMarkdownTool.execute({
  html: '<h1>Main Title</h1><h2>Subtitle</h2>',
  options: {
    headingStyle: 'setext',
  },
});

console.log(result.markdown);
// Main Title
// ==========
//
// Subtitle
// --------

Convert Tables

const result = await htmlToMarkdownTool.execute({
  html: `
    <table>
      <thead>
        <tr><th>Name</th><th>Age</th></tr>
      </thead>
      <tbody>
        <tr><td>Alice</td><td>25</td></tr>
        <tr><td>Bob</td><td>30</td></tr>
      </tbody>
    </table>
  `,
});

console.log(result.markdown);
// | Name | Age |
// | --- | --- |
// | Alice | 25 |
// | Bob | 30 |

Convert Code Blocks

const result = await htmlToMarkdownTool.execute({
  html: '<pre><code>function hello() {\n  console.log("Hello");\n}</code></pre>',
});

console.log(result.markdown);
// ```
// function hello() {
//   console.log("Hello");
// }
// ```

Convert Inline Code

const result = await htmlToMarkdownTool.execute({
  html: '<p>Use the <code>console.log()</code> function.</p>',
});

console.log(result.markdown);
// Use the `console.log()` function.

Convert Images

const result = await htmlToMarkdownTool.execute({
  html: '<img src="photo.jpg" alt="A beautiful sunset">',
});

console.log(result.markdown);
// ![A beautiful sunset](photo.jpg)

Convert Text Formatting

const result = await htmlToMarkdownTool.execute({
  html: '<p>This is <strong>bold</strong> and <em>italic</em> text.</p>',
});

console.log(result.markdown);
// This is **bold** and *italic* text.

Convert Blockquotes

const result = await htmlToMarkdownTool.execute({
  html: '<blockquote><p>This is a quote.</p></blockquote>',
});

console.log(result.markdown);
// > This is a quote.

Complex HTML

const result = await htmlToMarkdownTool.execute({
  html: `
    <article>
      <h1>Blog Post Title</h1>
      <p>Introduction paragraph with <a href="/link">a link</a>.</p>
      <h2>Section 1</h2>
      <ul>
        <li>Point one</li>
        <li>Point two</li>
      </ul>
      <h2>Section 2</h2>
      <p>More content with <strong>bold</strong> and <em>italic</em>.</p>
      <pre><code>const x = 42;</code></pre>
    </article>
  `,
});

console.log(result.markdown);
// # Blog Post Title
//
// Introduction paragraph with [a link](/link).
//
// ## Section 1
//
// - Point one
// - Point two
//
// ## Section 2
//
// More content with **bold** and *italic*.
//
// ```
// const x = 42;
// ```

console.log(result.wordCount);
// 20

Strip HTML Tags

const result = await htmlToMarkdownTool.execute({
  html: '<div><span>Just plain text</span></div>',
});

console.log(result.markdown);
// Just plain text

Supported HTML Elements

| Element | Markdown Output | |---------|-----------------| | <h1> - <h6> | # to ###### (or underlined) | | <p> | Paragraph with blank lines | | <strong>, <b> | **bold** | | <em>, <i> | *italic* | | <a> | [text](url) | | <img> | ![alt](src) | | <ul>, <ol> | Bullet or numbered lists | | <li> | List items | | <code> | `code` | | <pre> | ``` code block ``` | | <blockquote> | > quote | | <table> | Markdown tables | | <hr> | --- | | <br> | Line break |

Word Count

The word count feature:

  • Removes markdown formatting characters
  • Counts only actual words
  • Normalizes whitespace
  • Filters empty strings
const result = await htmlToMarkdownTool.execute({
  html: '<p>The **quick** brown fox.</p>',
});

console.log(result.wordCount);
// 4 (counts "The", "quick", "brown", "fox")

Error Handling

try {
  const result = await htmlToMarkdownTool.execute({
    html: null,  // Invalid input
  });
} catch (error) {
  console.error(error.message);
  // "HTML input must be a string"
}

Common Use Cases

Convert Web Scraping Results

const scrapedHtml = await fetch('https://example.com').then(r => r.text());
const result = await htmlToMarkdownTool.execute({ html: scrapedHtml });
// Now you have clean markdown for processing

Convert Rich Text Editor Output

const editorHtml = richTextEditor.getHTML();
const result = await htmlToMarkdownTool.execute({ html: editorHtml });
// Store as markdown instead of HTML

Email to Markdown

const emailHtml = getEmailBodyHtml();
const result = await htmlToMarkdownTool.execute({ html: emailHtml });
// Clean markdown representation of email

Documentation Generation

const apiDocsHtml = generateApiDocs();
const result = await htmlToMarkdownTool.execute({ html: apiDocsHtml });
// Markdown docs for GitHub/GitLab

Best Practices

  1. Sanitize First - Use @tpmjs/tools-html-sanitize before converting untrusted HTML
  2. Choose Appropriate Style - Use atx for GitHub, setext for readability
  3. Consistent Markers - Stick to one bullet list marker in your project
  4. Handle Errors - Wrap conversions in try-catch for production use
  5. Trim Output - Call .trim() on markdown if needed

Limitations

  • Complex CSS styling is lost (only semantic HTML is preserved)
  • Custom HTML elements are converted to their text content
  • Nested tables may not render perfectly
  • Some exotic HTML5 elements may not have markdown equivalents

License

MIT