Web development is always changing. One trend in particular has become very popular lately, and it fundamentally goes against the conventional wisdom about how a web page should be made. It is exciting for some but frustrating for others, and the reasons for both are difficult to explain.
A web page is traditionally made up of three separate parts with separate responsibilities: HTML code defines the structure and meaning of the content on a page, CSS code defines its appearance, and JavaScript code defines its behavior. On teams with dedicated designers, HTML/CSS developers and JavaScript developers, this separation of concerns aligns nicely with job roles: Designers determine the visuals and user interactions on a page, HTML and CSS developers reproduce those visuals in a web browser, and JavaScript developers add the user interaction to tie it all together and “make it work.” People can work on one piece without getting involved with all three.
In recent years, JavaScript developers have realized that by defining a page’s structure in JavaScript instead of in HTML (using frameworks such as React), they can simplify the development and maintenance of user interaction code that is otherwise much more complex to build. Of course, when you tell someone that the HTML they wrote needs to be chopped up and mixed in with JavaScript they don’t know anything about, they can (understandably) become frustrated and start asking what the heck we’re getting out of this.
As a JavaScript developer on a cross-functional team, I get this question occasionally and I often have trouble answering it. All of the materials I’ve found on this topic are written for an audience that is already familiar with JavaScript — which is not terribly useful to those who focus on HTML and CSS. But this HTML-in-JS pattern (or something else that provides the same benefits) will likely be around for a while, so I think it’s an important thing that everyone involved in web development should understand.
This article will include code examples for those interested, but my goal is to explain this concept in a way that can be understood without them.
Background: HTML, CSS, and JavaScript
To broaden the audience of this article as much as possible, I want to give a quick background on the types of code involved in creating a web page and their traditional roles. If you have experience with these, you can skip ahead.
HTML is for structure and semantic meaning
HTML (HyperText Markup Language) code defines the structure and meaning of the content on a page. For example, this article’s HTML contains the text you’re reading right now, the fact that it is in a paragraph, and the fact that it comes after a heading and before a CodePen.
Let’s say we want to build a simple shopping list app. We might start with some HTML like this:
We can save this code in a file, open it in a web browser, and the browser will display the rendered result. As you can see, the HTML code in this example represents a section of a page that contains a heading reading “Shopping List (2 items),” a text input box, a button reading “Add Item,” and a list with two items reading “Eggs” and “Butter.” In a traditional website, a user would navigate to an address in their web browser, then the browser would request this HTML from a server, load it and display it. If there are already items in the list, the server could deliver HTML with the items already in place, like they are in this example.
Try to type something in the input box and click the “Add Item” button. You’ll notice nothing happens. The button isn’t connected to any code that can change the HTML, and the HTML can’t change itself. We’ll get to that in a moment.
CSS is for appearance
CSS (Cascading Style Sheets) code defines the appearance of a page. For example, this article’s CSS contains the font, spacing, and color of the text you’re reading.
You may have noticed that our shopping list example looks very plain. There is no way for HTML to specify things like spacing, font sizes, and colors. This is where CSS (Cascading Style Sheets) comes in. On the same page as the HTML above, we could add CSS code to style things up a bit:
As you can see, this CSS changed the font sizes and weights and gave the section a nice background color (designers, please don’t @ me; I know this is still ugly). A developer can write style rules like these and they will be applied consistently to any HTML structure: if we add more <section>
, <button>
or <ul>
elements to this page, they will have the same font changes applied.
The button still doesn’t do anything, though: that’s where JavaScript comes in.
JavaScript is for behavior
JavaScript code defines the behavior of interactive or dynamic elements on a page. For example, the embedded CodePen examples in this article are powered by JavaScript.
Without JavaScript, to make the Add Item button in our example work would require us to use special HTML to make it submit data back to the server (<form action="...">
, if you’re curious). Then the browser would discard the entire page and reload an updated version of the entire HTML file. If this shopping list was part of a larger page, anything else the user was doing would be lost. Scrolled down? You’re back at the top. Watching a video? It starts over. This is how all web applications worked for a long time: any time a user interacted with a webpage, it was as if they closed their web browser and opened it again. That’s not a big deal for this simple example, but for a large complex page which could take a while to load, it’s not efficient for either the browser or the server.
If we want anything to change on a webpage without reloading the entire page, we need JavaScript (not to be confused with Java, which is an entirely different language… don’t get me started). Let’s try adding some:
Now when we type some text in the box and click the “Add Item” button, our new item is added to the list and the item count at the top is updated! In a real app, we would also add some code to send the new item to the server in the background so that it will still show up the next time we load the page.
Separating JavaScript from the HTML and CSS makes sense in this simple example. Traditionally, even more complicated interactions would be added this way: HTML is loaded and displayed, and JavaScript runs afterwards to add things to it and change it. As things get more complex, however, we start needing to keep better track of things in our JavaScript.
If we were to keep building this shopping list app, next we’d probably add buttons for editing or removing items from the list. Let’s say we write the JavaScript for a button that removes an item, but we forget to add the code that updates the item total at the top of the page. Suddenly we have a bug: after a user removes an item, the total on the page won’t match the list! Once we notice the bug, we fix it by adding that same totalText.innerHTML
line from our “Add Item” code to the “Remove Item” code. Now we have the same code duplicated in more than one place. Later on, let’s say we want to change that code so that instead of “(2 items)” at the top of the page it reads “Items: 2.” We’ll have to make sure we update it in all three places: in the HTML, in the JavaScript for the “Add Item” button, and in the JavaScript for the “Remove Item” button. If we don’t, we’ll have another bug where that text abruptly changes after a user interaction.
In this simple example, we can already see how quickly these things can get messy. There are ways to organize our JavaScript to make this kind of problem easier to deal with, but as things continue to get more complex, we’ll need to keep restructuring and rewriting things to keep up. As long as HTML and JavaScript are kept separate, a lot of effort can be required to make sure everything is kept in sync between them. That’s one of the reasons why new JavaScript frameworks, like React, have gained traction: they are designed to show the relationships between things like HTML and JavaScript. To understand how that works, we first need to understand just a teeny bit of computer science.
Two kinds of programming
The key concept to understand here involves the distinction between two common programming styles. (There are other programming styles, of course, but we’re only dealing with two of them here.) Most programming languages lend themselves to one or the other of these, and some can be used in both ways. It’s important to grasp both in order to understand the main benefit of HTML-in-JS from a JavaScript developer’s perspective.
- Imperative programming: The word “imperative” here implies commanding a computer to do something. A line of imperative code is a lot like an imperative sentence in English: it gives the computer a specific instruction to follow. In imperative programming, we must tell the computer exactly how to do every little thing we need it to do. In web development, this is starting to be considered “the old way” of doing things and it’s what you do with vanilla JavaScript, or libraries like jQuery. The JavaScript in my shopping list example above is imperative code.
- Imperative: “Do X, then do Y, then do Z”.
- Example: When the user selects this element, add the
.selected
class to it; and when the user de-selects it, remove the.selected
class from it.
- Declarative programming: This is a more abstract layer above imperative programming. Instead of giving the computer instructions, we instead “declare” what we want the results to be after the computer does something. Our tools (e.g. React) figure out the how for us automatically. These tools are built with imperative code on the inside that we don’t have to pay attention to from the outside.
- Declarative: “The result should be XYZ. Do whatever you need to do to make that happen.”
- Example: This element has the
.selected
class if the user has selected it.
HTML is a declarative language
Forget about JavaScript for a moment. Here’s an important fact: HTML on its own is a declarative language. In an HTML file, you can declare something like:
<section>
<h1>Hello</h1>
<p>My name is Mike.</p>
</section>
When a web browser reads this HTML, it will figure out these imperative steps for you and execute them:
- Create a section element
- Create a heading element of level 1
- Set the inner text of the heading element to “Hello”
- Place the heading element into the section element
- Create a paragraph element
- Set the inner text of the paragraph element to “My name is Mike”
- Place the paragraph element into the section element
- Place the section element into the document
- Display the document on the screen
As a web developer, the details of how a browser does these things is irrelevant; all that matters is that it does them. This is a perfect example of the difference between these two kinds of programming. In short, HTML is a declarative abstraction wrapped around a web browser’s imperative display engine. It takes care of the “how” so you only have to worry about the “what.” You can enjoy life writing declarative HTML because the fine people at Mozilla or Google or Apple wrote the imperative code for you when they built your web browser.
JavaScript is an imperative language
We’ve already looked at a simple example of imperative JavaScript in the shopping list example above, and I mentioned how the complexity of an app’s features has ripple effects on the effort required to implement them and the potential for bugs in that implementation. Now let’s look at a slightly more complex feature and see how it can be simplified by using a declarative approach.
Imagine a webpage that contains the following:
- A list of labelled checkboxes, each row of which changes to a different color when it is selected
- Text at the bottom like “1 of 4 selected” that should update when the checkboxes change
- A “Select All” button which should be disabled if all checkboxes are already selected
- A “Select None” button which should be disabled if no checkboxes are selected
Here’s an implementation of this in plain HTML, CSS and imperative JavaScript:
There isn’t much CSS code here because I’m using the wonderful PatternFly design system, which provides most of the CSS for my example. I imported their CSS file in the CodePen settings.
All the small things
In order to implement this feature with imperative JavaScript, we need to give the browser several granular instructions. This is the English-language equivalent to the code in my example above:
- In our HTML, we declare the initial structure of the page:
- There are four row elements, each containing a checkbox. The third box is checked.
- There is some summary text which reads “1 of 4 selected.”
- There is a “Select All” button which is enabled.
- There is a “Select None” button which is disabled.
- In our JavaScript, we write instructions for what to change when each of these events occurs:
- When a checkbox changes from unchecked to checked:
- Find the row element containing the checkbox and add the
.selected
CSS class to it. - Find all the checkbox elements in the list and count how many are checked and how many are not checked.
- Find the summary text element and update it with the checked number and the total number.
- Find the “Select None” button element and enable it if it was disabled.
- If all checkboxes are now checked, find the “Select All” button element and disable it.
- Find the row element containing the checkbox and add the
- When a checkbox changes from checked to unchecked:
- Find the row element containing the checkbox and remove the
.selected
class from it. - Find all the checkbox elements in the list and count how many are checked and not checked.
- Find the summary text element and update it with the checked number and the total number.
- Find the “Select All” button element and enable it if it was disabled.
- If all checkboxes are now unchecked, find the “Select None” button element and disable it.
- Find the row element containing the checkbox and remove the
- When the “Select All” button is clicked:
- Find all the checkbox elements in the list and check them all.
- Find all the row elements in the list and add the
.selected
class to them. - Find the summary text element and update it.
- Find the “Select All” button and disable it.
- Find the “Select None” button and enable it.
- When the “Select None” button is clicked:
- Find all the checkbox elements in the list and uncheck them all.
- Find all the row elements in the list and remove the
.selected
class from them. - Find the summary text element and update it.
- Find the “Select All” button and enable it.
- Find the “Select None” button and disable it.
- When a checkbox changes from unchecked to checked:
Wow. That’s a lot, right? Well, we better remember to write code for each and every one of those things. If we forget or screw up any of those instructions, we will end up with a bug where the totals don’t match the checkboxes, or a button is enabled that doesn’t do anything when you click it, or a row ends up with the wrong color, or something else we didn’t think of and won’t find out about until a user complains.
The big problem here is that there is no single source of truth for the state of our app, which in this case is “which checkboxes are checked?” The checkboxes know whether or not they are checked, of course, but, the row styles also have to know, the summary text has to know, and each button has to know. Five copies of this information are stored separately all around the HTML, and when it changes in any of those places the JavaScript developer needs to catch that and write imperative code to keep the others in sync.
This is still only a simple example of one small component of a page. If that sounds like a headache, imagine how complex and fragile an application becomes when you need to write the whole thing this way. For many complex modern web applications, it’s not a scalable solution.
Moving towards a single source of truth
Tools, like React, allow us to use JavaScript in a declarative way. Just as HTML is a declarative abstraction wrapped around the web browser’s display instructions, React is a declarative abstraction wrapped around JavaScript.
Remember how HTML let us focus on the structure of a page and not the details of how the browser displays that structure? Well, when we use React, we can focus on the structure again by defining it based on data stored in a single place. When that source of truth changes, React will update the structure of the page for us automatically. It will take care of the imperative steps behind the scenes, just like the web browser does for HTML. (Although React is used as an example here, this concept is not unique to React and is used by other frameworks, such as Vue.)
Let’s go back to our list of checkboxes from the example above. In this case, the truth we care about is simple: which checkboxes are checked? The other details on the page (e.g. what the summary says, the color of the rows, whether or not the buttons are enabled) are effects derived from that same truth. So, why should they need to have their own copy of this information? They should just use the single source of truth for reference, and everything on the page should “just know” which checkboxes are checked and conduct themselves accordingly. You might say that the row elements, summary text, and buttons should all be able to automatically react to a checkbox being checked or unchecked. (See what I did there?)
Tell me what you want (what you really, really want)
In order to implement this page with React, we can replace the list with a few simple declarations of facts:
- There is a list of true/false values called
checkboxValues
that represents which boxes are checked.- Example:
checkboxValues = [false, false, true, false]
- This list represents the truth that we have four checkboxes, and that the third one is checked.
- Example:
- For each value in
checkboxValues
, there is a row element which:- has a CSS class called
.selected
if the value is true, and - contains a checkbox, which is checked if the value is true.
- has a CSS class called
- There is a summary text element that contains the text “
{x}
of{y}
selected” where{x}
is the number of true values incheckboxValues
and{y}
is the total number of values incheckboxValues
. - There is a “Select All” button that is enabled if there are any false values in
checkboxValues
. - There is a “Select None” button that is enabled if there are any true values in
checkboxValues
. - When a checkbox is clicked, its corresponding value changes in
checkboxValues
. - When the “Select All” button is clicked, it sets all values in
checkboxValues
to true. - When the “Select None” button is clicked, it sets all values in
checkboxValues
to false.
You’ll notice that the last three items are still imperative instructions (“When this happens, do that”), but that’s the only imperative code we need to write. It’s three lines of code, and they all update the single source of truth. The rest of those bullets are declarations (“there is a…”) which are now built right into the definition of the page’s structure. In order to do this, we write our elements in a special JavaScript syntax provided by React called JSX, which resembles HTML but can contain JavaScript logic. That gives us the ability to mix logic like “if” and “for each” with the HTML structure, so the structure can be different depending on the contents of checkboxValues
at any given time.
Here’s the same shopping list example as above, this time implemented with React:
JSX is definitely weird. When I first encountered it, it just felt wrong. My initial reaction was, “What the heck is this? HTML doesn’t belong in JavaScript!” I wasn’t alone. That said, it’s not HTML, but rather JavaScript dressed up to look like HTML. It is also quite powerful.
Remember that list of 20 imperative instructions above? Now we have three. For the price of defining our HTML inside our JavaScript, the rest of them come for free. React just does them for us whenever checkboxValues
changes.
With this code, it is now impossible for the summary to not match the checkboxes, or for the color of a row to be wrong, or for a button to be enabled when it should be disabled. There is an entire category of bugs which are now impossible for us to have in our app: sources of truth being out of sync. Everything flows down from the single source of truth, and we developers can write less code and sleep better at night. Well, JavaScript developers can, at least…
It’s a trade-off
As web applications become more complex, maintaining the classic separation of concerns between HTML and JavaScript comes at an increasingly painful cost. HTML was originally designed for static documents, and in order to add more complex interactive functionality to those documents, imperative JavaScript has to keep track of more things and become more confusing and fragile.
The upside: predictability, reusability and composition
The ability to use a single source of truth is the most important benefit of this pattern, but the trade-off gives us other benefits, too. Defining elements of our page as JavaScript code means that we can turn chunks of it into reusable components, preventing us from copying and pasting the same HTML in multiple places. If we need to change a component, we can make that change in one place and it will update everywhere in our application (or in many applications, if we’re publishing reusable components to other teams).
We can take these simple components and compose them together like LEGO bricks, creating more complex and useful components, without making them too confusing to work with. And if we’re using components built by others, we can easily update them when they release improvements or fix bugs without having to rewrite our code.
The downside: it’s JavaScript all the way down
All of those benefits do come at a cost. There are good reasons people value keeping HTML and JavaScript separate, and to get these other benefits, we need to combine them into one. As I mentioned before, moving away from simple HTML files complicates the workflow of someone who didn’t need to worry about JavaScript before. It may mean that someone who previously could make changes to an application on their own must now learn additional complex skills to maintain that autonomy.
There can also be technical downsides. For example, some tools like linters and parsers expect regular HTML, and some third-party imperative JavaScript plugins can become harder to work with. Also, JavaScript isn’t the best-designed language; it’s just what we happen to have in our web browsers. Newer tools and features are making it better, but it still has some pitfalls you need to learn about before you can be productive with it.
Another potential problem is that when the semantic structure of a page is broken up into abstract components, it can become easy for developers to stop thinking about what actual HTML elements are being generated at the end. Specific HTML tags like <section>
and <aside>
have specific semantic meanings that are lost when using generic tags like <div>
and <span>
, even if they look the same visually on a page. This is especially important for accessibility. For example, these choices will impact how screen reader software behaves for visually impaired users. It might not be the most exciting part, but JavaScript developers should always remember that semantic HTML is the most important part of a web page.
Use it if it helps you, not because it’s “what’s hot right now”
It’s become a trend for developers to reach for frameworks on every single project. Some people are of the mindset that separating HTML and JavaScript is obsolete, but this isn’t true. For a simple static website that doesn’t need much user interaction, it’s not worth the trouble. The more enthusiastic React fans might disagree with me here, but if all your JavaScript is doing is creating a non-interactive webpage, you shouldn’t be using JavaScript. JavaScript doesn’t load as fast as regular HTML, so if you’re not getting a significant developer experience or code reliability improvement, it’s doing more harm than good.
You also don’t have to build your entire website in React! Or Vue! Or Whatever! A lot of people don’t know this because all the tutorials out there show how to use React for the whole thing. If you only have one little complex widget on an otherwise simple website, you can use React for that one component. You don’t always need to worry about webpack or Redux or Gatsby or any of the other crap people will tell you are “best practices” for your React app.
For a sufficiently complex application, declarative programming is absolutely worth the trouble. It is a game changer that has empowered developers the world over to build amazing, robust and reliable software with confidence and without having to sweat the small stuff. Is React in particular the best possible solution to these problems? No. Will it just be replaced by the next thing? Eventually. But declarative programming is not going anywhere, and the next thing will probably just do it better.
What’s this I’ve heard about CSS-in-JS?
I’m not touching that one.
I am a full-stack developer but there are people, known as front-end designers, who have no knowledge of JavaScript and mixing JavaScript with HTML is frustrating them.
Although frameworks like Vue and React updates many things atomatically but if the developer has forgotten to program something then there will be bug; framework doesn’t fix everything automatically. So, frameworks are useful for rapid development but saying – we can make that change in one place and it will update everywhere in our application (when front-end frameworks are used) – could be exaggerating.
Also, it is better to separate HTML and JavaScript in publically accessible (without login) pages; and use a front-end framework in dynamic pages which depend of live updation through user interaction.
Developers need to choose and use such frameworks wisely. I am completely agree with your message in the section – Use it if it helps you, not because it’s “what’s hot right now”.
Absolutely! Developers still need to pay attention, and you can definitely still have lots of kinds of bugs. I only mean that tools like this make it possible to define and use single sources of truth. The developer still has to take advantage of that and stick to it.
What a well written article.
Engrossing read.
I’d like to add, as a somewhat front end developer who relies on imperative programming, I understood completely the purpose or the point Mike was making with this article.
It’s about awareness of what these new frameworks are, why people have started using them and their perks and of course things that may not be so likeable about them.
Mike goes on to inform us, when and where something like react would be useful and where it would be unnecessary or complete overkill.
I wonder then if instead of spending an eternity playing with native js, jquery and trying new things with these languages and learning things I could do with these two that I thought I could never do before, if I’m wasting valuable time and should ought to be ‘diving in’ to the pool with the js framework folks.
The thing is, I’ve just not had any reason to use any of them just yet. Until I do, I’ll keep it html5+css3+javascript & jquery+php and mysql
I’m sure when the time is right I’ll be okay with jumping over to the next big framework heh.
A shame that it wasted your time. Good job it left you enough time to write a lengthy comment!
Great write-up, thanks Mike.
“What’s this I’ve heard about CSS-in-JS?
I’m not touching that one.”
Glad you like it! Heh, yeah, that’s a topic for another day :) I still haven’t wrapped my head around it yet.
I am a tech-lead at a Dutch startup, and an Engineering Lead in a Pakistani tech firm.
I am going to make a valid point here bur before that, I would need to justify something, my stance and my position. By skillset, I am a Cloud & Solution Architect, a Computer Systems Engineer, Computer Architect, Project & Product Manager, an IoT Expert, a full-stack developer, Robotist and a Graphics Designer.
Now, first of all I thought this article was a comparison between server side rendering, or a review of ejs, or nest and static HTML templates, it wasn’t.
Then I though it might be about HTML5, it’s APIs and power it has given to Web Developers and JS Wrappers available to consume them, it wasn’t.
Bear with me since this article was a waste of my time , yet not entirely useless, but not what the title suggests.
Instead it was a comparison between JSX and HTML. The article states HTML as a declarative language. SQL is a declarative language my friend. HTML is just markup, it’s a markup language. Keeping aside HTML5. And if you are talking about inline functions, you have got to do some research in how browsers work and how they render web pages.
And JSX isn’t HTML, it’s just a fancy new feature that is also available in React and you might be able to utilize it by importing babel, setting up ts config and tweaking your linter.
Might not want to publish articles with extremely catchy titles just to get more views out of it. PS, this page is CSS tricks. A group of Frontend End Web Developers I suppose?
You don’t have to include html in js to make app development simpler. Frameworks like Vue and svelte don’t need such abstraction and to a lot of new comers are easier to understand as they are closer to plain html/css/ks
It’s true, this isn’t the only solution to these problems, nor is it the best. I only wanted to explain why you might do it at all. From what I’ve seen of Vue and Svelte, they are also elegant and possibly more approachable (depending on how you use them), but they have their own downsides as well. Vue’s custom attributes and template strings make it not truly HTML either, just a different abstraction. And Svelte is enough of a black box that I think I might have a hard time reasoning about it when debugging.
I need to learn more about them before I criticize them too much though, I definitely am coming at this with mostly React experience, comparing it to my experience of using things like jQuery. I may yet decide to go all in with Vue or Svelte instead :) thanks for the perspective!
If you use Web Components in a certain and consistent way, maintaining a well documented library for your users, then you can use HTML as it was invented for: to DEFINE content and its structure.
I think eventually Web Components will rule front-end development.
I think you may be right about web components, I have my eye on them. For now though, they don’t seem mature enough for my needs. We’ll get there!
When reading the article, that’s exactly what came to my mind. The problems listed by the author are real for React/JSX, but Vue.js still keeps some separation of concerns. In my company, designers usually code HTML/CSS and when adopting a framework to modernize our stack, we’ve opted for Vue.js as the learning curve would be a bit less steep for designers.
What about these issues:
Backend: for web applications, you still need a whole separate layer of, e.g., saving to a db, storing and getting configurations, etc. By moving to React, we didn’t simplify any of this.
Workflow: plain HTML/CSS/JS doesn’t require much setup for my local laptop or my commodity web server. Even a LAMP stack is quite commodified. I can use any tools I want (text editors, etc.). But to get going with React, I need to deal with (at the least) Node, dependency-management, rapid version changes…
Teamwork: One of the benefits of React-style components is that teams can work together without muddling things up. But it also requires a lot of enforced agreement — this text editor, that version, this vendor, that plugin. This was how things worked in the pre-HTML world, where Macs and Windows could barely exchange files at all. This is why “onboarding” is such a buzzword now: it doesn’t just mean “learn how the codebase works” it means “set up your environment in this exact way.”
I agree with you that React might be useful for you if you’re building an “app” — but good old-fashioned web pages feel like they’ve been downgraded to an afterthought in this age of harping on “apps.”
It seems to me that companies like Google and Facebook benefit when an infrastructure and particular style of working gets defined by them. It’s classic lock-in.
Thanks for the thoughtful essay.
I’m glad you enjoyed the article! I think I agree with a lot of what you said here, but a few things:
Backend: true, moving to React doesn’t solve any backend problems, the comparison I’m trying to draw is frontend-specific. But in my opinion if you don’t render HTML on the server, that nicely decouples the document’s presentation from the API / business logic, leaving the backend only responsible for providing those things through a nice REST API or GraphQL, etc. And you can still use tools to server-side render your React for performance and SEO if you want, although I’ll admit that can be a bit rough.
Workflow: for the majority of “React and friends” projects you’ll find out there, you’re totally right. But, a bundler is not strictly required: you can use React (and even JSX) in plain static HTML+JS, using
<script>
tags just like jQuery. You won’t get the benefits of bundlers, but you can do quick-and-dirty prototypes this way, or add a small React widget to an otherwise static page, no webpack required: https://reactjs.org/docs/add-react-to-a-website.htmlTeamwork: that’s definitely a legitimate issue with all of this, but I don’t think that’s a problem unique to something like React. An organized codebase has always been a hard thing to maintain across collaborators.
All legitimate points, but it’s never so cut-and-dried.
“But to get going with React, I need to deal with (at the least) Node, dependency-management, rapid version changes…”
Yes, and that for me is the biggest barrier to learning some of these tools. I have both IIS and Apache servers on my workstation, I’ve got databases, Python, PHP, etc. and any of those were easier to understand how to install and configure than what I’ve read about Node, package managers, and all the other overhead that seems to go with these new frameworks. (If anyone can recommend a good tutorial about how to set all that up on a Windows workstation, that would be great.)
But the even bigger question in my mind as I have read articles about React or all the other frameworks popping up has been, “why?” Until I read this article it sounded like a lot of extra complexity without that much benefit. Or maybe the authors were using React in a situation where it was complete overkill, and some of the other posters have alluded to. Now I get it, or at least I get it far more than before. Thanks, Mike.
Just another I know React thus Im holier than thou attitude. Even Google has problems with JS rendering in 2020, so you are handicapping yourself by using JS on an ecommerce website. Who can post the little brain vs the big brain meme here for me.
Where in my article do I imply that I’m holier than thou? I apologize if I came across that way. I am only trying to explain the reasoning behind why you might use it. It absolutely has flaws. SEO is a big one, if you run into that issue I think that falls under “use it if it helps you”.
It’s ….zero percent that. Literally not a single smug or I’ll conceived point in the entire article.
This isn’t really new … Blade = HTML-in-PHP, ERB = HTML-in-Ruby, jinja = HTML-in-Python, JSX = HTML-in-JavaScript.
Before, designers wrote templates and developers wrote PHP/Python/Ruby. Now the sensible split is between presentational vs stateful components.
Yeah, I perhaps should have given more background on the history of other server-rendered templating frameworks. This is only new in the sense of being able to write client-side stuff declaratively; those examples all still fall under the “changes require reloading the page” flaw I think. They are absolutely better solutions if you don’t need a lot of fancy client-side widgets, though. You can always use a little of both :)
Maybe it would have been worth getting into presentational vs stateful components, but I felt that might be a bit out of scope of the article. I appreciate you adding that context.
Good article. Nice explanation.
Please let me know how it is different from Angular.
Whenever controls need to be created dynamically we can use anyone of the JQuery or Angular or React etc., Frameworks.
I really liked the way you explained ”you can use React for that one component”.
If I have many HTML files, where user interaction is very limited and I have only one component where interaction is maximum, then please provide an example of developing the single component and how to integrate all of them into a single website and publish.
My impression of the main difference between React and Angular is that React provides a top-down uni-directional flow of data (everything comes from the source of truth), and Angular provides bi-directional data binding (link some stuff together so that when one of them changes the others will automatically change). I find React to be more predictable, and even though its elements are defined in JSX/JavaScript they are closer to describing normal HTML than Angular, which involves a bunch of custom attributes in its HTML. React is also less opinionated (which can be good and bad), whereas Angular is sort of an all-in-one package where you need to do everything “the Angular way”. They each have their place, and I will admit I am biased as I have much more experience with React.
For an example of adding a single React component to an otherwise non-React website, see the page in the React docs that I linked to in the “Use it if it helps you” section: https://reactjs.org/docs/add-react-to-a-website.html. Basically, you can include an empty
<div>
somewhere on your website and then tell React to render there, and it will take over that div’s children and leave the rest of your page alone.I don’t mind the HTML/CSS-in-JS approach, as long as your output is well crafted. Being able to deliver that craft is only possible by having a great foundation of the basics in the three languages mentioned.
What I mean by that, the components are not rendering “div soup” to the DOM and they work well (semantic) with the components they’re being slotted into.
With CSS-in-JS, as long as it isn’t inline-styles, and the developer experience of working with CSS-in-JS is a good one, I’m all for it.
100% agree.
Tim Berners-Lee had the wisdom to foresee this. His Rule of Least Power has been a guiding principle of the W3C for years.
https://www.w3.org/2001/tag/doc/leastPower
And with regards to HTML:
Wise words, I can’t argue with that. That’s a big thing to consider in the trade-off. I think React is best used when it preserves things like the ability to index and read data, either through server-side rendering (e.g. Gatsby) or by designing the application’s backend to include a public-facing API so that the React view is just one front-end, consuming the same data that is also available programmatically for other uses.
What is diff btw Framework and Library?
To be honest, I think the distinction has been lost a bit in the JavaScript world; they are often used interchangeably, and I’m guilty of that.
According to Wikipedia, “A library offers functions to be called by its parent code, whereas a framework defines the entire application design.” (https://en.wikipedia.org/wiki/JavaScript_framework) So by that definition, I would consider React to be a library, not a framework. And in fact React’s own website calls it that. Thanks for pointing that out!
I like frameworks like React, but I also hate the way they (mostly) leave a user with no JavaScript in the dark. I personally like to couple react with a server side render for the initial load.
I feel like this post started on the wrong foot by mentioning that you need Javascript to stop the whole page from reloading. Most websites for code editing post to an iframe to refresh the results. It’s important we don’t forget all the HTML & CSS tools given to us.
I’ll shortly be embarking on a journey of creating a real time IRC client that will work seamlessly without JS and/or cookies (mostly using some css-tricks!).
Can you elaborate on this? I would think that frame’s contents still have the same restrictions, but I haven’t come across code like that before. That sounds like an interesting solution!
Just watch then what WebAssembly is going to do in some years from now. A lot of enterprise systems will become dumb terminals with nothing more than a canvas and a web socket, and will amount to a VNC client.
There’s so much to unpack here, and we have certainly strayed very far away from our roots. How does reaching for a tool like react solve the problem of a single source of truth differently than using ES modules, classes, and commonJS? And how about the template tag and HTML imports to separate markup and components?
The inputs are all missing labels in the examples, and the table summary should be a caption element with aria-live=assertive.
Thank you for pointing out the missing labels and aria attributes! I need to go back and update those, and practice what I preach. I’m still learning how to make accessible markup, I am one of the JavaScript developers who learned all this in the wrong order!
As for your question, those things solve a different source-of-truth problem, helping to avoid repeated code. React manages the source of truth for view state specifically, and helps to avoid repeated state (user input, data loaded from an API, results of user interaction, etc) as well as code.
This is a helpful article. Especially for relative new comers. I think Mike is clear about the intent of the article too so there is no air of holiness at all. It is clearly not a sermon, it is a commentary that provides a low gradient insight into a very current debate. Good work. Thanks Mike.
I still don’t see the rationale behind HTML/CSS-in-JS! If we must take back our words on the principle of Separation of Concerns, we must as well take back our words on all other design and development principles like Inversion of Control, the Single Responsibility principle, etc. If it doesn’t make sense to separate things, why do you componentize? Why isn’t a monolithic UI better? You see, it’s really shameful that even professional devs are having to preach one thing but practice another! Or maybe React developers never really understood any of these and the REASON we have 3 distinct technologies (HTML, CSS and JS) in the first place.
A good framework is one that facilitates development all within the spheres of our profession; one that makes it easier to do the right thing, and harder to do the wrong thing. It’s sad how many developers have got caught up in this. I can’t begin to imagine how many web apps have been made in this code mess, how they’re surviving currently, and the amount of time and resources that will sooner or later be needed to rewrite them to normalcy as the community is now welcoming “sane” UI frameworks like CHTML (https://github.com/onephrase/chtml).
I disagree. Just because we’re experimenting with rethinking one thing doesn’t mean we need to rethink everything.
React differs between separation of technology and separation off concern, it’s all in their docs. It separates state from from the view layer, but treats all elements of the view layer as a function of state which is not just logical, you could argue that we haven’t understood what separation of concern meant before react.
Look at frameworks before react. They separate technologies, which terminated scope. But you obviously need these technologies to be dynamic, so scope is introduced back via DI and logic is introduced back via syntax extensions (for-each, if, etc). In other words they separate for no reason at all, just to glue these parts back with massive complexity.
Using HTML @import to import HTML files into other html files is the React for me.
As a one‐man‐band marketing consultant I sometimes get dragged into full-build website projects where I have to stretch patchy skills to meet client requirements. Coming across well-written, opinionless and accessible content like this is a godend.
Nicely done, Mike, you’re bookmarked!
Thank you and the CSS-Tricks team for this article. Interesting, reasonable, informative. Declarative vs Imperative? Small brain here. didn’t know that. Learnt something new. :thumbsup:
Thank you so much for this overview! I now better understand, when and why to use HTML-in-JS frameworks, and that they have their good. I also learnt what their selective purpose should be and that they are not meant to supersede HTML per se – hopefully some overly enthusiasts of React, Vue etc. will read your article, too.
I don’t understand why people are shouting HTML in JavaScript is weird…this same set of people have used HTML in PHP and other server side template systems before and to spoil it all, they are saying Vue, Angular or Svelte is better and they never take time to inspect the final output of these guys and find out it is all HTML in JavaScript at the end.
I have to agree with you there. At least JSX prevents SQL injections from interpolating user input into string-template-based HTML ;)
Excellent explanation of imperative and declarative programming , after a long time I read one of the best article.
Great article, I’m trying to push the company I work for into a more declarative JS framework and have been given the time to experiment. For me, I’ve kinda fallen in love with Angular as it still has a certain degree of separation of concerns (as in separate files for html, styles and the typescript. I’ve found during this experimentation with the rest of my team that the other FE devs who are more html and scss leaning can work on what they need to easier than they could with react or vue
That is definitely a strong point in favor of Angular, and also of Vue and Svelte for that matter. I think those land at a different place on the trade-off spectrum here, but (strictly my opinion) React’s predictability and ecosystem put it ahead of those for me, at least for sufficiently complex UIs. It’s definitely a decision each team should make based on their own priorities and the task at hand.
Personally, I am very curious to see what the future holds for Web Components, since they could be used within any of these frameworks. I still have issues with them, but they are moving in the right direction. Maybe my next article will be about that!
React differs between separation of technology and separation off concern, it’s all in their docs. It separates state from from the view layer, but treats all elements of the view layer as a function of state which is not just logical, you could argue that we haven’t understood what separation of concern meant before react.
Look at frameworks before react. They separate technologies, which terminated scope. But you obviously need these technologies to be dynamic, so scope is introduced back via DI and logic is introduced back via syntax extensions (for-each, if, etc). In other words they separate for no reason at all, just to glue these parts back with massive complexity.
Awesome article. Aptly described.
Thanks alot for this spoon feeding article mate. It felt very much like tailor made for me. Till this moment i was hesitant to try and raged on this js eating html programming method. Im one of the guy who liked keeping html css and js distinct even in a complex applications..i knew that these new frameworks were changing this method but it only made me go nuts like why!!!
Every inch of my ambiguity is clear now and frankly you have given me a confident tap on shoulder on how i should perspective these new frameworks.
What a great article. You absolutely explained it perfectly. I’m a full stack developer but I have felt uneasy with putting HTML into js. I feel like it’s an evolutionary step which very soon we will not do any more. I’m still a purest on the front end HTML/CSS/JS. For all the above reasons you mentioned. On the backend we use partial views so this is how reusable single source components are achieved. What’s delivered at the client side is really just a dynamic response but the client gets a pure response. So many ways to cut code eh!
Excellent write-up! I find it’s almost impossible to find good technical writing aimed at non-experts (other than tutorials, that is).
My projects lately have been split between using vanilla HTML+js and using reactive tools, and while I have a good grasp of the practical differences, I’m constantly thinking “how would I explain this to someone for whom this is new? What’s the thought process they would need to understand?” My answer would now be to send them this article :)
Truly inspiring. The web needs more of this kind of writing.
It’s more a short vs. long term question imo, and what makes more sense depends on your domain, and how much you can or a are willing to plan ahead. There’s so much happening in that area because there’s no native middle ground between those technologies imo.
JS/React are quickly changing and more flexible short term, HTML and CSS are more stable but also more rigid. It’s no surprise that there is money in creating a middle ground, by making JS more stable and long term viable with frameworks (e.g. Gatsby), and making HTML and CSS more flexible short term by combining concerns (e.g. colocation of styles and semantics in Tailwind).
Hey Mike,
Nice article! It’s funny, I was just thinking about all of this yesterday. I’m also a Frontend Developer, but I didn’t start really getting in-depth with JavaScript until our company dove head first into React a couple of years ago. All of the “traditional” frontenders like me were suddenly plunged into an amorphous world of ES6, JSX, React, and JavaScript. At the time, I wasn’t able to discern the difference between a lot of it.
Now that I’m very comfortable writing complex React Apps, I started thinking about how hard this would be to create these same stateful Apps with vanilla JS. I actually created a jsfiddle yesterday of a counter app. What I wasn’t able to do was articulate out loud exactly why it was annoying without React. I think you cemented it for me from another comment, the fact that React provides:
Thanks for this article, it’s like it was written for me. Also, I appreciated the references to the late 90’s/early 00’s jams!
P.S. Small world; I was in your C++ class in high school. Your snake game was unreal. Hope all is well. :)
Not counter-arguments, but genuine questions:
How does this measure up for Accessibility? Will it work with Screen Readers? A lot of government sites have quite definite accessibility requirements, and HTML works pretty well these days, even when written badly. I guess that JavaScript should be fine, but only if the developers do the work to make it work correctly. See https://webaim.org/techniques/javascript/
How does this affect SEO? Google have only recently updated their indexer (Caffeine) to use a recent version of Chrome. And JavaScript based pages will inevitably be indexed later/more infrequently that HTML ones – HTML pages are easy to index, JavaScript ones require code to be run first. Other search engines have varying levels of support; some are blind to JavaScript. See https://www.deepcrawl.com/knowledge/white-papers/javascript-seo-guide/how-javascript-rendering-works/
Personally, I don’t like mixing content and code – it makes it too hard to change the content – but then I do build CMSes for a living…
“As web applications become more complex, maintaining the classic separation of concerns between HTML and JavaScript comes at an increasingly painful cost. ”
“but if all your JavaScript is doing is creating a non-interactive webpage, you shouldn’t be using JavaScript.”
Yes. Of course. But violation of these is why JS is “eating” HTML. There’s a new hammer (i.e., React) and now EVERYTHING is a nail. What’s disturbing is the bias that’s going into these decisions. That is, devs/engineers are making themselves the focal point instead of the client and/or application. What could go wrong?
Great stuff. I consider myself to be a frontend minimalist, so totally agree on many points.
One thing had me wondering, the caption of the table contains a checked number status along with two buttons.
Isn’t the caption intended to describe what the table actually is, like List of Ingredients or whatever? I mean the screen reader picks it up and reads what the table is. Now it’s more of a status bar with actions and I guess that would be confusing?
Hmm. It feels a lot like XAML, the XML markup used for WPF/UWP/Xamarin (in slightly different dialects) UI programming in .NET. Your code-behind has a single observable collection of whatevers, and the XAML code declaratively constructs a view of that collection which can be filtered or sorted or whatever, and then applied as a list box, or the items of a combo box, or the basis for looking at the currently selected entry in more detail, etc. And if the original item in the observable collection changes, then everything that depends on that changes as well.
It does require wiring up a lot of stuff correctly, though, and debugging it if the bind doesn’t map the way you think it does can be a real pain. But the overall principle is very similar. Figure out a way to make templates work, and you’re most of the way there.
It would be interesting to see things built that way using HTML/Javascript. Use attribute values to determine the bindings, and have the JS framework track the changes.
Caveat: It’s been a while since I’ve used Javascript seriously, and it might be that it can already handle that kind of setup. It just looks like it’s not quite all the way there, yet. It would be interesting to try to build such a system.
Great Article, Mike!
For the sake of curiosity and “to broaden the audience of this article as much as possible” I implemented the Shopping List using Vue.js (from a CDN):
I would like to add that It’s not my intent to say one framework is better than another, the idea here is to give people different perspectives on how such outcome can be reached using different tools.
Wow…
… Where are you shopping that you can buy exactly 2 eggs?
Absolutely loved this. Top-notch writing, technical and highly informative.
This was a great article. The first time I’ve really gotten a better understanding of why you would use a framework like React other than the fact that everybody says you should because it’s just ‘better’.
I really like vanilla JS and I’m still learning and getting better at it and I’ve been able to get most things done just fine using it so I haven’t been motivated to really dive in and learn a framework but this article has given me a different outlook.
And that’s funny about the CSS-In-JS :-) I’m not quite there yet with that. I enjoy my SCSS just fine.
At least JSX prevents SQL injections from interpolating user input into string-template-based HTML ;)
This is flat out incredible! Thanks, looking forward to the follow ups.
If you seek more info about which JavaScript frameworks to choose, there’s a handy article on that topic: https://www.ideamotive.co/blog/consider-these-javascript-frameworks-to-be-more-valuable-on-a-job-market
You can read there about Svelte, TypeScript, GraphQL, NestJS, Gatsby, NextJS and Immer.
Hello! Its a great article, I agree that While HTML is a standard markup language that provides the primary structure of a website, JavaScript is an advanced programming language that makes web pages more interactive and dynamic. If you want to become a web developer who can quickly create websites, then a good knowledge of JavaScript and various, popular JavaScript web development frameworks is very important for your product development process (PDP) You can find information about technologies, that could be a smart choice for your Minimum Viable Product software.