react-marksome

Lightweight, flexible and readable labels in React using a subset of markdown

Usage no npm install needed!

<script type="module">
  import reactMarksome from 'https://cdn.skypack.dev/react-marksome';
</script>

README

react-marksome

npm npm bundle size

Parses some markdown, builds a tree of segments and renders them in React.

It was designed for adding basic support for styling and links to singleline strings.

See Rationale for more info.

Quick start

Install:

npm i react-marksome

Import and render the Marksome component:

import { Marksome } from 'react-marksome';

function Demo() {
  const text =
    'The *quick* *brown* **fox** jumps over the *lazy* **dog**. [Wikipedia][1]';

  const references: References = {
    '1':
      'https://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog',
  };

  return <Marksome text={text} references={references} />;
}

renders the following line:

The quick brown fox jumps over the lazy dog. Wikipedia

For more examples, see the stories together with related fixtures.

API

Marksome component

React component that parses and renders a subset of markdown.

It expects the markdown text to be provided via a text prop, which then is combined with reference links ([label][reference]) defined under the references prop.

Props

type MarksomeProps = HTMLAttributes<HTMLSpanElement> & {
  text: string;
  references?: References;
};

type References = Record<string, string | ReferenceRenderFunction>;

type ReferenceRenderFunction = (children: ReactNode) => ReactElement;

Basic usage

See Quick start.

Custom components

One can actually render custom components in the place of reference links by providing a render function instead of link url:

function CustomComponentsDemo() {
  const text = 'The following is an actual button: [*Howdie*][greeting-button]';

  const references: References = {
    'greeting-button': (children) => (
      <button
        onClick={() => {
          alert('Hello!');
        }}
      >
        {children}
      </button>
    ),
  };

  return <Marksome text={text} references={references} />;
}

Rationale

The current subset of markdown that is supported is:

  • **strong text**
  • *emphasized text*
  • [link description][reference]

By restricting ourselves to only support some markdown we're able to:

  • build a light package (bundlephobia)
  • that provides a flexible, readable and condensed format for singleline pieces of text

Additionally, we build out a tree of segments instead of simply using string replacement mostly for extensibility and configuratility, like being able to render segments with custom React components.

All of the above means that users don't need to worry about escaping the text since:

  • it relies on regular React components instead of injecting HTML via dangerouslySetInnerHTML
  • the only way to inject a link is via a separate references object.

Supported browsers

The following browserslist is supported without the need of any polyfills:

>0.25% or last 2 major versions and supports es6-module

caniuse-lite db date: 15/02/2020

  • and_chr 87
  • and_ff 83
  • and_qq 10.4
  • android 81
  • chrome 87
  • chrome 86
  • chrome 85
  • edge 87
  • edge 86
  • firefox 84
  • firefox 83
  • ios_saf 14.0-14.3
  • ios_saf 13.4-13.7
  • ios_saf 13.3
  • ios_saf 13.2
  • ios_saf 13.0-13.1
  • ios_saf 12.2-12.4
  • opera 72
  • opera 71
  • safari 14
  • safari 13.1
  • safari 13
  • samsung 13.0
  • samsung 12.0

Alternatives

If you're looking for wider markdown support:

  • snarkdown for lightweight Markdown parser that returns plain HTML string
  • markdown-to-jsx for a lot configurability and extensibility

Commands

This project was bootstrapped with TSDX. Check its docs for more info on the commands.

Storybook

npm run storybook

This loads the stories from ./stories.

Testing

Jest tests are set up to run with npm test.

Bundle analysis

Calculates the real cost of your library using size-limit with npm run size and visualize it with npm run analyze.

Credits

  • devuo for providing some ideas and inspiration!