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

@soroush.tech/markdown

v1.2.0

Published

Headless, composable markdown editor + renderer for @soroush.tech/design-system — Control, Toolbar, Editor, and Preview built on react-markdown, remark-gfm, and rehype-highlight.

Downloads

542

Readme

npm version npm downloads coverage unpacked size types included license

A headless markdown editor and preview.

Compose a toolbar, a source editor, and a live preview however your UI needs — and every element is styled by your theme. The renderer works standalone too, turning any markdown string into themed components, with support for tables, task lists, strikethrough, autolinks, syntax-highlighted code, and mermaid diagrams.

The Preview renderer output — a heading, a formatted paragraph, a task list, a blockquote, a code block, a table, and a mermaid sequence diagram, all as themed components

Why headless?

Most markdown editors hand you a fixed widget — a bordered box with a toolbar bolted on top and an Edit/Preview toggle you can't move. This one gives you the pieces instead:

  • You own the layout. Put the preview beside the editor, below it, in a modal, or drop it entirely — the parts don't care.
  • You own the state. The value is yours (useState, a form, a store); the editor just reads and writes it.
  • It looks like your app. Output is themed components — Typography, Link, Table, and its own CodeBlock — not unstyled HTML, so it inherits your theme with zero extra CSS.

Features

  • GitHub-Flavored Markdown — tables, task lists, strikethrough, and autolinks.
  • Syntax-highlighted code — fenced blocks are highlighted automatically; unknown languages degrade gracefully.
  • Mermaid diagrams — a ```mermaid fence renders as a themed diagram with built-in zoom and pan controls, loaded lazily on the client and falling back to the source until it does.
  • A real editing surface — Tab-to-indent, selection tracking, caret restoration, formatting buttons, heading and code-language selects, a hover-grid table picker, and a diagram picker that inserts starter templates for 23 mermaid diagram types.
  • Composable partsControl, Toolbar, Editor, and Preview, coordinated through React context.
  • Themeable to the slot — restyle the editor, toolbar, and preview through your theme, no forking required.
  • Typed and SSR-safe — first-class TypeScript, 100% test coverage, no browser globals at module scope.

Install

# npm
npm install @soroush.tech/markdown @soroush.tech/design-system
# pnpm
pnpm add @soroush.tech/markdown @soroush.tech/design-system
# yarn
yarn add @soroush.tech/markdown @soroush.tech/design-system

Requires the design system. This package renders through @soroush.tech/design-system, so its components must live inside that library's ThemeProvider. If you aren't already using the design system, start there first.

Quick start

Wrap your app in the design system's ThemeProvider once, then render markdown anywhere inside it:

import { ThemeProvider } from '@soroush.tech/design-system/theme'
import { Preview } from '@soroush.tech/markdown'

export function App() {
  return (
    <ThemeProvider>
      <Preview>
        {
          '# Hello\n\nRendered through your **theme** — tables, `code`, and [links](https://soroush.tech) included.'
        }
      </Preview>
    </ThemeProvider>
  )
}

That's the whole renderer. To let people write markdown, add the editing parts.

Editor

The Editor works standalone via value/onChange — no Control needed:

import { useState } from 'react'
import { Editor } from '@soroush.tech/markdown'
import { ThemeProvider } from '@soroush.tech/design-system/theme'

function MarkdownField() {
  const [value, setValue] = useState('# Start writing\n\nJust the source editor — no preview.')

  return (
    <ThemeProvider>
      <Editor value={value} onChange={setValue} />
    </ThemeProvider>
  )
}

A full editor and preview in a split screen

Everything inside Control shares one value and selection, so you arrange the panes freely. Here's a toolbar above a side-by-side source and live preview:

import { useState } from 'react'
import { Control, Toolbar, Editor, Preview } from '@soroush.tech/markdown'
import { Flex } from '@soroush.tech/design-system/Flex'

function MarkdownField() {
  const [value, setValue] = useState(
    '# Start writing\n\nType on the left, watch it render on the right. →'
  )

  return (
    <Control value={value} onChange={setValue}>
      <Toolbar />
      <Flex gap={4}>
        <Editor />
        <Preview>{value}</Preview>
      </Flex>
    </Control>
  )
}

There is intentionally no Edit·Split·Preview switch — which panes to show, and when, is your call.

The parts

| Part | Role | | --------- | --------------------------------------------------------------------------------- | | Control | Headless provider — owns the value/selection state. Takes value + onChange. | | Toolbar | Formatting buttons, heading/code-language selects, and the table picker. | | Editor | The source <textarea> — Tab-to-indent, selection, caret restore. | | Preview | Renders a markdown string (its child) to themed components. |

Toolbar and Editor must be rendered inside Control; Preview works anywhere. Import each directly from the package — there is no Markdown.* namespace. Full prop references live in the source on GitHub.

Customizing the look

Everything is styled through the design system's theme, and there are two levels to reach for — a shared theme for the whole look, and per-component slots for the markdown parts specifically.

Customize the theme — restyle everything

Preview renders design-system components that read theme tokens, so your theme already governs how markdown looks. Build one with createTheme — palette, spacing, type scale, radii — and pass it to ThemeProvider; the markdown output changes along with the rest of your UI, no markdown-specific setup. See the design system's theming guide for the full token set.

import { ThemeProvider, createTheme, baseTheme } from '@soroush.tech/design-system/theme'

const theme = createTheme(baseTheme, {
  palette: {
    primary: {
      main: '#7C3AED',
      light: '#A78BFA',
      dark: '#5B21B6',
      contrastText: '#FFFFFF',
    },
  },
})

// <ThemeProvider theme={theme}> … </ThemeProvider>

Customize the components — target the markdown parts

For tweaks specific to the editor, toolbar, or preview, this package registers three themeable slots under theme.componentsMarkdownEditor, MarkdownPreview, and MarkdownToolbar:

const theme = createTheme(baseTheme, {
  components: {
    MarkdownPreview: { styleOverrides: { root: { maxWidth: '72ch' } } },
    MarkdownToolbar: { styleOverrides: { root: { gap: 4 } } },
  },
})

The overrides are fully typed — importing the package registers the slots on the theme automatically.

Building your own parts

Need a custom control or a word count? useMarkdownContext() exposes the same value, selection, and dispatch the built-in parts use — call it from any component inside Control.

License

MIT © Soroush Tech