14-day Cloud trial
Start today. For free.

One editor. 50+ features. Zero constraints. After your trial, retain the advanced features.

Try Professional Plan for FREE
PricingContact Us
Log InGet Started Free

Developer insights

Dangerous examples of technical debt in rich text editors

Published December 19th, 2022

 19 min read

In an ideal world, the technical debt in your project is intentional and controllable. But rich text editors are complex beasts that exist in an ever-changing environment – which means one of the biggest dangers to rich text editor development is environmental tech debt.

Millie Macdonald

Product Manager at Halo Connect

Many modern software projects rely on numerous external dependencies – libraries, frameworks, and other tools that make development easier. Usually though, you have a degree of control over those dependencies.

Rich text editors aren’t so lucky.

Rich text editors aren’t standalone applications

A rich text editor by itself isn’t very useful – it has to be used within the context of another application. That means it has to be compatible with that application – or multiple applications, depending on how it’s used – and be able to adapt to outside changes.

The rich text editor environment is complex

A rich text editor needs to support numerous browser and operating system (OS) combinations. But there are dozens of combinations, and both browsers and OSes constantly change, which makes for a very complex environment.

Rich text editors are at the mercy of many standards and specifications

Security. Privacy. Even just the HTML specification. Rich text editors have to support, work with, implement, and comply with a wide range of standards and specifications – all of which restrict some features and require others.

Staying on top of all these external factors isn’t simple.

You have to know what to monitor, how to monitor it, and how to assess modification news for its impact on your rich text editor. It requires dedication, domain knowledge, and significant time investment.

Because if you don’t do that, you’re risking the accrual of significant environmental tech debt.

What is environmental tech debt?

Programmer Ward Cunningham originated the technical debt metaphor, in his 1992 article. A Google search uncovers many types of tech debt that have since been defined – especially seeing there's no rigid lines of delineation between what is and what isn’t considered tech debt.

Three key examples of technical debt that affect a rich text editor (RTE) are:

  • Environmental tech debt is technical debt that accumulates not because of anything you do, but because of changes in the surrounding environment. Splunk goes on to say that “Failure to keep up with these changes will inevitably result in an application that no longer functions properly, and like any other form of tech debt, it is a problem that gets worse over time.”
  • Intentional tech debt is technical debt that you’ve chosen to take on after weighing the pros and cons. Defined in 2007 by Steve McConnell, he suggested that intentional technical debt is debt that’s taken on consciously as a strategic tool.
  • Unintentional tech debt is tech debt you don’t realize you’re choosing, often due to time constraints or a lack of knowledge. This type of tech debt is usually caused by internal factors and accrues while adding features, or because an aging codebase has started to accumulate cruft. In Steve McConnell’s words, he called it “the non-strategic result of doing a poor job.”


Following McConnell’s definition of intentional and unintentional tech debt, Martin Fowler took McConnell’s concept a step further and published what he calls the “Technical Debt Quadrant.

Each quadrant carries different opportunity costs and trade-offs, and seemingly small decisions can have big consequences.

However, environmental tech debt differs from both intentional and unintentional debt, because you have no control over the timing, frequency or rationale behind the changes forced on your codebase. All you can control is the speed of response and level of domain expertise you apply to the issues.

No new features, yet tech debt still accrues

A rich text editor is inherently a very complicated application that accrues technical debt of its own accord, very easily. However, they also exist in a very complex environment.

There’s a lengthy list of external factors that make rich text editors prone to accumulating environmental tech debt, simply by the very fact of them existing and functioning. For a rich text editor, the source of just a few of the many potentially dangerous examples of tech debt include:

  • Browser and OS changes
  • HTML, CSS, and JavaScript specification and implementation changes
  • Changes to accessibility standards (e.g. WCAG and ARIA)
  • Changes to accessibility tools (such as screen readers like Jaws)
  • New security exploits, and changes to security standards (e.g. OWASP’s annual Top 10)
  • Privacy standard changes (e.g. GDPR and SOC2)

Changes to any one (or all) of these factors likely requires your rich text editor to adapt. Often, each of these sources has its own inherent limitations and issues (i.e the cruft in the HTML specification – see Tech Debt Example 2) which you also need to work around.

For each and every environmental change and problem, there’s a decision to make: do you invest the time to deal with it, or do you take it on as environmental tech debt?

And, that’s just for the environmental issues you know about – if you miss the news about a change or don’t have the domain knowledge to spot a problem, you can get slammed by environmental tech debt with no warning. And it's well known you never knowingly accrue more technical debt (let alone unknown technical debt) that you have to pay off.

To more clearly expose the potential dangers lurking in your rich text editor, here’s a few examples of tech debt that have had major consequences.

Get more insights in our
Technical Debt White Paper


Tech debt example 1

User environment changes

To behave correctly, a rich text editor has to account for the environment it runs in:

  • The browser
  • The operating system, and
  • The device/s its users use.

However, browsers update constantly. Operating systems change in significant ways, overnight. And different device types can have very different needs and behaviors.

It’s difficult to develop a rich text editor that accounts for all these complications, as well as the multiple environments that constantly change… unless you have deep domain knowledge of rich text editors and their idiosyncrasies.

There’s worse news. Keeping track of all the changes that can potentially cause you to accrue environmental tech debt, is sometimes even harder than finding it all.

Rich text editor tech debt example: Chrome User Agent changes

One complication that ensues from functioning within so many environments, is that the creation and maintenance of a great user experience (UX), sometimes requires environment-specific code. For example, customizing shortcuts for MacOS and Windows, or switching mouse clicks for touch gestures on phones and tablets. Or even fixing browser-specific bugs with code that only runs on that browser.

One way to differentiate environments is by using the browser’s User Agent string. However, this browser feature is under heavy debate, and has been for quite some years.

 Customisation vs end-user privacy

Unfortunately, the same features that make the User Agent string great for UX, also make it bad for privacy – because it can be used by bad actors to grab end-user data without their knowledge. This has led to far reaching discussions within the engineering community, about restricting or even replacing the User Agent string.

read MORE

User agents are a complicated topic

This MDN article about browser detection using the user agent explains what user agents can and can’t be used for, and the privacy risks inherent to user agents.

User Agent string example on various browsers

 The Chrome User Agent saga

Some parts of the User Agent string have already been frozen, resulting in Windows 11 and MacOS Big Sur onwards being reported as previous OS versions. Whereas MDN already recommends using feature detection and other methods instead of the User Agent string. But one of the most controversial and debated changes has been Chrome's User Agent Client Hints API.

In January 2020, Chrome announced a plan to freeze and deprecate the User Agent string and replace it with the User Agent Client Hints (UA-CH) API. Compared to the User Agent string – which makes a lot of data easily accessible – UA-CH would only provide specific information to websites, if they requested it, and only over a secure connection.

This would be a great step forward for privacy.

However, other browsers haven’t adopted UA-CH, and there are many concerns about whether UA-CH is a sufficiently strong enough replacement for the User Agent string. There are also concerns about how much development work is required to adjust to using UA-CH.

To their credit, Chrome has delayed and changed their plans several times in response to feedback. Unfortunately, this has created uncertainty around what changes will happen, and when.

Across the world, software companies are keeping a close eye on Chrome’s announcements.

And given the work required to adjust, decisions have had to be made about whether to change code ahead of time, or wait until change is a requirement. In other words, engineering teams everywhere are deciding whether to add the User Agent string to their pile of intentional technical debt that’s accumulating, or whether to pay it down.

However, browser changes aren't the only problem. The opposite can be just as bad, too.

Tech debt example 2

Backwards compatibility in the HTML specification

At first glance, tables might seem like a simple concept. However, in reality, working with HTML tables is very difficult – especially in rich text editors.

The HTML specification for tables has changed a lot since tables were first added in HTML 3.2. However, in order to not break old websites that are using old features, browsers tend to support both the new features and the old ones.

This makes HTML tables a nightmare of cruft and tech debt – and rich text editors potentially have to implement and support the entire resulting mess.

The infamous XKCD comic regarding standards proliferation, from https://xkcd.com/927/

Rich text editor tech debt example: RTE table complexities

Table support is one of the most complicated pieces of the TinyMCE codebase. It spans several libraries and modules, including:

  • The Advanced Tables premium plugin repository, which implements advanced features like sorting
  • The Tables plugin module, which implements basic features like styling and adding rows and columns
  • The Snooker module, which handles manipulating table HTML for the plugin features
  • The Darwin module, which handles selection in tables
  • The DOM Table Model, which adds basic table support to the TinyMCE core editor
  • Several more libraries and modules which are shared with other parts of TinyMCE core editor

A lot of the complexity in TinyMCE’s table code is caused by having to absorb and handle the environmental tech debt inherent in the HTML specification for tables, and the way the various browsers implement it. Why bother to do that? Because otherwise bad things happen.

Put simply, unless you ensure the table HTML can be absorbed, your whole rich text editor breaks when a user copy-pastes content from anywhere, into the table.

However, to handle the HTML specifications, there’s only two alternatives: add explicit support for it, or do the absolute minimum to prevent the editor breaking… and assign any further support to your tech debt pile.

But remember… for every feature you do support for the HTML specifications, your code complexity grows, again making the code more prone to accruing tech debt. It’s almost a no-win situation for rich text editors.

Let’s look at two examples of technical debt in TinyMCE’s table code.

 Small table changes = big table problems

The modularisation of TinyMCE’s table code usually makes development easier by isolating code for specific functionality into specific places. However, it doesn’t completely remove the risk of changes in one library, causing ripples across the entire dependency tree.

For example, a bug fix in the Snooker module might require changes to every other library. While a new feature in the Advanced Tables premium plugin might require cascading changes all the way down to the DOM Table Model.

This makes it easy to accrue unintentional tech debt, if you miss seeing the side-effect of a change made. And, if a fix or feature snowballs because of the ripple effect, you may well have to choose between technical debt or meeting your launch deadline.

The only real way to mitigate these issues is tapping into the deep domain knowledge of rich text editor specialists, like TinyMCE, and accessing their inhouse developer expertise.

 Big table codebase = big table mess

Complex code tends to breed cruft, code rot, and tech debt, and TinyMCE’s table code isn’t immune. Bug fixes are fine, but occasionally, implementing new features can hit roadblocks. And sometimes, all the future-proofing and good design you’ve done can’t save you from needing to just rewrite the code.

For example, Advanced Tables (premium) was originally designed to only enable table sorting. It was well-designed, but a bit rushed and very focused. This caused issues when adding new features, due to how different the new features were, from sorting. In the end, it was more efficient to replace large amounts of the original code than to try to fit the new features into the old code.

The 3-year Aggregate Decay in an Advanced Tables plugin Individual commits in a repo, by yearly cohorts, across 3 years

The half-life of code in the Advanced Tables repository. In the three years since it was created, over 80% of its code has already been replaced.

If HTML tables weren’t so complicated, or browsers could support only the newest table features without breaking half the internet, this likely wouldn’t have been necessary. But that’s not possible, and it’s not unique to rich text editor’s table features and plugins.

It applies to many aspects of rich text editors and why their code half-life is so short.

You may be tempted to think that tables are fairly low risk, if you decide to relegate any improvements to your ever growing list of technical debt. But other aspects of rich text editors are much more dangerous. They need attention. Now.

read MORE

Is your code’s half-life this short?

Is your code half-life shorter than your engineering career

Tech debt example 3

Rich text editor security attacks and exposure

Privacy and security are always a key concern when handling user input. In a plain text form, the ways to mitigate the usual risks are well known and documented. However, rich text editors are much rarer, and much more complicated.

Security attacks can target the editor itself, the application it’s embedded in, the environment in which it’s running, or the server where the editor content is eventually saved.

XSS attacks, DOM clobbering, JavaScript prototype pollution and structural damage to the HTML are all attack types you have to mitigate. Every rich text editor feature you add, has to be checked for privacy violations. And on top of all that, there are security and privacy standards that need to be met, such as SOC2.

What is SOC2?

Paraphrasing Secureframe, a SOC2 audit looks at how a company handles user data with regards to its security, availability, processing integrity, confidentiality, and privacy.

Many big software companies, such as Google and Atlassian, as well as open source maintainers like Tidelift, publicize their SOC2 attainment and results.

There’s a lot to manage, with rich text editor security:

  • Defending against attack vectors
  • Protecting your users’ privacy
  • Meeting the relevant standards.

All that takes time and domain expertise in rich text editors. And it isn’t a one-off problem. New vulnerabilities are constantly being found. New attacks are constantly being reported. Privacy standards are constantly changing. It doesn't ever end.

For rich text editors, it’s never-ending work, and relegating tasks to the tech debt ‘fix later’ list can be dangerous, especially when it comes to security issues. Sometimes though, the really hard issues just have to be fixed.

Rich text editor tech debt example: DOM Parsing update in TinyMCE 6.0

HTML is a very flexible markup language, and that means it has hundreds if not thousands of security vulnerabilities. Both CSS and JavaScript also have their own plethora of issues.

A HTML-based rich text editor has to handle all these vulnerabilities.

The TinyMCE rich text editor does this by parsing and sanitizing every piece of content added to the editor – whether it comes from code, the clipboard, or a user typing something. Doing this without affecting the performance of the editor (or affecting other editor features) is a considerable mission.

That’s why TinyMCE recently switched its in-house DOM parser and sanitizer, for a third-party tool.

What is the OWASP Foundation?

The Open Web Application Security Project® (OWASP) is a nonprofit foundation and community that works to improve the security of software.

It conducts community-led open-source software projects, educational and training conferences, and produces freely-available articles, methodologies, documentation, tools, and technologies in the field of web application security.

 Build our own or buy it?

TinyMCE is an editor with heritage. For many years, handling the security of its content was something our engineers solely handled, because there were no third-party libraries available to use. Therefore, we reacted quickly when a new exploit was discovered, and easily customized the parsing and sanitizing to our needs.

However, it also required a lot of work.

Recent years have seen an increase in the number and complexity of known vulnerabilities. The domain knowledge required to ensure the security of a rich text editor has grown in relation to that, and the amount of code needed to mitigate all the potential attacks has exploded.

At the same time, industry standards have appeared, and seemingly stabilized. Whole new industries have grown up around software security and privacy, while security tools have improved by leaps and bounds.

In-house DOM ParserThird-party DOM Parser
ProsCan be easily customized, and quickly patched when new exploits are found.Maintenance overhead is passed to third-party developers.
ConsMaintenance costs grow as the age and complexity of the code increases.Reliance on a third-party to be responsive and maintain a high quality.

Switching to a third-party security solution was a difficult decision. As was finding the right tool and implementing the switch. However, it was necessary.

TinyMCE’s DOM parser was a big, complex piece of code that only a few developers understood, and working on it was fraught with complications and delays. Plus, the volume of maintenance and tech debt wasn’t sustainable, on top of every other moving part in the rich text editor and 50+ plugins.

However, not fixing security issues wasn’t an option. The risks associated with accumulating security tech debt are much too high.

In the end, switching to an industry-standard, third-party security solution that’s maintained by experts, was a win-win for everyone: Tiny spends more time on rich text editing – our area of expertise – and our users receive the high security standards they expect, and need.

 Protecting user privacy

The flip side of rich text editor security is privacy. While rich text editors mostly only deal with user input within the user’s browser, any data that’s collected from the editor or transferred elsewhere must follow privacy best practices. Otherwise, you’re liable for data breaches – whether that’s during data transfer or while it’s stored in your servers.

Similar to security, privacy is another aspect of rich text editor development, where taking on tech debt can be very risky.

Data management must be implemented right the first time – and it needs to be regularly maintained. Especially when new laws or standards are introduced, such as Europe’s GDPR.

For TinyMCE, one of our biggest privacy challenges came with the implementation of our Real-time Collaboration (RTC) premium plugin. By nature, RTC functionality requires user data to be transmitted over the internet, so that users can see what others are doing. Doing that securely, without overly impacting the plugin’s functionality was complex work, and required us to implement new features such as content encryption during transmission.

NOTE: From January 2023, TinyMCE no longer offers Real-Time Collaboration (RTC) for new customers. For Existing customers, we'll be in contact to discuss options. Please reach out to your Account Manager if you are a customer using RTC, and you have any questions about the plugin.

This was a case where technical debt needed to be carefully managed, to ensure its negative consequences didn’t exceed its advantages.

In the case of RTC, if we hadn’t put the work in to protect our users' privacy and data, and had instead relegated such measures to technical debt work to be scheduled, it would have resulted in unacceptable risks to users’ security and privacy.

Our goal has never been to reach zero tech debt. Because sometimes, some debt has been a good thing for our growth. Why’s that?

Ideally, a ‘Goldilocks level of tech debt’ is what you want to carry – not too much, not too little. Your tech debt management plan needs to balance growth aspirations and housekeeping duties, to ensure you’re continuing to deliver value at high speed, without sacrificing quality, security or privacy.

But there is another way to minimize your tech debt.

Reading resources

Atlassian’s data privacy guidelines are a great rundown of privacy best practices.

web.dev’s lesson on forms and privacy has several useful examples.

Firewall Times maintains a terrifying timeline of recent data breaches.

Easiest way to avoid technical debt, is buying RTE components

Cost drives much of today’s technology.

The typical cost of managing the technical debt generated by a rich text editor – and its advanced features – isn’t small. As you can see, even discussing the possibility of adding functionality or fixing a bug and then deciding not to do it, takes time.

And the more rework you have to do, the higher the price tag and opportunities lost.

By curating a repository of vetted, pre-approved components and release versions (open source, purchased and subscribed), you’re minimizing security exposures, ongoing maintenance and technical debt accumulation. The components can be safely used and reused within your tech stack, across the enterprise.

That allows your development work to quickly move, more safely, and avoids last-minute blockers during a development cycle.

Assembling pre-approved specialist components lets you safely walk the tightrope between technical debt and innovation. And it maximizes your opportunity cost.

Download the white paper

Opportunity Cost of Technical Debt: Minimize Your Rich Text Editor Development


Millie Macdonald

Product Manager at Halo Connect

Millie is a Product Manager at Halo Connect who dabbles in writing. Previously, she worked at Tiny as a Product Owner, dev, and QA engineer. She loves learning above all else, whether it's about people, tech, or leadership.

Related Articles

  • Developer InsightsMar 7th, 2024

    Understanding Uncaught TypeErrors in JavaScript

Join 100,000+ developers who get regular tips & updates from the Tiny team.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Tiny logo

Stay Connected

SOC2 compliance badge


© Copyright 2024 Tiny Technologies Inc.

TinyMCE® and Tiny® are registered trademarks of Tiny Technologies, Inc.