What is Sir Trevor?

Sir Trevor provides a means to transform a text input into a rich content editor that’s been re-imagined for the web. The content of the editor is stored as HTML inside a JSON object, with the structure and the contents of the post serialized inside of it.

Get Started



npm package

npm install --save sir-trevor


Bower package.

Your bower.json file should look something like this:

  "name": "your-project",
  "dependencies": {
    "sir-trevor-js": "0.6.0"

Then run bower install on your project to install the necessary dependencies.

Alternatively, grab the following files and include them in your project:

You’ll need the following CSS file too:

And the icons file:


A Sir Trevor element must be contained inside a form like follows:

  <textarea class="js-st-instance"></textarea>

Then to transform this element to a Sir Trevor instance:

  var editor = new SirTrevor.Editor({
    el: document.querySelector('.js-st-instance'),
    defaultType: 'Text',
    iconUrl: 'build/sir-trevor-icons.svg'

You’ll also need to configure icon url

The Output

Sir Trevor stores structured JSON that describes your document.

A typical piece of Sir Trevor JSON looks like this:

  "data": [{
    "type": "text",
    "data": {
      "text": "<p>Hello, my name is <b>Sir Trevor</b></p>",
      "format": "html"

Each piece of JSON is made up of an object that contains the type and data for the block.

Generally, when rendering Sir Trevor on the server side you should map the types of the blocks to partials that define the presentation of that block, then all you have to do is loop over the JSON data and render the correct partial.

For a server-side example, please see our Sir Trevor Rails gem. The ideas within this could easily be extrapolated for other languages.

Retrieving Editor Instances

You can retrieve SirTrevor.Editor instance by assigning the editor to a variable.

var editor = new SirTrevor.Editor({});


Configuring iconUrl

Icons are included using an external svg file. This will need a url so that the icons can be found. This is set using default.

  iconUrl: "sir-trevor-icons.svg"

If you are using Sir Trevor in IE or a browser that doesn’t support svg fragments showing it could be because your browser doesn’t include svg sprite support.

<script src="../node_modules/svg4everybody/dist/svg4everybody.js" type="text/javascript" charset="utf-8"></script>

Customising icons

If you want to customise the icons, or add a custom block you’ll want to generate a new icon file. Icons are generated using Icomoon

Source svgs

Icomoon project

Once you’ve made changes to the icomoon project you can generate the svg file. Extract the svg from the downloaded project and add to your project. You’ll also need to set the location of iconUrl using the instructions above.


The editor accepts the following options. Options are passed to the editor on initialisation.

Specify an array of block types to use with the editor.
Defaults to all block types.

  blockTypes: ["Text", "Tweet", "Image"]

Specify a default block to start the editor with.
Defaults to no block.

  defaultType: "Text"

Set an overall total number of blocks that can be displayed.
Defaults to 0 (infinite).

  blockLimit: 1

Set a limit on the number of blocks that can be displayed by its type.
Defaults to {}.

  blockTypeLimits: {
    "Text": 2,
    "Image": 1

Specify which block types are required for validatation.
Defaults to none.

  required: ["Text", "Image"]

Call a function once the Editor has rendered.
Defaults to undefined.

  onEditorRender: function() {
    alert('Do something');

Block Options

You can set specific options for blocks by using the setBlockOptions method.

SirTrevor.setBlockOptions('Tweet', {
  someValue: true

Global Options

You can also set options globally for all Sir Trevor instances using the setDefaults method.

  required: ["Text"]


Tweet Block

To use the Tweet block you’ll need some server side code. This will need to lookup a Tweet ID and return the tweet in JSON via the Twitter API. Unfortunately, the only way to do this via the API is with an authenticated call.

You can change the Tweet fetch URL as follows:

SirTrevor.setBlockOptions("Tweet", {
  fetchUrl: function(tweetID) {
    return "/tweets/?tweet_id=" + tweetID;

Image Block

The image block relies on a server side component to store images on the server. By default Sir Trevor will do an AJAX file upload in the background to a /attachments endpoint. You can change this as follows:

  uploadUrl: "/images"

The uploader posts an attachment hash that has three properties:

There is an uploader example using Rails + Carrierwave.


There are a few hook in points per block that you can use:

Called immediately when render is called.

SirTrevor.Blocks.Text.beforeBlockRender = function() {
  alert('Do something');

Called once a block has been rendered.

SirTrevor.Blocks.Text.onBlockRender = function() {
  alert('Do something');

Mediated Events

We use events bound to an individual editor to trigger actions internally. You can use these events to hook into the inner workings of Sir Trevor.

Block events

Error events

Formatter events

You can use access these events using the mediator object on an editor as follows:

var editor = SirTrevor.Editor({
  el: document.querySelector('.js-editor')

editor.mediator.on('block:create', function() {

Custom Blocks

A founding principle of Sir Trevor is to have an extensible editor that you can create your own block types on top of. We’ve made it really simple for you to get started and build your own block types.

A good place to start is to read through one of the blocks that comes bundled with Sir Trevor.

There’s also a Sir Trevor Blocks repository.


A SirTrevor.Block essentially takes some data, provides an interface for that data and knows how to serialize itself into JSON.

Generally the flow for a block goes like this:

  1. Create block
  2. Render block
  3. Edit some data
  4. Submit form
  5. Validate block with validations
  6. Block data is serialized to the block store

1. Create block

// Trigger BlockManager to create a block of the type and data required.
mediator.trigger('block:create', block.type, block.data)

// Create a new block
var block = new Block(data);

// Render block

// BlockManager.renderBlock then attaches the block to the dom and calls a final function
block.onBlockRender() // Placeholder function. Could deal with focus.

2. Render block

// Called when a block is first added to the dom or moved.

block.beforeBlockRender() // Placeholder function
block._initTextBlocks() // Initialise scribe text areas
block.withMixin() // Load mixins for block
block.checkAndLoadData() // 
> block.beforeLoadingData() // Set block as loading, loadData and then set block as ready
> > block.loadData() // Each block should implement this to populate from data
block.save() // store current block data to the block store.
> block.setData()

The methods associated with doing this are:

Function is called with the JSON block data when updated and allows the block to rerender as required.

loadData(data) {
  this.el.querySelector('.js-cite').value = data.cite;

Takes a JSON object and stores it against the block.


Get the current block data as a JSON object

getBlockData() // returns {}

Override the block data for storage and return a JSON object.

_serializeData() {
  return {
    cite: this.el.querySelector('.js-cite')

Render Block UI

SirTrevor.Blocks.ComplexType = SirTrevor.Block.extend({
  type: "complex_type",

  // Custom html that is shown when a block is being edited.

  editorHTML: `
      // Add a scribe controlled text field
      // Note: Only possible to have 1 per block at present
      <div class="st-text-block" contenteditable="true"></div>

      // Add a simple input field
      <input type="text" name="inputtext1" value="inputtext1" />

      // Add a simple text area
      <textarea name="textarea1">textarea1</textarea>

      // Add a checkbox
      <input type="checkbox" name="checkbox1" value="1" checked="checked" />
      <input type="checkbox" name="checkbox2" value="2" />

      // Add a checkbox which toggles `on` & `off` values
      <input type="checkbox" name="checkbox3" value="3" data-toggle="true" />
      <input type="checkbox" name="checkbox4" value="4" checked="checked" data-toggle="true" />

      // Add radio buttons. `name` will need to be defined per block
      // `data-name` is used as an override for the data key to be saved
      <input type="radio" name="block1-radio1" value="radio11" data-name="radio1" />
      <input type="radio" name="block1-radio1" value="radio12" data-name="radio1" checked="checked" />
      <input type="radio" name="block1-radio2" value="radio21" data-name="radio2" />
      <input type="radio" name="block1-radio2" value="radio22" data-name="radio2" />

      // Add select boxes
      <select name="select1">
        <option selected="selected">select12</option>


We’ve abstracted all of the interface components for creating a Sir Trevor block. The following mixins are available to all blocks:

Provides a drop zone support for the block. Exposes the onDrop event which must be overwritten.

Provides the UI support for a pastable component (like the video block). You can override the default paste handler by re-implementing the onContentPasted method.

Provides support for uploadable content and mixins in the uploader into the block. The uploadable mixin will use the uploadUrl set in the SirTrevor.setDefaults by default. Your custom block can override this by defining uploadUrl in the block body.

Gives a way to fetch content remotely through a editor managed queue.

Provides a second, smaller UI in the lower left block corner to control its contents. Requires the controls-object so be specified in the block configuration ('command-name': handler).

Provides ajax functionality for a block. Along with a url you can pass options that will get passed to the Ajax.fetch library.

Provides support for the block to be handled as an inline text block. Currently supported by Text, Heading and Quote blocks.

The droppable, uploadable and pastable components have the ability to override the default HTML that gets built as the UI. This can easily be done through the upload_options.html, drop_options.html or paste_options.html objects on the block. Each takes a string that is passed to an underscore _.template method.


There are two types of validations with Sir Trevor, required fields and custom validators. To add a field in your block as required, simply add the st-required class to it.

If you want to create custom validators, just define the method on your block and add it to the validations array on the block. To trigger an error on the block, you add an error to the errors array using the this.setError method.

validations: ['myCustomValidator'],

myCustomValidator: function() {
  var someField = this.$('.field');

  if (someField.value === "BEER!") {
    this.setError(someField, "must not contain beer");

Text editing


Sir Trevor uses Scribe for text editing. The document that is available can be found here https://github.com/guardian/scribe/wiki.

Text Formatting

The main reason for using Scribe is to provide text formatting and make content editable cross browser compatible.

Formatting has been enabled using various plugins that can be found here:

To add your own formatting you’ll want to install a plugin or create your own.

Create a Scribe plugin

If you want to create your own plugins then follow the steps below:

Step 1.

Define your toolbar commands

Step 2.

Modify the linkPrompt plugin

The main file is

You’ll find this assigns scribe.commands.linkPrompt which is the cmd set in the config.
So what you’ll do is write your own plugin and then assign it to something like scribe.commands.customLinkPrompt then modify the formatBar.commands in your config override.

Step 3.

You’ll need to find a way to call scribe.usefor the plugin.

If it needs to be on all blocks then you’ll need to patch something in:

Per block you can define configureScribe