Swizec Teller - a geek with a hatswizec.com

Senior Mindset Book

Get promoted, earn a bigger salary, work for top companies

Senior Engineer Mindset cover
Learn more

    The unreasonable difficulty of adding a feature to a Textarea

    Here's a fun challenge for ya: Add Giphy support to GitHub comments. How hard can it be?

    Indeed, how hard can it be?

    psht giphy

    45min speedcoding challenge! That's how hard.

    All you need is a Chrome extension that injects a little input field next to each comment. Type search into input field, press Enter, talk to Giphy's API, add markdown to the textarea.

    Piece of cake.

    So on Monday I gave it a shot ...

    Click through for source
    Click through for source

    ... and failed miserably.

    Chrome extensions are easy in theory, but I wanted to use React for reasons. A different project where it makes more sense and this was a good excuse to figure it out.

    Well, it didn't work. It is nigh impossible to convince create-react-app to work as a Chrome Extension.

    Until I discovered react-chrome-extension. A boilerplate that comes with everything configured. Build steps, manifest files, full React support. It's wonderful 👌

    Attempt no. 2

    React problem resolve, surely this is gonna be a piece of cake now. Let's do this!

    Friday I tried again

    Click through for source
    Click through for source

    We wasted time drinking beer and shooting the shit about San Francisco, Silicon Valley, and some recent career news on my end (more on that later). Would you say SF is fancy? It's covered in poop, but also seeing a Porsche is so common you don't even notice anymore 🤔

    But giphs-for-github worked!

    Well ... the operation was a success but the patient died. Oops.

    The Giphy part

    Finding a giph was easy. Giphy's API is great and React Hooks make building small forms a breeze.

    Click through for source
    Click through for source

    A single <Giphys> component.

    1. Render a form with an input element
    2. Use a search state
    3. Run setSearch on change events
    4. Call findGiphy on submit and prevent default
    5. Use giphy-api to run a search query
    6. Take the first result
    7. Insert into textarea

    Rendering this next to every textarea is a matter of some classic DOM manipulation. Find all textareas, inject an element in their parent.

    Click through for source
    Click through for source

    Works great 👌

    So why does it break the textarea?

    Attempt no. 3

    The most obvious way to add content to a textarea using JavaScript looks like this.

    Click through for source
    Click through for source

    target is our textarea node. Its value resides in the .value property and the DOM spec allows us to change it.

    Value is just a string so we += another string. Works.

    But GitHub's JavaScript framework freaks out. The Comment button doesn't become enabled, there's an error, and anything you type into the textarea triggers even more errors.

    Which brings us to Sunday when I tried to figure this out once and for all.

    Click through for source
    Click through for source

    That was ... fun? Confusing? I learned more than I ever wanted to know about keyboard events? 🤨

    Why is this so hard?

    The problem is two-fold:

    1. Pressing Enter causes an error. GitHub's code picks up on the event and gets confused
    2. GitHub's framework is data-driven. Our shenanigans put reality out of sync with internal state and GitHub JS gets confused

    I don't know what they use, but you can imagine why it wouldn't like outsiders messing with things.

    Nothing a little change event can't fix.

    Click through for source
    Click through for source

    Nope.

    That's strange. How could a change event not make it work? Most frameworks use the onChange event ...

    But then you look at the list of events GitHub's textarea is listening for and wow that's a lot.

    svidZbN

    Maybe we need to replay the full keyboard interaction to make this work? Something crazy like this StackOverflow comment lists?

    Focus, keydown, beforeinput, keypress, input, change, keyup ... essentially replaying the whole sequence of events as if this were a real user interacting with the website.

    It didn't work.

    Not only didn't it work, the content didn't even show up. You still have to call textarea.value +=.

    We even tried faking the input event to make it look like a copy paste. Didn't work. Not even gonna show you the code.

    What about faking the textarea itself?

    The craziest idea was replacing the whole textarea with a textarea of our own. If you could unrender that one and make it listen to all the same DOM events as the original, that should be seamless, right?

    Unfortunately you can't get a list of event listeners for a DOM node.

    Yes Chrome lists them in dev tools. You can even use getEventListeners in Chrome console.

    svidZbN

    There's no way to get them in real code.

    foiled_again giphy

    Wisdom of the crowds to the rescue

    Out of options, out of ideas, I asked the internet for help.

    Click through for source
    Click through for source

    And the internet delivered! Thanks @_tarekdj

    Firing the change event was the right idea. I was just doing it wrong.

    Click through for source
    Click through for source
    Click through for source
    Click through for source

    Yay it works!

    Sure, the framework error is still there but we can fix that with a submit button instead of pressing Enter. I've tried, it worked.

    As long as it doesn't break functionality I'm okay with firing an error.

    What's more curious is why @_tarekdj's change event works and mine doesn't.

    A change event is not a change event

    Let's see, we've got two change events. One works, one doesn't

    Click through for source
    Click through for source

    We're creating a new Event as per MDN docs. It's the most basic of event objects that all the others build off of.

    The Event interface represents an event which takes place in the DOM.

    The Event Constructor creates an event object of a certain type. dispatchEvent fires it.

    Second argument is an EventInit dictionary with options. By default events are non-bubbling.

    That feels important 🤔

    Event bubbling is how events propagate up the hierarchy of DOM elements by the way. That's how a form knows to submit when you press Enter inside an input field 5 levels down.

    Click through for source
    Click through for source

    The working version also creates an event and dispatches it. Except it's using a more old school approach.

    Calls createEvent which has a shiny red banner saying we should be using event constructors instead. But it still creates an uninitialized event.

    Creates an event of the type specified. The returned object should be first initialized and can then be passed to EventTarget.dispatchEvent.

    The initEvent call initializes it.

    7vuC9hE

    That's not a good sign 😅

    What do those booleans we're passing in do? Here's the function signature

    Click through for source
    Click through for source

    🤔

    So it was all about bubbling! Let's try

    Click through for source
    Click through for source

    It works! 😱

    Well that was fun. Thanks for reading.

    Happy Monday ✌️,
    ~Swizec

    Published on July 15th, 2019 in Front End, Livecoding, Technical

    Did you enjoy this article?

    Continue reading about The unreasonable difficulty of adding a feature to a Textarea

    Semantically similar articles hand-picked by GPT-4

    Senior Mindset Book

    Get promoted, earn a bigger salary, work for top companies

    Learn more

    Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.

    Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.

    Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.

    Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev

    Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization

    Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections

    Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog

    Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com

    By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️

    Created by Swizec with ❤️