snarkdown-in-react

2.0.2 • Public • Published

Snarkdown React

Snarkdown in React npm

Tiny markdown parser for React.

snarkdown-in-react is a fork of snarkdown.

Whereas snarkdown is 1kb minified and gzipped, snarkdown-in-react is a little larger, at 1.4kb (all in, no external dependencies). For that you get custom rendering and easy use in React.

I created snarkdown-in-react originally to handle the online manual in my game Head over Heels Online

Use case:

  • You want to show some markdown in your react app
  • You don't need MDX (react components inline in the markdown)
  • You don't want to inflate your bundle size
  • You may (or may not) need to render to your own, custom React components
  • You don't need to inject custom parsing

API

import {
  SnarkdownInReact,
  type CustomComponentsOption,
} from "snarkdown-in-react";

const MyComponent = () => {
  return <SnarkdownInReact markdown={myMarkdown} />;
};

const myCustomRenderers: CustomComponentsOption = {
  // default rendering for em is <em> - this example overrides it with <span class="em">
  em: ({ children }) => <span className="em">{children}</span>,

  // wrap images in a div with a click handler and some tailwind classes:
  img: ({ children, src, alt }) => (
    <div className="w-full" onClick={() => console.log("click")}>
      <img className="scale-2" src={src} alt={alt} />
    </div>
  ),
};

const MyComponentWithCustomMarkdownRendering = () => {
  return (
    <SnarkdownInReact
      markdown={myMarkdown}
      customComponents={myCustomRenderers}
    />
  );
};

// note that if your markdown is very large, you might want to consider wrapping in useMemo to avoid
// repeated parsing. For most normal use cases this will not improve performance and may make it worse,
// and to improve performance it is almost certainly better to address why your app is over-rendering
import { parse } from "snarkdown-in-react";
import { useMemo } from "react";
const MyCachedComponent = PureComponent(() => {
  return useMemo(() => parse(myMarkdown), [myMarkdown, parse]);
});

parsing paragraphs

By default, <p> is output for paragraphs. This can cause issues if you need to put block-level elements inside your markdown. To change to <div> (or any other tag) you can do:

return (
  <SnarkdownInReact
    markdown={myMarkdown}
    customComponents={{p: 'div'}}
  />
);

Like the upstream Snarkdown:

  • a dead simple [Markdown] parser.
  • has no run-time dependencies (except react itself)
  • It's designed to be as minimal as possible, for constrained use-cases where a full Markdown parser would be inappropriate.
  • passes all tests from snarkdown (well, all that still apply)
  • doesn't support tables

Unlike upstream Snarkdown:

  • supports pluggable, custom rendering
  • returns jsx that it creates directly (never creates a html string)
  • assumes you have a modern (circa 2025) workflow
  • is in typescript
  • is a little bigger, at 1.4k minified and gzipped
  • doesn't bother building to cjs or javascript, or push to any cdns. Use via the npm package repository, and typescript+es only
  • in fact, doesn't have any build whatsoever. The typescript file is the main. If you're not using typescript and want to add a build to js, feel free to raise a PR. The esbuild-powered build task in the package.json is purely to keep an eye on the size
  • tests in vitest (not mocha/chai)
  • doesn't support reference links
  • doesn't let through raw html in markdown
  • thanks to React (and not supporting html), is somewhat xss-safe, since raw html is never concatenated and written out (I don't use .dangerouslySetInnerHtml).

Parsing differences:

double line breaks like this:

some text

some other text

is parsed to <p>s:

<p className="paragraph">some text</p>
<p className="paragraph">some other text</p>

this is unlike snarkdown which uses <br />:

some text<br />some other text

Package Sidebar

Install

npm i snarkdown-in-react

Weekly Downloads

8

Version

2.0.2

License

MIT

Unpacked Size

62.4 kB

Total Files

8

Last publish

Collaborators

  • jimhigson