Extending Bard

The Bard fieldtype is a rich-text editor based on TipTap, which in turn is a Vue component that wraps around ProseMirror, which is robust JavaScript framework for building rich-text editors that don't directly write HTML or rely on contenteditable, but rather a document model.

Required Reading

Before you attempt to create any Bard extensions, it would be wise to learn how to write a TipTap extension first. Otherwise you’d be trying to learn how to ride a motorcycle before you can even ride a bike. Or a unicyle before you can juggle. To have a better understanding of how to write a TipTap extension, you’d in turn benefit greatly on reading about how ProseMirror works.

Hot Tip!

Writing custom extensions for Bard is pretty complicated, but can be rewarding and give you powerful results.

In short, here’s a quickstart of the things you should probably start with:


You may add your own TipTap extensions to Bard using the extend method. The callback may return a single extension, or an array of them.

Statamic.$bard.extend(({ mark, node }) => mark(new MyExtension));
Statamic.$bard.extend(({ mark, node }) => {
return [
mark(new MyExtension),
node(new AnotherExtension)

The classes you return should be wrapped using the provided helper functions (i.e. mark or node like in the example above).


Your extension class should look like a TipTap extension (see an example here) except it should not extend another class, and you should use methods instead of getters.

export default class MyExtension {
name() {
return 'myextension';
schema() {
// Your schema stuff
commands({type}) {
// Your command stuff
inputRules({type}) {
return [] // Input rules if you want
plugins() {
return []
pasteRules() {
return []

Marks and Nodes

The extend callback will provide the mark and node functions to you. Use it to wrap your class, and under the hood it will convert it to an actual TipTap extension class to be used by Bard.

Within your class, Statamic will provide commonly used functions along with the arguments you’d get in a TipTap extension. This prevents you from needing to import the entire TipTap library into your build. For example:

// mark
commands({ type, toggleMark }) {
return () => toggleMark(type)
// node
commands({ type, toggleBlockType }) {
return () => toggleBlockType(type)
Hot Tip!

If you need more TipTap methods than the ones passed into the arguments, you can use our TipTap API.

If you’re providing a new mark or node and intend to use this Bard field on the front-end, you will also need to create a Mark or Node class to be used by the PHP renderer.


To add a button to the toolbar, use the buttons method. The callback may return a button object, or an array of them.

Statamic.$bard.buttons(() => {
return { name: 'bold', text: __('Bold'), command: 'bold', icon: 'bold' };
Statamic.$bard.buttons(() => [
{ name: 'bold', text: __('Bold'), command: 'bold', icon: 'bold' },
{ name: 'italic', text: __('Italic'), command: 'italic', icon: 'italic' },

Returning values to the button method will push them onto the end. If you need more control, you can manipulate the supplied buttons argument, and then return nothing. For example, we’ll add a button after wherever the existing bold button happens to be:

Statamic.$bard.buttons(buttons => {
const indexOfBold = _.findIndex(buttons, { command: 'bold' });
buttons.splice(indexOfBold + 1, 0, {
name: 'italic', text: 'Italic', command: 'italic', icon: 'italic'

TipTap API

In your extensions, you may need to use functions from the tiptap library. Rather than importing the library yourself and bloating your JS files, you may use methods through our API.

Statamic.$bard.tiptap.core; // 'tiptap'
Statamic.$bard.tiptap.commands; // 'tiptap-commands'
Statamic.$bard.tiptap.utils; // 'tiptap-utils'

You could shorten things up by using destructuring. For example:

const { core: tiptap, commands, utils } = Statamic.$bard.tiptap;
const selection = new tiptap.TextSelection(...);

ProseMirror Rendering

If you have created a mark or node on the JS side to be used inside the Bard fieldtype, you will need to be able to render it on the PHP side (in your views).

The Bard Augmentor class is responsible for converting the ProseMirror structure to HTML.

You can use the addMark and addNode methods to bind a Mark or Node class into the renderer. Your service provider’s boot method is a good place to do this.

use Statamic\Fieldtypes\Bard\Augmentor;
public function boot()
Docs feedback

Submit improvements, related content, or suggestions through Github.

Betterify this page →