Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs: add "components.md" documentation. #427

Merged
merged 2 commits into from
Nov 23, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions docs/components.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Components

The UI of Calypso is built with _components_ and _sub-components_. We have constructed a system that allows us to enjoy benefits of style encapsulation and benefits from the natural CSS cascade (and native toolset) at the same time.

Our use of composition is one that embraces CSS reusability, with the cascade as a useful tool, but through composition — we reuse components not classes.

## Glossary

This document focuses on UI components, not data containers or other non-UI pieces. That is, React components that directly render HTML elements and require the addition of class attributes for styling. We have essentially two kinds of these:

* `component/index.jsx`
* `component/sub-component.jsx`

We'd call one "component" and the other "sub-component".

![Components!](https://cldup.com/CP_Z6Cqec--3000x3000.png)

A component is represented by the folder holding the main `index.jsx` file, and a sub-component is any other jsx file used to render pieces of a component. The folder is the "component" namespace and determines the class prefix for any sub-component in that folder. The only folder that matters for _namespacing_ is the immediate container of the jsx files.

There are three resulting aspects of this distinction:

* There's only one `style.scss` per component.
* Classes (both in components and sub-components) are always prefixed to the `component` name.
* Sub-folders do not care about their parent folder for any functional purposes.

That means a sub-component needs to write its HTML classes using the folder name (the component), and its styles will go to the folder's `style.scss` file. The decision to turn a sub-component into a component should take this into account, because once you do so its scope and prefix becomes global and independent.

## Syntax

We write classes like `.my-component__element` to indicate the component an element belongs to. Thus, component names (the folder holding the "index.jsx" file) need to be written with a global scope, specific, and clear enough in meaning.

We avoid vanilla _html_ selectors like `.my-component h1` in favor of `.my-component__title` whenever possible.

We also avoid Sass indentation outside of pseudo-selectors, media-queries, and `is-modifiers`. Most selectors should be a single class selector at the root of a style file. For more details on how we write and structure Sass code, look at the [Sass/CSS document](coding-guidelines/css.md).

## Folders

Any component folder should be able to be moved to `client/components` at any time without losing meaning or having conflicts. We place components in folders for organizational purposes, but they are not semantically coupled to this structure.

### Example

If we are creating a component to render post meta information and placing it in `my-sites/posts/meta-info`, we consider that to be incorrect. `meta-info` is too generic, its meaning obscure on its own — remember the sub-folder is not aware of its container —, and should better be written as `post-meta` or `post-meta-info`, regardless of what the parent folder may happen to be.

Imagine any folder with a jsx as a flat list of components.

Here's another example with `post-navigation` on how this decisions affect how we write the UI pieces:

If we place it in `posts/navigation.jsx` the classes used would be `.posts__navigation`, reflecting it's a sub-component of `posts` and would move with it anywhere `posts` goes. But if we move it to its own folder `posts/posts-navigation/index.jsx` then it would be written as `.posts-navigation`, and it would become its own piece independent of `posts`. If it is kept under the posts directory is only for organization.

Any of these are right approaches, the reason to create a folder should be a matter of _how independent we want a piece to be_, and whether it will be usable in other places. Any folder groupings outside of the immediate parent are purely organizational and should have no effect in the classes used or the naming of the components themselves.

## Reusability

Components are reusable in nature, regardless of where they are placed in the directory structure. This is an important clarification, since we don't place components in folders based on whether they are reusable or not. It's not a requirement for a component to live in `client/components` to be reused. Indeed, we use the `my-sites/site` component to render the current site in the editor, to render the site picker in the sidebar, to render sites in "Me", etc. The pieces that go to "client/components" are those that don't have a natural preference to one of our main section groups and are thus purer UI building blocks.

## Expressiveness

One advantage of avoiding inline JS styles as props are the times modifications of a child in the context of a remote parent are needed.

Imagine you want to change the border color of a `SiteIcon` component when it is displayed in the sidebar of `my-sites`. That `SiteIcon` component happens to be rendered within a `Site`, within a `SiteSelector`, and finally in a `Sidebar`.

If we were doing inline styles it would mean we need to pass down a style prop from `sidebar` (the component that wants to make the modification) all the way down to `site-icon` to modify that specific border style value. Which is messy, obscure, and requires passing down a meaningless attribute through components that don't care about it, coupling them with a design intent you want to express in the "Sidebar". Now, with CSS and our naming guidelines it becomes just an old `.sidebar .site-icon {}` on the sidebar's `style.scss` file.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree with one aspect of this. I think it would be better for the .sidebar .site-icon {} directive to live in the site-icon's style.scss file. So all of the styles related to site-icon are in one place and very easy to see and be aware of together. You also can see that some change you are trying to make would potentially be out-specified in certain cases. Whereas you would likely miss that otherwise.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reasoning is that .sidebar .site-icon {} is really an aspect of the sidebar, not of site-icon, and should be placed together with the design aspects that make the sidebar. There's also no reason for site-icon to have any awareness of parent intentions. Another aspect of this is that if we start compiling separate .css files based on components used, any component using site-icon would be compiling styles for sidebar, which they shouldn't.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider all the positioning/color changes done to .gridicon. It would be incredibly messy to have all of that in gridicons/style.scss


That remains expressive, simple to read, and given our convention it immediately signals `site-icon` is a child component of `sidebar` at some level to whoever reads the styles or inspects them, reflecting the composition tree naturally in the stylesheet, and the intention of only modifying that individual component in this specific context. Since specificity also increases, it means it doesn't matter where in the build process the sidebar stylesheet order comes.