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

react-native-markdown-lite

v1.0.0

Published

Dependency-free markdown renderer for React Native, with a pure parser you can use on its own

Readme

react-native-markdown-lite

npm version install size npm downloads License: MIT

Description

A markdown renderer for React Native with no runtime dependencies, and a pure parser you can use without the renderer.

It was written for screens that show a document the app did not write — a licence text, a changelog, a README, a remote note — where the markdown is incidental and the budget for it is small. It renders to Text and View, and nothing else.

Features

  • Zero runtime dependencies. About 7.5 kB gzipped for the renderer and the parser together, 5.7 kB for the parser alone. Metro does not tree-shake, so what a package weighs is what the app carries.
  • A parser you can use on its own. react-native-markdown-lite/parser imports neither React nor React Native, so it runs in Node, in a test or in a worker.
  • Styled by you. Every element takes its style from a styles prop merged over the defaults, key by key — no CSS-in-string layer and no theme object to learn, so an app's existing design tokens go straight in.
  • Safe with documents you did not write. Only expected URL schemes open, nesting is bounded, and nothing is fetched — see Untrusted documents.
  • Accessible by default. Headings, links and image alts carry the roles a screen reader needs to navigate the document.
  • TypeScript throughout, with the document model exported.
  • ESM and CommonJS, with types for both.

Install

npm install react-native-markdown-lite

Peers: react >= 18, react-native >= 0.70. Nothing else.

Usage

import { Markdown } from 'react-native-markdown-lite';

const Screen = () => (
  <ScrollView>
    <Markdown value={'# Title\n\nSome **bold** text and a [link](https://example.com).'} />
  </ScrollView>
);

Styling

styles is layered on top of the defaults the way React Native composes a style array, so you only pass the properties you want to change and everything else stays put — including the layout an element is built from, like the row a list item needs to keep its bullet beside the text:

<Markdown
  value={document}
  styles={{
    text: { color: theme.colors.onSurface, fontSize: 16 },
    heading1: { color: theme.colors.onSurface, fontWeight: '700' },
    link: { color: theme.colors.primary },
    codeBlock: { backgroundColor: theme.colors.surfaceVariant },
  }}
/>

| Key | Applies to | |---|---| | body | the outer container (view) | | text | every piece of text; the base the rest inherit from | | paragraph, heading1…heading6 | block text | | strong, emphasis, code, link, imageAlt | inline text | | codeBlock (view), codeBlockText | fenced and indented code | | list (view), listItem (view), listItemContent (view), marker | lists, their bullets or numbers, and the column the item's text lives in | | blockquote (view) | quoted blocks | | rule (view) | thematic breaks |

Props

| Prop | Type | Default | | |---|---|---|---| | value | string | — | the markdown source | | styles | MarkdownStyles | {} | layered over the defaults | | options | ParseOptions | { linkify: true } | parser options | | onLinkPress | (href: string) => void | Linking.openURL | called instead of opening the link, with the href exactly as written | | selectable | boolean | false | lets the reader select and copy | | testID | string | — | passed to the container |

The parser on its own

import { parseMarkdown } from 'react-native-markdown-lite/parser';

parseMarkdown('# Title\n\n- one\n- two');
// [
//   { type: 'heading', level: 1, children: [{ type: 'text', value: 'Title' }] },
//   { type: 'list', ordered: false, start: 1, items: [ … ] },
// ]

The document model is exported as MdDocument, MdBlock and MdInline, so a renderer of your own — a slide deck, a summariser, a search indexer — can walk it without reimplementing the parsing.

Untrusted documents

This package exists to render a document the app did not write — a licence text, a changelog, a remote note — so the three ways such a document could misbehave are closed off:

  • Only http, https, mailto and tel links open. A document cannot reach the OS with intent:// or file://, or fire a deep link back into your own app. The link still renders and still responds to a tap; it is only the default handler that refuses. Pass onLinkPress and you receive every href exactly as written, including the refused ones, and decide for yourself.
  • Nesting is bounded. Blocks and inline spans stop being given structure past 32 levels and the rest is kept as text, so a file of nothing but > characters cannot overflow the stack.
  • Nothing is fetched. Images render as their alt text.

Text is never executed or interpolated anywhere — it only ever becomes the children of a Text — so there is no injection surface to speak of beyond the above.

What it supports

ATX (# …) and setext (===) headings · paragraphs with soft and hard line breaks · fenced and indented code blocks · bullet and ordered lists, nested · blockquotes · thematic breaks · **bold**, *italic*, `code` · inline, reference and shortcut links · autolinks and bare URLs · images as alt text · backslash escapes.

What it does not

This is a pragmatic subset, not a CommonMark implementation. It is worth knowing which corners were cut and why:

  • Tables are not parsed. They render as paragraphs with the pipes intact, which is honest but not pretty. A table is rarely legible at phone width anyway.
  • Raw HTML is dropped, tags and comments alike, and the text they wrap is kept. React Native has no element to map <div> onto.
  • Images are never loaded. The alt text renders instead.
  • Emphasis uses a simpler rule than CommonMark's delimiter stack. ***both*** falls back to literal text.
  • Footnotes, task lists, strikethrough and definition lists are not supported.
  • _ inside a word never opens emphasis, on purpose: snake_case and __dirname must survive.
  • Nesting stops at 32 levels. Past that the remaining text is kept, but flat. No real document comes close.

If your documents need any of these, reach for a full CommonMark implementation instead — this one trades coverage for weight, and that trade is only worth it when the subset is enough.

Contributing

npm ci
npm run verify   # lint, typecheck, tests, build and a smoke test of the built artifact

The parser is tested in plain Node; the renderer is tested against a stub of the three React Native modules it touches, so the test run needs neither Metro nor the React Native jest preset. npm run smoke runs the built artifact the way a consumer resolves it, including the legacy parser/ path that bundlers without package exports take.

Releasing

Publishing takes two steps on purpose. CI can stage a release on its own, but making it public needs a person:

  1. Bump version in package.json, write the CHANGELOG.md entry, and merge to main.
  2. Tag vX.Y.Z and create the GitHub release. CI checks the tag against package.json, builds, smoke-tests the artifact and runs npm stage publish. The version is now in the registry but not installable.
  3. Approve it, which is the step that asks for 2FA:
npm stage list react-native-markdown-lite   # find the stage id
npm stage download <stage-id>               # optional: inspect the exact tarball
npm stage approve <stage-id>                # publishes it

npm stage reject <stage-id> throws the staged version away if something looks wrong, and the version number stays free.

This is why there is no npm token in this repository: the trusted publisher may stage, and only a human with 2FA can publish.

License

MIT © Gabriel Galilea