Designing
a Rich Content Editor

for a of the Web

WordPress

Democratise publishing

Turns 16!
of the Web
60% of CMS
100+ languages
38 million active installs

github.blog
newsroom.fb.com
news.microsoft.com
whitehouse.gov
techcrunch.com
blog.mozilla.org
newyorker.com
vogue.com
beyonce.com

WordPress

Open Source

Contributors worldwide
Backwards compatible
Out of the Box
Striving for Simplicity
Plugins & Themes

Easy is Relative

The web grew
Expectations grew
Steep learning curve
Competition

Previous Editor

Entirely contentEditable
DOM is source of truth
Fragile black box
Difficult to integrate with

<b>Oh&nbsp;</b><span><b>no</b>!</span>

Oh no!

Gutenberg

2.5 years
10 000 code merges
420 contributors
Incremental development

                    

        

                    


Everything
is a Block!

No contentEditable!

Block Markup: HTML

Lower level language of the web

Works everywhere
No lock-in
Readable
No logic needed to render

Difficult to parse

Block Markup: HTML?

Higher level language

Comments as delimiters
Permissive
Built-in
Just disappears

Own grammar: easy to parse

Static

<!-- wp:plugin/hours {"meta": 1 } -->
<table>...</table>
<!-- /wp:plugin/hours -->

Dynamic

<!-- wp:plugin/advertisement /-->

Parsed into an Object Tree

Redux Store

Backwards Compatibility

Classic editor as a block

Isolated Containers

Block grammar specification
React error boundaries
contentEditable

Blocks UI

Contextual tools
Design system
Single interface
Consistent experience

Placeholders & Templates

<!-- wp:core/image /-->

Swap content
Alert user on publish
Predefined

Reusable Blocks

Extend

Drawings
Calendar
Shape dividers
Forms
Advertisement
Code editor
Map
Payment

Discoverability

Inserter
Searchable
Plugin directory

Rich Text

External Solution?

Light
HTML input/output
Native UI:   
Dependency
Format boundaries

Format Boundaries

It's ‸<a ...>hyperlinked</a>.

<RichText />

contentEditable!
Controlled component
Manipulation helpers

{ text: 'I love React!',
  formats: [,,[B],[B],[B],[B],,,,,,,,],
  start: 7,
  end: 12 }

Key & Input

DOM → object → DOM
create        diff  

Extend

Formatting
Autocomplete
Text patterns (e.g. list, code)
Annotations
Content checking

<RichText>
  { ( { value, onChange } ) =>
    <Button onClick={ () =>
      onChange( toggleFormat(
        value, { 'slide/fragment' }
      ) )
    } />
  }
</RichText>

Block and Rich Text
Interactions

Explicit · Writing flow

<BlockEditor />

<RichText />

Versatile

Documents · Static Pages · AMP · Slides · Full Site

Drupal · Laravel · OctoberCMS · Jekyll

Full Site

Template editor
Direct manipulation
Theme just stylesheet

Thanks!

Resources

Why ContentEditable is Terrible by Nick Santos
The Language of Gutenberg by Miguel Fonseca
Gutenberg, or the Ship of Theseus by Matías Ventura
Gutenberg posts aren’t HTML… by Dennis Snell
Block Editor Handbook by Gutenberg contributors
One-third of the web! by Joost de Valk
Editor Technical Overview by Matías Ventura