Skip to content
pcwadarongPublic

About

composable markdown editor toolkit

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Latest commit

 

History

104 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

chaeditor

English | 한국어

Build composable markdown editors for React with authoring helpers, rich embeds, and overridable styling. chaeditor ships as one package. Use subpath imports like chaeditor/react and chaeditor/core to pull in only what you need.

Links

Guides

Recommended order:

If you are integrating for the first time, start with the Next.js guide.

If uploads, image insertion, link preview cards, or route wiring are part of the job, the wiki is more useful than the README alone.

If you are using React but do not need a Next.js-specific walkthrough, open Introduction / Host Adapters in Storybook first.

Quick Start

Choose the integration path that matches your current scope.

Renderer only

Use this when you only need markdown display.

import 'chaeditor/styles.css';

import { MarkdownRenderer } from 'chaeditor/react';

const Example = async () => {
  return <MarkdownRenderer markdown="# Hello chaeditor" />;
};

Editor without host adapters

Use this to try out text input, toolbar actions, and preview before wiring up any upload logic.

'use client';

import { useState } from 'react';

import 'chaeditor/styles.css';

import { MarkdownEditor } from 'chaeditor/react';

const Example = () => {
  const [value, setValue] = useState('# Hello chaeditor');

  return <MarkdownEditor contentType="article" onChange={setValue} value={value} />;
};

Full integration

Use this when you need uploads, attachments, videos, and preview cards.

'use client';

import { useState } from 'react';

import 'chaeditor/styles.css';

import { createDefaultHostAdapters } from 'chaeditor/default-host';
import { MarkdownEditor } from 'chaeditor/react';

const adapters = createDefaultHostAdapters();

const Example = () => {
  const [value, setValue] = useState('');

  return (
    <MarkdownEditor adapters={adapters} contentType="article" onChange={setValue} value={value} />
  );
};

Then follow Integrating chaeditor in Next.js to create the expected host routes and verify the real app flow.

Host Adapter Checklist

chaeditor keeps upload logic, link preview data, and framework-specific rendering out of the package — those belong to your app. This is what makes the package reusable across different products without modifications.

For most React apps, a solid editor integration covers these adapters:

Adapter What it enables If omitted When teams usually add it
uploadImage file-backed image insertion in editor flows image upload UI can render, but file-backed insertion needs a host implementation add this if users should upload images from the editor
uploadFile attachment upload attachment UI can still appear, but upload-specific actions should stay disabled add this if attachments are part of your content model
uploadVideo video file upload video helpers can fall back to URL-based insertion add this only when your product supports video uploads
fetchLinkPreviewMeta preview cards with title, description, and image preview cards fall back to plain links add this if pasted links should render as rich cards
resolveAttachmentHref host-aware attachment URLs renderer uses markdown href as-is add this when stored files resolve through your app routing or CDN rules
renderImage rendering through your app's image component package uses its default image renderer recommended when your app standardizes on next/image or a branded media component
imageViewerLabels built-in viewer copy override package uses built-in labels optional, only for copy override

For most products, the following combination covers the baseline host integration:

  • uploadImage
  • uploadFile
  • uploadVideo if your product supports uploaded video
  • fetchLinkPreviewMeta
  • resolveAttachmentHref
  • renderImage if image rendering consistency matters in your app

A React-first adapter example:

import 'chaeditor/styles.css';

import { MarkdownEditor } from 'chaeditor/react';

const adapters = {
  uploadImage: async ({ contentType, file, imageKind }) => {
    return uploadImageToYourApi({ contentType, file, imageKind });
  },
  uploadFile: async ({ contentType, file }) => {
    return uploadFileToYourApi({ contentType, file });
  },
  uploadVideo: async ({ contentType, file, onProgress, signal }) => {
    return uploadVideoToYourApi({ contentType, file, onProgress, signal });
  },
  fetchLinkPreviewMeta: async (url, signal) => {
    return fetchPreviewMetaFromYourApi(url, signal);
  },
  resolveAttachmentHref: ({ href }) => href,
  renderImage: ({ alt, className, fill, sizes, src }) => (
    <img
      alt={alt}
      className={className}
      sizes={sizes}
      src={typeof src === 'string' ? src : src.src}
      style={fill ? { inset: 0, position: 'absolute' } : undefined}
    />
  ),
};

For a deeper look at the adapter contract and host/package ownership, read Introduction / Host Adapters in Storybook.

Installation

Install chaeditor once, then import only the subpaths you need. For most app code, chaeditor/react and chaeditor/core are the right starting points. The root chaeditor entrypoint still works, but it mixes React and core exports into one surface — use the subpaths above instead.

npm install react react-dom chaeditor
pnpm add react react-dom chaeditor
yarn add react react-dom chaeditor
bun add react react-dom chaeditor

CSS choice

Entry Use when Includes
chaeditor/styles.css you want the safest default, or you render math package styles, Panda output, KaTeX styles, KaTeX fonts
chaeditor/styles-lite.css you intentionally own KaTeX CSS, or you do not render math package styles without KaTeX runtime styles

Recommended default:

import 'chaeditor/styles.css';

Lighter option:

import 'chaeditor/styles-lite.css';

If you choose styles-lite.css and render math, also import:

import 'chaeditor/styles-lite.css';
import 'katex/dist/katex.min.css';

See Styling and CSS setup for a fuller decision guide and consumer-side checklists.

Package Surface

chaeditor is one npm package with selective subpath imports. You do not install subpaths separately.

Import path Provides Use when
chaeditor/react MarkdownEditor, MarkdownToolbar, MarkdownRenderer, and React registries most app integrations
chaeditor/core pure helpers, markdown contracts, and theme utilities logic-only usage or server-safe helpers
chaeditor/default-host packaged upload and preview helpers quick start, demos, or route-convention wiring
chaeditor/panda-primitives packaged Panda primitive shells only when you want to reuse or wrap the default shells
chaeditor/styles.css full default CSS bundle safest styling path
chaeditor/styles-lite.css lighter default CSS bundle when your app owns KaTeX styling

For the full breakdown, read Choosing import paths.

Task-Based Shortcuts

Theme And Host Customization

chaeditor separates theme overrides from host-owned integration logic.

  • Use createChaeditorThemeVars() when you want to override semantic tokens such as primary, surface, text, or font stacks.
  • Use primitiveRegistry when you need to replace the actual Button, Input, Textarea, Popover, Modal, or Tooltip shells.
  • Use createDefaultHostAdapters() or custom adapters when uploads, href resolution, image rendering, or link preview data belong to your app layer.

Minimal theme override example:

import 'chaeditor/styles.css';

import { createChaeditorThemeVars } from 'chaeditor/core';
import { MarkdownEditor } from 'chaeditor/react';

const themeVars = createChaeditorThemeVars({
  primary: '#0f766e',
  primarySubtle: '#ccfbf1',
  surface: '#f8fafc',
  text: '#0f172a',
  sansFont: 'var(--app-font-sans), system-ui, sans-serif',
});

const Example = () => (
  <div style={themeVars}>
    <MarkdownEditor contentType="article" onChange={() => {}} value="" />
  </div>
);

The full primitive replacement walkthrough lives in Replacing default UI primitives.

Local Development

pnpm install
pnpm lint
pnpm check-types
pnpm test
pnpm build
pnpm run verify:package-surface

If a change is visual or touches docs-facing examples, also run:

pnpm storybook

Reporting Issues

Before opening a new issue, check whether the same problem is already reported. Bug reports are much easier to act on when they include:

  • package version
  • framework or runtime version
  • a clear reproduction path
  • error text or screenshots when relevant
  • whether the bug happens in the real app, Storybook, or only after packing

Contributing

If you want to contribute, start with CONTRIBUTING.md.

About

composable markdown editor toolkit

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages