wysimarkFeaturesDocsLicense

Getting Started

Installation

Install @wysimark/react using

npm i --save @wysimark/react

or

yarn add @wysimark/react

or

pnpm add @wysimark/react

Usage

Basic Usage

This example shows you how to use the Wysimark Editor in React.

import { Editable, useEditor } from "@wysimark/react"
import { useState } from "react"

const MyComponent = () => {
  const [markdown, setMarkdown] = useState("# Hello World")
  const editor = useEditor()
  return <Editable editor={editor} value={markdown} onChange={setMarkdown} />
}

Wysimark behaves like a typical controlled input.

You pass a value and an onChange handler to the Editable component. The value is the markdown and the onChange handler is called whenever the markdown changes.

The onChange handler is called with the current markdown as the first argument. That's why we can pass setMarkdown directly to the onChange handler.

Usage with File Uploads

This examples show you how to create a Wysimark editor with image uploading, server-side image resizing and file attachment uploading enabled.

Follow the same steps as "Basic Usage" above then:

  • Get a free upload API key and generate an authToken at https://www.portive.com. Portive is the creator of Wysimark and provides back-end services to help you manage server-side uploads. You need to create a free account which includes 1 GB of free upload storage. It takes about 3 minutes to get an auth token.
  • Once you have the authToken pass it to the useEditor hook.
import { Editable, useEditor } from "@wysimark/react"
import { useState } from "react"

const MyComponent = () => {
  const [markdown, setMarkdown] = useState("# Hello World")
  const editor = useEditor({ authToken: "AUTH_TOKEN_GOES_HERE" })
  return <Editable editor={editor} value={markdown} onChange={setMarkdown} />
}

Where it says AUTH_TOKEN_GOES_HERE you should provide your own auth token.

Usage with Setting Markdown

This examples shows you how to create a Wysimark editor and how set the value of the Markdown.

import { Editable, useEditor } from "@wysimark/react"
import { useCallback, useState } from "react"

const MyComponent = () => {
  const [markdown, setMarkdown] = useState("# Hello World")
  const editor = useEditor({ authToken: "AUTH_TOKEN_GOES_HERE" })

  const sayGoodbye = useCallback(() => {
    setMarkdown("# Goodbye World")
  })

  return (
    <div>
      <Editable editor={editor} value={markdown} onChange={setMarkdown} />
      <button onClick={sayGoodbye}>Say Goodbye</button>
    </div>
  )
}

When the user clicks the button that says Say Goodbye the markdown will be set to # Goodbye World.

useEditor

Use the useEditor hook to create an editor object which needs to be passed to the Editable component.

The useEditor hook is where we set the initial content and configure the behavior of the Editor.

Example usage:

const editor = useEditor({
  authToken: "xxxx",
})

UseEditor options:

type UseEditorOptions = {
  authToken?: string
  height?: number
  minHeight?: number
  maxHeight?: number
}

authToken?: string

Set the authToken for uploading files and images which enables these features.

If you don't need or want to support uploads, you can omit this option. The upload attachments and images features will be disabled and pasting or dropping files into the editor won't work. Pasting and dropping text will continue to work.

height?: number | string

Sets the css height for the Editable component.

minHeight?: number | string

Sets the css min-height for the Editable component.

maxHeight?: number | string

Sets the css max-height for the Editable component.

Editor

The editor object is returned by the useEditor and needs to be passed in as a prop to the Editable component.

type Editor = {
  getMarkdown: () => string
  setMarkdown: (markdown: string) => void
}

Typically, you won't need to use these methods.

The editor object has methods that are useful to read data from the editor and to set the value of the editor. They behave different than when you get and set the values of the Editable component directly with the value and onChange prop.

NOTE: The typescript types for this Editor object will show more methods and properties that are required to make the editor work. These are internal methods and properties that you should not use.

getMarkdown: () => string

Calling getMarkdown returns the editor's content as Markdown.

import { Editable, useEditor } from "@wysimark/react"
import { useRef } from 'react'

const MyComponent = () => {
  const [markdown, setMarkdown] = useState("# Hello World")
  const editor = useEditor({})

  const showMarkdown = () => {
    alert(editor.getMarkdown()
  }

  return <div>
    <button onClick={showMarkdown}>Show Markdown</button>
    <Editable editor={editor} value={markdown} onChange={setMarkdown} />
  </div>
}

This differs slightly from reading the markdown state. Converting the editor's content to Markdown is an expensive operation so the onChange callback is throttled, by default to once per second. The onChange callback is also called when the editor is blurred.

Calling editor.getMarkdwon() will return the current value of the editor, even if the onChange callback has not been called yet because it is throttled and the editor wasn't blurred.

In this example though, using editor.getMarkdown() is not necessary. When you click the button, the markdown state will have been updated because the editor has been blurred and you can just use that.

setMarkdown: (markdown: string) => void

Calling setMarkdown sets the editor's content using the markdown argument.

import { Editable, useEditor } from "@wysimark/react"
import { useRef } from "react"

const MyComponent = () => {
  const [markdown, setMarkdown] = useState("# Hello World")
  const editor = useEditor({})

  const resetMarkdown = () => {
    // reset the editor to an empty string
    editor.setMarkdown("")
  }

  return (
    <div>
      <button onClick={resetMarkdown}>Reset Markdown</button>
      <Editable editor={editor} value={markdown} onChange={setMarkdown} />
    </div>
  )
}

This is an alternate way of setting the markdown in the editor. The recommended way is to update the value prop of the Editable component.

Editable

The Editable component is the main component of Wysimark and is where the editor is rendered.

You must pass the Editor object returned from the useEditor hook to it as a prop.

You must also pass the markdown value and a callback function to handle changes to the markdown value.

type EditableProps = {
  editor: Editor
  value: string
  onChange: (markdown: string) => void
  throttleInMs?: number
  placeholder?: string
  className?: string
  style?: React.CSSProperties
}

Example usage:

import { Editable, useEditor } from "@wysimark/react"
import { useRef } from "react"

const MyComponent = () => {
  const [markdown, setMarkdown] = useState("# Hello World")
  const editor = useEditor({})

  return (
    <Editable
      editor={editor}
      value={markdown}
      onChange={setMarkdown}
      throttleInMs={500}
      placeholder="Type something here..."
    />
  )
}

editor: Editor

This prop is required and is the return value of the useEditor hook.

value: string

This prop is required and is the markdown value of the editor.

onChange: (markdown: string) => void

A callback function that is called whenever the editor's content changes. For performance reasons, this callback is throttled by default to 1000ms (1 second). You can change this by passing a throttleInMs prop.

throttleInMs?: number

The number of milliseconds to throttle the onChange callback by. Defaults to 1000ms (1 second).

placeholder?: string

The placeholder text to show when the editor is empty.

className?: string

A class name to apply to the root element of the editor.

style?: React.CSSProperties

A style object to apply to the root element of the editor.