Just as Ruby must be wrangled into modules in the interest of organization and scalability, we must evade our CSS demons by approaching them with a similar plan. Here at Foraker Labs, we have harnessed the power of the ‘Component Library’ to style our applications with consistency and efficiency. Elevating styles to the forefront of our priorities has afforded speed in development as well as page load time, but most importantly, it has suppressed that ever-looming annoyance of having to sift through poorly organized CSS.
Great, so what is a component library?
For those who may be unfamiliar with the term, a ‘Component Library’ is a collection of all of the bits and pieces that make up the entire interface of an application. Components include everything from basic elements like buttons, links, headers, and typography to more complex interface widgets like forms, navigation, pagination controls, and modals, which are created by composing the simpler components together. The result is that every element application-wide has a consistent style and feel which translates directly to a seamless user experience and prominently highlights the brand or idea that is being presented. From there, styling should be as simple as plopping the desired components into your views and shipping the code.
How do I arrange my files?
If you were to take a look at a stylesheets directory in a Foraker app, you might find something that structurally resembles this:
. +-- stylesheets +-- base | +-- extends | | +-- extends that apply to base components | | | +-- mixins | | +-- mixins that apply to base components | | | +-- base.scss | +-- _buttons.scss | +-- _fonts.scss | +-- _forms.scss | +-- _tables.scss | +-- _typography.scss | +-- _variables.scss | +-- components | +-- forms.scss | | +-- custom form components | | | +-- alerts.scss | +-- breadcrumbs.scss | +-- navigation.scss | +-- pagination.scss | +-- search_box.scss | +-- tabs.scss | +-- pages | +-- component_library.scss | +-- other page-specific CSS rules | +-- application.css
Notice we have three main folders named base, components, and pages under the stylesheets directory of our app.
Within base, you will find the most basic of the components…the building blocks for the more complex, application-specific components in the project. This includes fonts, variables (sizes, colors, breakpoints), typography (headers, links, quotes, and other textual elements), and default styling for different types of buttons, tables, lists, and forms.
The components folder is the next step up from base in terms of complexity. This folder contains components that are created by mixing, matching, and reusing elements from base. For instance, your navigation might contain some sort of header or title text, action buttons or links, and potentially even some sort of search field. Leveraging these styles from base minimizes the amount of CSS that needs to be written because the smaller components already exist and have already been styled. Furthermore, if we make changes to any of these base components, they will be propagated throughout the interface application-wide, keeping our CSS DRY and maintainable, and the user experience consistent. We simply need to incorporate our desired base components’ HTML into a navigation template and apply some styling to the widget as a whole to achieve the arrangement that we want. This navigation template can then be plopped straight into our view template without requiring any extra work.
Styling that needs to be customized on a per-page basis should be rather minimal. Page-specific styles can be found in the pages directory. If you find that you are overriding many styles in any one component to achieve a functional or stylistic goal, it is most likely time to introduce a new component to the library.
How can I maintain a component library in my application?
In order to maintain a component library, it is necessary to have a place in your application where you can go to view all of the components, experiment with new ideas, and refine the components that already exist. At Foraker, we maintain a css_components.html.erb view that lives inside of a development module in the views directory in each app that houses the HTML for each individual component in our library. We wire the view up to a route in config/routes.rb:
Now we can start adding our components! You may have noticed that the directory tree above had a file called component_library.scss in the pages directory. This is because the component library should be nicely formatted for your viewing and updating pleasure!
The component library should be one of your first endeavors when building a new Rails app. The simplest place to start is with your base components. You can encode basic CSS rules based on the branding of your project where things like color schemes and font-faces have already been defined for you. Think about things that are necessary in every application like flash messaging, errors, basic form fields, and different types of action buttons and what certain colors might mean to the users of your application. The default layout of your application will also be a concern at this point, and you will be able to make decisions about what navigation, headers, and footers might look like as well as other elements that might be found on every page.
From there, allow feature development to drive new additions to your library and only add new components when the need arises. Every time a new component is created, it gets added to this file so that all developers and designers are aware of its existence to prevent duplication and to act as a style guide of sorts for the application. If you are approaching this in the right way, your component library will constantly be changing and evolving throughout the life of your application.
Why should I bother doing this?
Component libraries can truly help us to avoid some of the problems that make our CSS difficult to deal with. They encourage shallower nesting of styles and prevent us from creating styles that promote dependency between parent and child because every component and every sub-component get styled independently. Naturally, the base or sub-components precede the more complex components so we can build our templates from the inside out and think of our styles in terms of objects and the smaller objects with which they are composed. In the end, we can achieve consistency across our entire application by writing less CSS, thus living happier, much more sane lives as developers over all.