
Pell – A simple and small rich-text editor for the web - thmslee
https://github.com/jaredreich/pell
======
marijn
Nonsense, I've written a much smaller one: `function tinyEditor(element) {
element.contentEditable = true }`

That, plus a few crude buttons, is all this does. As several other comments
point out, there's good reasons why real WYSIWYG packages are bigger—the user
experience of working with a plain contentEditable element is still terrible,
the output HTML still a complete mess. If you don't care much about that, you
don't need an editor component, since setting an attribute and wiring up some
buttons to call `execCommand` is easy enough to do from scratch.

Disclaimer: I work on one of those 'bloated' editors,
[http://prosemirror.net](http://prosemirror.net) , and find it a little
annoying when someone implies their crude afternoon hack is somehow equivalent
and we're crazy for putting in all that effort.

~~~
jaredreich
The last thing I want for notable developers of high quality WYSIWYG editors
is to get upset. Take this with a grain of salt. Continue doing the great
things you do with ProseMirror and your other valuable open source
contributions. But don't get upset. Try getting inspired, to move with the
times, to trust browsers more, to make YOUR projects smaller, lighter, and
easier to use.

P.S. Just because something is small, doesn't mean it's a crude afternoon hack
:)

~~~
krat0sprakhar
> The last thing I want for notable developers of high quality WYSIWYG editors
> is to get upset.

While I'm certain you have good intentions, the size comparison chart at the
top of the README is a bit misleading. It would be fair to list out the trade-
offs on going ahead with ContentEditable so that users can know what they are
getting if they choose Pell.

To clarify, Pell looks awesome and I don't intend to diss on your project or
your hard work, just that the way the project's README is laid out I feel
@marijn's response is not totally unwarranted.

------
Tade0
As a person who used to work for a company developing one of the more popular
in-browser text editors I can tell you that all that "bloat" is there so that
you'll get consistent results across browsers.

Unfortunately there's no way around this short of not using contenteditable -
which is even worse sometimes.

Most editors feature customized builds which let you reduce the footprint of
the editor. If you're looking for quick gains first and foremost disable
support for pasting from other applications, e.g. MS Word. It's always a major
feature.

~~~
roryisok
sometimes, you can be sure of the browser / rendering engine ahead of time,
and you don't _need_ all that "bloat".

For instance, react-native, electron or windows store apps.

~~~
Tade0
In these cases you'd have to freeze the version of every layer beneath the
editor(browser/env, OS and so on), otherwise any regression in these layers is
going to break your app.

But if you decide to freeze you run the risk of exposing your users to
security issues.

~~~
jchw
I doubt this? contenteditable is pretty stable in Chrome/WebKit.

~~~
Tade0
I don't know - you tell me.

Anyway we had our share of trouble with a customer due to an exotic rendering
issue that occurred in two consecutive versions of Chrome and then
disappeared, so yeah.

~~~
jchw
Sure, but that happens. We hit an insane performance problem related to Chrome
and some weird combination of CSS that disappeared in a similar number of
versions.

I'd say it's the exception and not the rule, though.

------
anilgulecha
This is cool :)

That said (and not to take thunder away from your page), this is possible
because the HTML spec itself allows for any element to be made into a
"WYSIWYG" editor by adding the "contenteditable" attribute.

What most other larger editors are doing is working around some of the
horrendous non-standardized versions of execCommand which varies across
browsers.

Ideally a web standards body should come out with a <input type="richtext">
element, which is controlled through a sane API, and the spec spelled out to
support everything by default. And get rid of the bane that is rich text
editing on the web.

~~~
simias
Wouldn't it make more sense to just add a standard API to invoke an external
editor instead of yet again reinventing the wheel? It might be more
interesting to standardize a certain type of rich text markup that could then
be produced and consumed by a variety of software, both online and off.

There are web extensions that let you do that but it's often a bit clumsy I
found, so I just tend to edit my text in Emacs and then copy/paste it in the
box.

Regular <textarea> editing on the web is not generally a pleasant experience
(I just had to grab my mouse to extend the comment area so that I can actually
see what I'm typing) but rich text "WISIWIG" editors are even worse because
the edition shortcuts always intersect somewhat with the regular browser
shortcuts (sometimes in fun and interesting ways), they're slow and generally
simply not up to par with stand alone editors.

Why does everything need to be in the browser? It's a complete anti-pattern as
far as I'm concerned. Emacs is often mocked as the "emacs OS" because of how
extensible it is but generally this is done by calling external programs, not
reimplementing everything in elisp from scratch.

~~~
_wmd
98% of the difficulty in implementing a rich text editor is already present in
every browser, its hard to call it wheel reinvention at that point. Drawing a
caret and responding to key presses by mutating the dom is about the only
thing left

~~~
simias
IMO actually displaying text is not the big challenge in a text editor.

The tricky part is the user interface, text transformation (sed, query-and-
replace, pipe through external programs...), text parsing (for syntax
highlighting and code folding for instance) and invoking external
applications, for instance to compile code or post-process your document. Web
browsers are not particularly good at any of these things since they're not
needed to purely "browse" the web.

If you want performance while handling big files you also need to optimize the
way you stream data from the disk, something browsers are terrible at. Is
there any web-technology-based editor that handles big files decently? Last
time I've seen a benchmark it was pretty abysmal. Not that Emacs is great at
it (it was pretty bad for a long time actually, especially pre-64bit
computers) but it still was orders of magnitude faster than Atom for instance:
[https://github.com/jhallen/joes-
sandbox/tree/master/editor-p...](https://github.com/jhallen/joes-
sandbox/tree/master/editor-perf)

~~~
_wmd
Accurately rendering text in an WYSIWYG HTML editor has equivalent difficulty
to implementing the engine used in the web browser that will eventually be
used to render that HTML, otherwise it can never truly be WYSIWYG

~~~
simias
That's fair, I'm obviously biased by my general loathing of WYSIWYG editors
but clearly I'm in the minority here. I guess when I think about text editors
I think mainly of code editors.

~~~
roryisok
I bet you like your syntax highlighted though

------
jaredreich
Hi everyone, author of pell.js here, thanks for all the positive AND critical
feedback. Hey, this is Hacker News, how boring would it be if everyone's
comment was just "Cool" or "Good job"? I love hearing the gripes and
individualized complaints of smart people that have worked on similar (and
much larger) projects.

I'd like to mention a few things about pell.js and it's goals:

\- It was not made to be the most full-featured editor out there

\- It was not made to fight with or worry about browser inconsistencies
(browsers are converging, quickly too)

\- It was made to demonstrate the underlying simplicity of something that
looks like magic to most beginner developers (including myself) and to teach
people how to use `contentEditable` and `execCommand` via a tiny, extremely
readable codebase

\- It was made for people who need just a basic WYSIWYG editor in their
app/site/whatever and who care about bundle size (PWA's anyone?)

Over time, many of the inconsistencies and issues will get fixed or
implemented in pell, but the goal of remaining tiny yet functional will always
remain paramount.

~~~
Afraithe
Don't expect the browser vendors to fix contentEditable or inconsistencies for
you, this has been the struggle of WYSIWYG editors for as long as they have
existed and it really hasn't gotten a whole lot better. You will quickly find
out that by the time your getting close to fix those inconsistencies, 4-6
years have passed and your right up there with the rest of the editors in
terms of size and complexity.

PS: Also working on one of those bloaty editors.

~~~
jaredreich
I will most definitely expect browser vendors to perform these fixes. I think
you've fallen behind on what's taking place in the browser world right now, a
huge percentage of users are on evergreen webkit browsers (and increasing
rapidly). The next 4-6 years of web will NOT look like the last 4-6 years of
web. And this doesn't even account for bundled browser implementations
(electron, etc.)

~~~
marijn
And those evergreen browsers are still doing terrible things when it comes to
contentEditable, and they don't really have a lot of choice, because it's an
underspecified poorly conceptualized idea that really doesn't leave them much
room to things right. There's some work happening on the W3C editing taskforce
to improve the concepts involved, but that's also moving at a glacial pace,
and having to struggle with browser vendors at every steps.

So again, don't suggest we (editor implementors) are clueless or behind the
times. We happen to have spent quite a bit of time on this stuff. We know it.

~~~
jaredreich
Again, you are getting offended. Not once did I suggest editor implementors
are clueless. They're likely some of the best and sharpest developers out
there. Please, as I mentioned earlier, take this project with a grain of salt.

By "fallen behind" I meant still making the assumption that many users are
still using outdated browsers. This is not the case anymore, especially in the
last year. And because of this fact, many WYSIWYG editors might be
implementing a lot of cross-platform bloat that just isn't necessary any more.
Rather than raging, perhaps browse through the ProseMirror source and see what
you can remove as "obsolete" code.

~~~
marijn
ProseMirror was started 2 years ago, initially only targeted evergreen
browser, and has recently grudgingly added support for IE11 because customers
asked for it. But yeah, I guess for some parts of some of the older projects
this may apply.

------
notzorbo3
It's great that it's small, but it suffers from the same horrible interactions
that most other web editors also suffer from.

Try quoting the last paragraph in the editor. It's now impossible to ever
escape from the quote. All new text at the bottom stays "quoted".

From a cursory test of the editor, it suffers from basically all the issues
that contenteditable suffers from.

The reason other editors are so big is because the take editing behaviour into
account.

~~~
Veedrac
Works for me in Chrome 60. Just return twice, like a normal editor.

~~~
c-smile
Try to insert text between two tables: <table>...</table><table>...</table>
...

That's the same problem.

At the moment caret positions in browsers are limited only by char-positions.
There are no carets in between box blocks.

Yet consider my question on SO :
[https://ux.stackexchange.com/questions/72309/caret-
positioni...](https://ux.stackexchange.com/questions/72309/caret-positioning-
in-html-richtext-wysiwyg-editor)

------
betageek
Also the editor that will output the most inconsistent HTML across browsers.
There's a reason all those other editors try and fix contenteditable (and are
therefore > 1k), for more info see [https://medium.engineering/why-
contenteditable-is-terrible-1...](https://medium.engineering/why-
contenteditable-is-terrible-122d8a40e480)

------
jwr
Every time I see a new WYSIWYG text editor, I wonder: do people really need to
set single words in bold, italic, underline, and strike-through?

I feel like this is a leftover of the old times, back when first WYSIWYG
editors appeared and these capabilities were impressive. I think these days
what one needs is not bold/italic, but facilities for editing structure,
inserting links, and positioning images, all according to a style template.

~~~
roryisok
Depends on your use-case I suppose. That's why most of these editors are
customisable. When writing posts on SO, I've used bold, italic, and strike-
through in the same post.

In every day usage, bold/underline/strike may be superfluous, but I would
argue that italics are _essential_. Without at least the ability to emphasise
a word in some way, your only option is uppercase.

------
codebeaker
I'm surprised to see no mention of the Trix editor here amongst the comments
about how contentEditable is the root of all evil. Trix has a nice solution,
from their readme:

    
    
      Trix sidesteps these inconsistencies by 
      treating contenteditable as an I/O devi-
      ice: when input makes its way to the ed-
      itor, Trix converts that input into an 
      editing operation on its internal docum-
      ent model, then re-renders that document
      back into the editor. This gives Trix 
      complete control over what happens after
      every keystroke, and avoids the need to 
      use execCommand at all.
    

Trix is from basecamp, and has a super healthy plugin/extension ecosystem -
[https://github.com/basecamp/trix](https://github.com/basecamp/trix)

Full disclosure: not affiliated at all, but the rare times I need a WYSIWYG
editor I tend to look for Trix and be very pleased.

~~~
dbbk
I've been using Mobiledoc lately which also follows this model, and it feels
like the right way to go for me. Fighting against contenteditable is a never-
ending uphill battle.

------
oblio
This is still relevant: [https://www.joelonsoftware.com/2003/08/01/rick-
chapman-is-in...](https://www.joelonsoftware.com/2003/08/01/rick-chapman-is-
in-search-of-stupidity/)

> When Pepsi-pusher John Sculley was developing the Apple Newton, he didn’t
> know something that every computer science major in the country knows:
> handwriting recognition is not possible. This was at the same time that Bill
> Gates was hauling programmers into meetings begging them to create a single
> rich text edit control that could be reused in all their products. Put Jim
> Manzi (the suit who let the MBAs take over Lotus) in that meeting and he
> would be staring blankly. “What’s a rich text edit control?” It never would
> have occurred to him to take technological leadership because he didn’t grok
> the technology; in fact, the very use of the word grok in that sentence
> would probably throw him off.

My point: Microsoft has identified and satisfied this need 20 years ago.
Although I'm a big supporter of the Open Web and open systems in general,
sometimes I do long for a bit of dictatorship to get things done. But then I
come to my senses :p

------
sheepy
TL;DR that is data:text/html,<div contenteditable> with buttons

------
StavrosK
As another alternative, I used SimpleMDE
([https://simplemde.com/](https://simplemde.com/)) for IPFessay
([https://gitlab.com/stavros/IPFessay](https://gitlab.com/stavros/IPFessay)),
and, while not this light, it's pretty good and featureful. It doesn't expose
all the features I'd like it to expose, but I'm quite satisfied by it.

~~~
roryisok
SimpleMDE looks great!

------
_ao789
1k does sound quite appealing. But: most of the time a WYSIWYG editor is
called is when in 'admin pages' where little to nobody gives a shit about page
load time. It's more about CRUD performing as expected.

~~~
djm_
>where little to nobody gives a shit about page load time.

If it has an end user that is not yourself, I can guarantee you they do care -
even if it's not a conscious realisation.

~~~
mattmanser
Depends on your target audience.

If it's 10 internal admin users on desktops, the only time they're going to
have to redownload the bundled js is when there's a change.

And if you're sensible you'll have multiple bundles, one of which will be a
bundle of rarely updated external libraries, including that editor. So once
every couple of months they have to wait an extra second or two for a page to
load.

Some of the internal apps I've written for clients have a core bundle that
almost never changes and then a js file almost per page (which each append a
hash of their contents to the URL to ensure efficient cache busting, managed
with an in memory cache of the hashes).

------
kronos29296
I am impressed by both the size and the features and no dependencies. Kinda
like a gui linux under 20 MB. People need to do such similar things instead of
a huge bloated single page web app with features that nobody want.

Great project.

~~~
yuchi
Sorry but it’s just using the standard _contenteditable_ attribute, which
works terribly, see [https://medium.engineering/why-contenteditable-is-
terrible-1...](https://medium.engineering/why-contenteditable-is-
terrible-122d8a40e480)

------
koehr
I actually started a simple WYSIWYG editor that doesn't use contentEditable
but instead a tiny subset of HTML and some virtual DOM like technology. Thanks
for this post. It makes me want to work more on it!

~~~
roryisok
I would be very interested in seeing that!

------
Ciantic
Copy & Pasting needs some work. Usually the biggest hurdle is people pasting
content from other pages and the editor can't sanitize it properly. This
doesn't appear to do any cleaning, which in practice never works because
regular people do not know how to use the plain pasting mechanism
(Ctrl+Shift+V instead of Ctrl+V).

------
manigandham
Side note - a list of other rich/html editors available today:
[https://gist.github.com/manigandham/65543a0bc2bf7006a487](https://gist.github.com/manigandham/65543a0bc2bf7006a487)

------
agentgt
I have always wanted a rich text editor where you could see the markdown as
well as the formatting it produces at the same time (and in the same edit
pane... ie not realtime rendering in a pane above).

That is if you typed:

    
    
        **blah**
    

It would show blah and still show the asterisk but in bold (apologies for
using code format but HN will strip the asterisks).

There are of course some editor plugins, and IDEs that do this but I haven't
seen one on the web.

EDIT Oh apparently there is stackedit (I hadn't googled in awhile).

~~~
roryisok
And simpleMDE, mentioned on this thread

------
oneeyedpigeon
Appears to fail my semantics test right off the bat. Type "Line one\nLine two"
results in:

    
    
        Line one
        <div>Line two</div>

~~~
kalleboo
Since it uses contenteditable, the result depends on your browser.

Firefox gives me

    
    
       Line one
       <br>
       Line two
       <br>

~~~
oneeyedpigeon
Yeah, I'm not convinced contenteditable is ready for primetime. In my
experience, pairing it with some javascript that cleans up the poor markup is
necessary.

------
fovc
What I really wish for is not a way to make textarea WYSIWYG, but a much
lighter way to add bold/italic/underline to text inputs, in such a way that I
can load lots of these in a single page. It sounds like I have a very niche
need, since I haven't found anything like this

------
dhosek
What I really want is a WYSIWYG/M editor which saves/reads from markdown. I
suspect that one or more of the various editors out there _can_ do it, but it
seems that all I can find are editors that will substitute the wysiwyg part
for MD rather than the HTML part.

~~~
jaredreich
Interesting. Filed an issue to track this idea:
[https://github.com/jaredreich/pell/issues/33](https://github.com/jaredreich/pell/issues/33)

------
sethammons
A tangent: does anyone have recommendations on a WYSIWYG editor that allows
easy math notation?

------
xchip
Fantastic, I was in fact wondering why other editors were so big. I love it!

~~~
detaro
I recommend reading the comments here on _why_ other editors are bigger.

------
mmerlin
Change the name. Cardinal George Pell is hopefully going to jail soon

------
kragen
You can't pell at that lutt. It's crenned with glauds.

------
h2onock
Looks great, less bloat on the Internet is what we all need.

------
superqwert
That min file could easily be minimised further....

------
erikb
Um, the simplest is a textbox and a send button.

------
chrismorgan
Just for the fun of it, I dove in and manually minified the code further,
without changing any semantics at all. With the following, I got it down from
2878 bytes to 2010 bytes which is a 30% saving:

    
    
      !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(e.pell={})}(this,function(e){"use strict";var t,n=Object,i=document,o=prompt,r="pell-",a="button",u="className",l="appendChild",d="createElement",c="insert",s="rderedList",f="Horizontal",p="formatBlock",m="Enter the ",b=n.assign||function(e,i,o,r){for(i=arguments,t=1;t<i.length;t++)for(r in o=i[t])n.prototype.hasOwnProperty.call(o,r)&&(e[r]=o[r]);return e},g=function(e,t,n){return{icon:e,title:t,result:n}},h=function(e,t){return i.execCommand.bind(i,e,!1,t)},k=function(e){return/^https?:\/\//.test(e)?e:"http://"+e},L={bold:g("<b>B</b>","Bold",h("bold")),italic:g("<i>I</i>","Italic",h("italic")),underline:g("<u>U</u>","Underline",h("underline")),strikethrough:g("<s>S</s>","Strike-through",h("strikeThrough")),heading1:g("<b>H<sub>1</sub></b>","Heading 1",h(p,"<H1>")),heading2:g("<b>H<sub>2</sub></b>","Heading 2",h(p,"<H2>")),paragraph:g("¶","Paragraph",h(p,"<P>")),quote:g("“ ”","Quote",h(p,"<BLOCKQUOTE>")),olist:g("#","Ordered List",h(c+"O"+s)),ulist:g("•","Unordered List",h(c+"Uno"+s)),code:g("&lt;/&gt;","Code",h(p,"<PRE>")),line:g("―",f+" Line",h(c+f+"Rule","<PRE>")),link:g("","Link",function(){(t=o(m+"link URL"))&&h("createLink",k(t))}),image:g("","Image",function(){(t=o(m+"image URL"))&&h(c+"Image",k(t))}),undo:g("↺","Undo",h("undo")),redo:g("↻","Redo",h("redo"))};e["default"]={init:e.init=function(e){var o=e.classes,c=e.actions,s=i.getElementById(e.root),f=i[d]("div"),p=i[d]("div");p.contentEditable=!0,f[u]=o.actionbar||r+"actionbar",p[u]=o.editor||r+"editor",p.oninput=function(t){return e.onChange&&e.onChange(t.target.innerHTML)},s[l](f),s[l](p),(c?c.map(function(e){return"string"==typeof e?L[e]:b({},L[e.name],e)}):n.keys(L).map(function(e){return L[e]})).forEach(function(e){t=i[d](a),t[u]=o.button||r+a,t.innerHTML=e.icon,t.title=e.title,t.onclick=e.result,f[l](t)})}},n.defineProperty(e,"__esModule",{value:!0})})
    

However, when you consider gzipping, this represents savings of roughly 12–16
bytes (it depends a little on whether the files are noeol and whether you
avoid file metadata going in the gzip stream—pro tip, make your gzipped files
smaller with `gzip < x > x.gz` instead of `gzip x`). Quite a few of the latter
“save another one or two bytes” tricks that I employed not only increase
runtime trivially (e.g. concatenating two string literals instead of using one
string literal), but they also increased gzip size by four or more bytes. (The
tricks for the strings “Enter the ”, “Horizontal”, “rderedList” and “insert”
had saved seven bytes ungzipped at the cost of about 21 bytes gzipped, and
“pell-” and “button” had saved one byte at the cost of eleven gzipped.) The
lesson there is—gzip is pretty good, and deduplication is normally a waste of
time in tiny files! I was hoping to get it under 2048 bytes raw and 1024 bytes
gzipped; I achieved 2048 bytes raw, but after undoing some of the silly tricks
gzipped is still 60 bytes off.

Of course, if you decide to abandon AMD/CommonJS support, you can quickly whip
210 bytes (100 gzipped) off, but that’s a change in semantics so I can’t count
that despite it getting it under 1000 bytes.

~~~
chrismorgan
And the really fun thing? Just write the HTML that it would have written
directly, and the result is also under 2KB, this time ~585 bytes gzipped, and
with _the same functionality_ (though as written here `onChange` is kind of a
global now). It looks like this (with line breaks added):

    
    
      <div class=pell-actionbar
      ><button class=pell-button title=Bold onclick="document.execCommand('bold',!1)"><b>B</b></button
      ><button class=pell-button title=Italic onclick="document.execCommand('italic',!1)"><i>I</i></button
      ><button class=pell-button title=Underline onclick="document.execCommand('underline',!1)"><u>U</u></button
      ><button class=pell-button title=Strike-through onclick="document.execCommand('strikeThrough',!1)"><s>S</s></button
      ><button class=pell-button title="Heading 1" onclick="document.execCommand('formatBlock',!1,'<H1>')"><b>H<sub>1</sub></b></button
      ><button class=pell-button title="Heading 2" onclick="document.execCommand('formatBlock',!1,'<H2>')"><b>H<sub>2</sub></b></button
      ><button class=pell-button title=Paragraph onclick="document.execCommand('formatBlock',!1,'<P>')">¶</button
      ><button class=pell-button title=Quote onclick="document.execCommand('formatBlock',!1,'<BLOCKQUOTE>')">“ ”</button
      ><button class=pell-button title="Ordered List" onclick="document.execCommand('insertOrderedList',!1)">#</button
      ><button class=pell-button title="Unordered List" onclick="document.execCommand('insertUnorderedList',!1)">•</button
      ><button class=pell-button title=Code onclick="document.execCommand('formatBlock',!1,'<PRE>')">&lt;/&gt;</button
      ><button class=pell-button title="Horizontal Line" onclick="document.execCommand('insertHorizontalRule',!1,'<PRE>')">―</button
      ><button class=pell-button title=Link onclick="var s=prompt('Enter the link URL');s&&document.execCommand('createLink',!1,/^https?:\/\//.test(s)?s:'http://'+s)"></button
      ><button class=pell-button title=Image onclick="var s=prompt('Enter the image URL'));s&&document.execCommand('insertImage',!1,/^https?:\/\//.test(s)?s:'http://'+s)"></button
      ><button class=pell-button title=Undo onclick="document.execCommand('undo',!1)">↺</button
      ><button class=pell-button title=Redo onclick="document.execCommand('redo',!1)">↻</button
      ></div
      ><div class=pell-editor contenteditable oninput="typeof onChange=='undefined'||onChange(event.target.innerHTML)"></div>

