As a front-end developer, it's helpful to be able to differenciate the type of components you are working with (or building). Why? Because by knowing the abstraction level of a component, you can composite them in a way that is easier to maintain, extend and modify in the future.
In this short article, we will define different types of components and order them by level of abstraction — the lowest on the list, will be components that do one thing only and are very specific, and up the list are very broad components that could have anything inside really.
One important thing to note however as could create confusion — we are not talking about components (elements) like div
or a
, but instead components we define as developers.
The list doesn't look into the type of data these components hold or how it's updated or anything of this sort. This list is used when you get an image of the design you need to create and you produce a clean HTML file from it. That's it. No state, no APIs, no backend, SPAs, anything. This list is just the HTML structure in it's purest form.
1. HTML Element Wrappers
It's a Button component. Or a Image component. A Link, List, Avatar, Date, Select and so on. Of course, they can get very complex very quickly, but in it's base form, it's the same as a regular HTML Element + a custom class or a couple of nested HTML Elements like <span>
or <svg>
.
From a very small scale like a <Button>
with a couple of colors like Primary or Secondary, such wrapper could grow to the Select2 library's scale for example. It remains a select, but with a ton of options and views.
Example of HTML Element Wrappers:
- Button
- List (like a checklist or ingredient list etc)
- Heading
- Date (like when a post was published)
- Counter (example: 17 successful clients)
2. Group of elements
The grouping is a single step above the HTML Element Wrappers — it's a collection of such elements. It's not really a component that can be described as a "Card" or "Comment" or "Header of the website" etc. It's only serving the purpose of wrapping the first level, so that you can style them as a whole.
Let's take the example of the Button
component: When you create a <Button>
component (or <button class="button">
), it applies all the styles from the .button
class. But how would that look like when there is a second button next to it? It's too generic to give it a name. You can't really call that class="buttons-for-signing-up". It's too generic, because as soon as you need to reuse these styles for moderating a comment, then it compeltely misses the point.
So, this is where we need the grouping component — an abstract component that cares only about the component that is inside it. Not the data, the component. So, in this case, you can name it .group-buttons
or .ctas-wrapper
or .buttons-wrapper
etc. With a name like that, it doesn't matter if the buttons say "Log in" / "Sign Up" or "Reply" / "Delete". It is still a wrapper. Of what? Of buttons! That's it, nothing more.
The second you wrap your very generic first level component with a specific name, you lock yourself from reusing it. And this goes agains the goal of building a reusable, maintainable and extendable structure.
3. Layout
Layout is a wrapper around other components, not just first level ones. A great example, that many front-end developers know of a Layout is the Grid system. Yep, the same grid you see in Bootstrap, Foundation or the good old 960 grid. It's abstract, becasue it doesn't care about what you put inside. It lays down the structure of your page, similar to HTML itself — what is on top, what is on left, right, bottom etc.
Layouts are a major part of any web app. You can separate a dashboard layout in piece like "top navigation", "main navigation (left)", "main", "footer" and each of those layout sub-components could contain more layouts. This is where CSS Grids shine, btw.
With this knowledge, you might already guess that naming layouts is tricky! Abstract names like the frameworks above use are perfect — small-6 or lg-3 etc, but, what do you do when you want your own? Like Main content of blog post and it's sidebar? When you name such sections, try to keep your names abstract as well, don't name the sidebar as "sidebar", because sometimes, it might hold something completely different. Example names you can use could be "Primary" and "Secondary" or "Primary" and "Aside". None define what exactly goes inside. Naming is maybe one of the hardest parts in development as a whole, not just Front-End, so don't worry if it takes more time to come up with a good name, it will be worth in the end.
As a takeaway - keep the names abstract in this level.
4. Unit
This is the first level where we actually can name a component with a specific name.
When you hear a Component, this is probably what you think of. I called it Unit, for the lack of better name probably at this moment and the confusion it would create if I called it a "Component". Well, everything in this list is a component in one form or another. Heck, even a <a>
element is a component if you think about it.
A Unit is something you limit a little, compared to the previous two levels. For example, a (or <div class="comment">
). You could have literally a single
tag inside with the comment, but most of the time it would take the author of that commebt, his avatar, a link to reply, a number for which comment this is, when it was posted, replies to it and so on.
Another unit could be a (or <div class="card">
) which can hold a heading and a body, maybe a footer. Each of these subcomponents could hold data of any time. This is a bit more generic than a comment as you could wrapp your comments in cards. But the common remains — they are build using smaller HTML Element Wrappers or groups of such or other small components and even other unit-level components.
A Unit is your escape hatch when you need to go specific. You are much more free to do it in this level than in the "Specific standalone HTML Element Wrapper" level, because your units, while named, are open to more types of content. They work mostly as wrappers like in the second level.
5. Specific standalone HTML Element Wrappers
That's a mouthfull, maybe shorter name would be helpful here. But it describes it good — for this one, you are specifically defining what a component should be in it's name. The name this time is not abstract — meaning, it won't hold just any value or content, but something specific.
A Button component can hold text like "Log in" or "Click me" or "Close" or "Download our FREE Ebook". But a component like PDFDownload
or <button class="pdf-download">
is much more specific. You shouldn't expect it to open a modal, right? It should download a PDF. Of course, you can inherit styles and attributes from the first level component like Button, but you make it more specific. And this decreases the cases when you can use it.
While this is a smaler component in terms of HTML tags than a Unit, it's less abstract, meaning, it has less use cases. Ideally, keep your specific elements to a minimum. You can even imagine that you have a budget like $1000 and each specific component will cost you $100. Why? Because the second you want to reuse some portion of your component, you have to create a new abstract one, then inherit it in your old specific component and in your new one. If you don't do it, you get repeated code. Here is an example:
You create the PDFDownload
component, that should look just like a button. And you even use the <button>
HTML tag. It looks like a button, it acts like a button, but it's a PDFDownload. Why? Why not just use <button>
? If you change the boder on all your buttons from 1px to 2px after a year, you will have to manually do the same for your PDFDownload
component and any other of it's kind.
Duplication is Evil! The concept of duplication is mentioned in countless contexts, not just in development. Conversion Rate Experts wrote a great article on that topic, which looks into the problem from the perspective of information management and how that could even ruin a company. The same thinking is applied in front-end development. Write as little code as possible and try to keep your abstract components abstract and introduce as little specific ones as possible.
6. Page
Pages are the same as specific elements, but in a much larger scale. Instead of the PDFDownload, which is just a button, a page holds everything you see on the screen. A page is what we call the "Homepage" or "About" or "Contacts". You might ask, well, how is that a component?
Remember, a component can be a single HTML Element or HTML Element that contains sub-components or children. What is the largest such HTML element you can think? The one, for sure! Or more often the
as it has all the structure that we care about. That is the reason why WordPress for example puts a class in the with the page ID, page template, type of page etc. Because with that, you can target all Blog post pages for example or the About Us page and so on.And this is low on the list as it's even less reusable than the specific standalone HTML wrappers — you can have 50 PDF Download buttons, but how many About Me pages do you have?
The lower we go on the list, the less styles you want to write for such components. So it's easy to say that it's usually a bad pracice to write styles for pages, because when you do that, you risk to end up with styles like:
.page-template-about-me,
.page-template-homepage,
.post-1241,
.page-template-resources, ...... {}
Maintaining that list of selectors above is a nightmare and it's easy to mess it up as it keeps on growing. Instead, try to break down your complex components into simpler ones, keep your components more abstract. Use modifiers and variations (more on that in an upcoming post).
Final words
The list above is a guide to what types of components there are and how specific you should get when you create and reuse them. Every front-end developer might have a different naming for such components, might have a different view even and different best practices. This line of thinking is what helped me work on hundreds of projects, many of which were maintained and continue to grow 4-5 years after the first line of code was written.
I have noticed that the lower on the scale I go, the harder it becomes to manage the project. Code smells like the selectors example above appear more often, patches with deeper selectors increase in frequency and overall, the joy of working on the project dies little by little. And I will be honest here, it's very hard to find motivation to work long-term on a bad codebase that is constantly patching old codebase with bad practices, that increases the specific elements and the only abstract ones are the oldest from when it was first build.
It's a responsibility of the developer to keep up with the best practices during all development cycles. A couple of minutes more thinking about a good name, a short search on the existing components, a quick chat with other developers — it all adds up to a better development experience and lower cost for the clients.
The instant gratification of fixing a bug quickly, commiting and deploying is a slippery slope. Doing that without improving the codebase afterwards results in the described scenario above — messy code with a ton of overwriting, specific classes that can't be reused or cases where you use the CommentForm component for a "Get a demo" page, just because your styles on the commenting form were so nice, that the client wanted the same for the main landing page that convers visitors to potential clients. Visually it's pretty, but in the code... well, it doesn't make much sense.
Read next: CSS Naming Conventions
Top comments (0)