An open letter on "Decoupling content from presentation”

To whomever it may concern,

My name is Jaden, and I’ve partnered with Sanity to write an open letter about a somewhat controversial term in modern developer marketing: “decoupling content from presentation”.

This phrase has showed up in the marketing materials of just about every company in this space (yes, even Sanity). But the reason we’re feeling slightly uncomfortable about it is not because it’s a bad idea or because it’s misleading — it’s just rarely fully explained. Think about the phrase:

  • decoupling — This is a fairly technical word. We could just say “separating”, but decoupling feels slightly different, like we’re implying that not only are the content and the presentation in different places, they’re completely independent from one another. The phrase itself doesn’t answer the question, to what extent are these concerns separated?
  • content — What exactly counts as content? It’s hard to argue with a body of text being part of the content, but are the images? Even the decorative ones? What about the relationship of those images to the text next to them? Is that part of the “content”? What about where those images should be placed in relation to the text they’re connected to?
  • presentation — What exactly counts as presentation? While the opacity of your background image, codified in the CSS on your homepage, is most definitely presentation, is the image itself presentation? Its URL is stored in CSS, but it imparts some meaning to the site’s visitors. What about colors? Most color definitions are clearly presentation, but shades specific to company branding invoke meaning beyond simply making the site aesthetically pleasing. Surely they’re semantically meaningful, as well as fonts and layouts — generic ones are just tools for displaying content, custom ones are the content.

We’re trying to draw a line down a gradient here, splitting a fuzzy spectrum into distinct categories, and it doesn’t seem like there’s any winning. Take a look at an interview I did a while back with content expert Jeff Eaton; he makes a convincing argument that make have you start thinking of your custom company font as “content”. That doesn’t make the phrase “decoupling content from presentation” useless, though — it just means we need to clarify what the perplexing phrase means in spirit and what adopting it as a development mantra of sorts means in practice. Let’s dive into the answers to all of these questions in this open letter.

Why decouple?

Despite the murkiness around the details, decoupling content from presentation is a noble goal because it involves finding a sensible way to give everybody only the access they need. Designers get to work in fonts and colors, developers get to work in semantics and functionality, writers get to work in copy creation, and so on. Nobody intrudes on the job descriptions of their coworkers.

It’s similar to how a building might restrict access by key card:

My building diagram

In this poorly-drawn building, the white rooms are available to access by anyone, but the red and blue rooms are available to people with those specific credentials. Some of the rooms are allowed to both red credentials and blue credentials — when we stop focusing on where the dividing line is between the categories and reframe the problem as one of restricting access to certain rooms, this overlap becomes completely normal!

Applying this back to our mantra, we can have:

  • “white rooms” → code and tooling that everyone at the company (outside of our main two teams) can access if necessary
  • “red rooms” → code and tooling that only content professionals can access
  • “blue rooms” → code and tooling that only designers can access

And crucially, we can have “rooms”, or sections of our workflow, where both the content people and the presentation people can overlap. That answers our first question about what “decoupling” means in this context:

This also indirectly answers the other two questions we raised earlier, about what exactly defines content and what defines presentation.

If deciding branding colors and maintaining them across the entire project is in the job description of your UI Designer, then restrict access to the code or tooling where that data is defined to only that UI Designer.

Decoupling in practice

How do we actually go about implementing this?

Here’s an interesting analogy, first published 12 years ago on CSS Tricks by Chris Coyier:

You have a website with 100 pages on it. All 100 pages use the same style.css file. You’d like to change the background color of every single page. You make one adjustment in the CSS file, and that background color adjustment will be reflected across all 100 pages. You don’t need to edit each of those pages individually. That’s the core benefit behind CSS: abstracting the design away from the markup.

Now you want to make another change to those 100 pages. You’d like to include the publication date underneath the title of each of the pages. That is something you’ll need to edit the HTML to do. If those 100 pages are based on a template, as they would be when using a CMS (Content Management System), you can make one adjustment to the template file and the date adjustment will be reflected across all 100 pages. That’s the core benefit behind a CMS: abstracting the content away from the markup.

We’ve bolded the most important parts because they contain our lesson: there exist more than two concerns.

We’ve already identified a third here in Chris’ argument, since both content and presentation are abstracted out of the markup. That markup is a concern in and of itself, and it’s covered by a different job description in most agencies. Let’s start with an example piece of markup and see how we might apply this advice and work through our access restriction process:

<!DOCTYPE html>
<html>
    <head>
        <title>Sanity Blog</title>

        <style>
            * {
                font-family: Arial;
                padding: 0;
                margin: 0;
                outline: 0;
                border: 0;
            }

            body {
                background: #eee;
                display: flex;
                align-items: center;
                justify-content: center;
            }

            main {
                max-width: 800px;
                width: 100%;
            }

            nav {
                width: 100%;
                height: 10vh;
                background: #111;
                display: flex;
                justify-content: end;
                align-items: center;
            }

            nav > a {
                color: #eee;
                text-decoration: none;
                font-size: 4vh;
                padding: 3vh;
                cursor: pointer;
            }

            article {
                padding: 5vh;
            }

            article > * {
                margin: 5vh 0;
            }

            h1 {
                font-size: 8vh;
            }

            blockquote {
                padding-left: 10px;
                border-left: 5px solid green;
            }

            footer {
                width: 100%;
                height: 10vh;
                display: flex;
                flex-direction: column;
                justify-content: center;
                align-items: center;
            }
        </style>
    </head>

    <body>
        <main>
            <nav>
                <a>Home</a>
                <a>Another Place</a>
            </nav>

            <article id="article-container">
                <h1>Title of the Article</h1>

                <p>Some content content content</p>
                <blockquote>"Anyone can do any amount of work, provided it isn’t the work he is supposed to be doing at that moment."</blockquote>
                <p>— Robert Benchley, "How to Get Things Done: One Week in the Life of a Writing Man", Chicago Tribune, 2-2-1930</p>

                <p>I definitely wasn't procrastinating by googling quotes while writing this article</p>
            </article>

            <footer>
                <p>Made by Jaden Baptista in 2022</p>
                <small>Not that anybody else would claim this</small>
            </footer>
        </main>
    </body>
</html>

And this is what it looks like:

A screenshot of how the HTML code above renders in a browser.

This obviously not-production grade sample should do for our demonstration. Here’s where we begin the abstractions:

  1. First, we need to decide what is the “article” that the content professional will be editing. There’s an HTML tag for that, and luckily we’ve used it to encapsulate our article already.
  2. The second step is to pull the HTML of that article to somewhere our authors will be more comfortable. They probably would rather work in a CMS than in the code directly. Of course, I’m going to recommend Sanity here, but not just because they’re sponsoring this letter — I’ve actually been working with it a lot recently for other articles and I’m growing to really enjoy it. For this simple demonstration, I’m going to follow the ironic advice of one comment on that CSS Tricks article above, which stated: “Simplicity need not give way to complexity in situations where circumstances don’t warrant.” Let’s assume that whichever CMS we’ve chosen has outputted a Markdown file in our folder alongside the HTML. This is a great spot to use ShowdownJS, which can convert Markdown to HTML on the client side. That means adding the <script> tag to point to where Showdown is hosted on cdnjs, deleting everything inside the <article> tag, and adding this JavaScript to the end:

     const loadCSS = async (filename) => {
         let link = document.createElement("link");
         link.rel = "stylesheet";
         link.href = filename;
         document.head.appendChild(link);
     };
    
     const fillInPage = async () => {
         const converter = new showdown.Converter({metadata: true});
         const articleContainer = document.getElementById("article-container");
         const markdown = await (await fetch(`/article.md`)).text();
         const html = converter.makeHtml(markdown);
         const metadata = converter.getMetadata();
    
         articleContainer.innerHTML = html;
         document.title = metadata.title
             ? `${metadata.title} | Sanity Blog`
             : `Sanity Blog`;
         if (metadata.css) loadCSS(metadata.css);
     };
    
     fillInPage();
    
  3. The next step is isolating our presentation from the layout. I’m going to do that by creating two CSS files with the style rules from above — one for the main layout of the site, and one to deal with rendering markdown inside of that article container. That means replacing that long and unruly <style> tag with two <link>s to the relevant stylesheets.

  4. Depending on your point of view, we could be done. But in our fictional company, we have UX Designers who are responsible for the user’s entire flow through the site, focusing especially on the navigation components, so the navbar and footer fall under their explicit purview. To give them access to these components (and only them), We need to move the <nav> tag to its own file — nav.html — and giving it a companion CSS file with some nav-specific styles stolen from the base.css file; I’ll do the same with the footer too. Often our chosen framework will precompile the components into the layout at some point during the build-serve process, so to simulate this occasionally-complex step, I’ll use a very small static-site generator called XM to build our pages and import these components. By the time I put the <head> in a component too, linked in the new CSS files, stuck the JavaScript in its own place, and cleaned up some other things, my code has become far tidier:

     <!DOCTYPE html>
     <html>
         <import src="head.html"></import>
    
         <body>
             <main>
                 <import src="nav.html"></import>
                 <article id="article-container"></article>
                 <import src="footer.html"></import>
             </main>
    
             <script src="load-article.js"></script>
         </body>
     </html>
    

But let’s again step back and analyze what just happened. We’ve actually blown past “decoupling content from presentation”, going so far as to separate the article from UI from SEO from UX from functionality from markup. This is crucial in a company with a dedicated article author, UI designer, SEO expert, UX designer, JavaScript developer, and semantic markup writer. Now our UX designer doesn’t have to muddle through unrelated markup to track and improve the user’s flow from page to page, and our SEO expert doesn’t need to weed through JavaScript to find the <meta> tags. But this is still crucial for one-dev teams because that one developer is wearing a different hat at any moment. I regularly fill all of these roles, but never all at once, because I’ve isolated those tasks in my task management system. Perhaps I’ll work on SEO for the morning, finish my objective, and then put on my content creator hat to write my client a blog post. It can be very confusing and disorienting to switch headspaces like this… unless I’ve very clearly delineated those sections of work from each other. For the time that I’m working on a particular specialized task, I have the workflow (and therefore the productivity) of a specialist, all because of some relatively minor but far-reaching architectural changes.

That is what what “decoupling content from presentation” is getting at — fundamentally isolating every arena of development that the team manager saw as isolated enough to hire a specialist for. We’re making our “access control” reflect our taskboard, and by and large, we’re making our project architecture reflect our business architecture.

Wrapping up

Over the course of this article, you might’ve noticed that the theme seemed to drift a bit — that was intentional. We started out by breaking down the phrase “decoupling content from presentation”, but as we went along and investigated more, we started to discover that this is simply shorthand for a development philosophy that goes far beyond just those two concerns. We didn’t even take this idea as far as we could’ve — at its logical extreme, we’d wind up with microservices.

But the question behind all of this: why? Who cares?

Well, while it might feel like a difficult phrase to parse, it actually signifies that the one using it is promoting the separation of concerns that has proven time and time again to be the best application development strategy. With tools that focus on this method of architecture (like Sanity, whose website inspired this diatribe in the first place), we can build from the ground up like this. It doesn’t take extra time; it just takes a little foresight. So for your next big project, take my advice and give your tooling options a long think. You won’t regret picking hosts, site generators, databases, design tools, frameworks, and yes, even CMSs that prioritize decoupling content from presentation.