Designing
a Rich Content Editor

for a of the Web

<!doctype html>

<title>Hello, JSConf EU! · Ella’s Website</title>

<nav><a href=”index.html“>Home</a></nav>

<h1>Hello, JSConf EU!</h1>

<p>Here’s my web page.</p>

<p>It’s so easy!</p>

<aside></aside>

<!doctype html>

<title>Hello, JSConf EU! · Ella’s Website</title>

<nav><a href=”index.html“>Home</a></nav>

<h1>Hello, JSConf EU!</h1>

<p>Here’s my web page.</p>

<p>It’s so easy!</p>

<aside></aside>

<!doctype html>

<title>Hello, JSConf EU! · Ella’s Website</title>

<nav><a href=”index.html“>Home</a></nav>

<h1>Hello, JSConf EU!</h1>

<p>Here’s my web page.</p>

<p>It’s so easy!</p>

<aside></aside>

<!doctype html>

<title>Hello, JSConf EU! · Ella’s Website</title>

<nav><a href=”index.html“>Home</a></nav>

<h1>Hello, JSConf EU!</h1>

<p>Here’s my web page.</p>

<p>It’s so <a href=”easy.html“>easy</a>!</p>

<aside></aside>

<!doctype html>

<title>Hello, JSConf EU! · Ella’s Website</title>

<nav><a href=”index.html“>Home</a></nav>

<h1>Hello, JSConf EU!</h1>

<p>Here’s my web page.</p>

<p>It’s so <a href=”easy.html“>easy</a>!</p>

<p><img src=”yay.gif“></p>

<!doctype html>

<title>Hello, JSConf EU! · Ella’s Website</title>

<nav><a href=”index.html“>Home</a></nav>

<h1>Hello, JSConf EU!</h1>

<p>Here’s my web page.</p>

<p>It’s so <a href=”easy.html“>easy</a>?</p>

<p><img src=”yay.gif“></p>

Hello JSConf EU!

Here’s my web page.

It’s so easy!

✨ contentEditable ✨

It’s magic!

<body contenteditable=”true“>
  All your editable wishes come true.
</body>

But… no specification!

Enter → <p>? <br>? <div>? Context?
Backspace <img>? <figure>? <figcaption>?
Bold → <span style=”“>? <b>? <strong>?

Hello, world!


Sheep

<p><b>Hello</b>, world!</p>
<figure><img src=”yay.gif“>
    <figcaption>Sheep<figcaption>
</figure>

<b>H</b><span><b>ello</b></span>
,&nbsp;world!
<br><br><img src=”yay.gif“>
Sheep&nbsp;

DOM

= Source of truth

Selection

This is a quote.

<blockquote>
  <p>This is a quote.</p>
</blockquote>

Selection

It’s hyperlinked.

It’s ‸<a …>‸hyperlinked‸</a>‸.
 
 

<body contenteditable=”true“>
  …
  <div contenteditable=”false“>Protected</div>
  …
</body>

✨ contentEditable ✨

It’s black magic!

<body contenteditable=”true“>
  ???
</body>

Gutenberg

2.5 years
10 000 code merges
420 contributors

Everything is a Block!

Block Markup: HTML

Lower level language of the web

Block Markup: HTML

Higher level language

<!– wp:plugin/calendar {“meta”: 1 } –>
<table></table>
<!– /wp:plugin/calendar –>

Dynamic

<!– wp:plugin/advertisement /–>

<!– wp:plugin/photo-album /–>

Backwards Compatibility

Classic editor as a block

Isolated Containers

Block grammar specification
Error boundaries
Limit contentEditable

Placeholders

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

Swap content
Alert user on publish

Templates

Reusable Blocks

Extend

Drawings
Calendar
Shape dividers
Forms
Advertisement
Code editor
Map
Payment

Discoverability

Inserter
Searchable
Plugin directory

Rich Text

Format Boundaries

It’s ‸<a …>hyperlinked‸</a>‸.

✨ contentEditable ✨

It’s magic!

<body contenteditable=”true“>
  Input · Selection · Resizes · Accessible · Native UI
</body>

Controlled State

const F =
{ type: 'core/link',
  url: 'https://w.org' }

{ text: 'I love JS!',
  formats: [,,[F],[F],[F],[F],,,,,],
  start: 7,
  end: 9 }

concat
indexOf
replace
slice
split

applyFormat
removeFormat
insertObject
insert
remove

Key & Input

DOM → object → DOM
create        diff  

Extend

DOM → object → object → DOM
create    transform    diff   

Extend

Input rules
Custom formatting
Autocomplete
Annotations
Content checking

Explicit
Block and Rich Text
Interactions

For a good writing flow

Versatile

Documents · Static Pages · AMP · Slides · Full Site

Drupal · Laravel · OctoberCMS · Jekyll

<?php site_title() ?>
<?php site_navigation() ?>

<article>
  <h1><?php title() ?></h1>
  <?php content() ?>
  <?php previous(); next() ?>
</article>

<aside>
  <?php search() ?>
  <?php latest() ?>
</aside>

<?php comments() ?>
<footer></footer>

Ella van Durpe
Home · Notes · Photos · About · Contact

Article
     Title
     Content
     Navigation

Sidebar
     Search
     Latest

Comments
Footer

WordPress

Democratise publishing

100+ languages
38 million active installs

@ellatrx

automattic.com/work-with-us

Resources

Why ContentEditable is Terrible by Nick Santos
We Called it Gutenberg for a Reason by Matt Mullenweg
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