Forum

Methodology

Toolbox

Platform

Community

File system organization

A component-based approach used in the BEM methodology also determines the way that BEM projects are organized in a file system. In BEM, it's not just the interface that is divided into independent components, i.e. blocks, but the implementation of blocks is also divided into independent parts, namely files.

Below on this page you will find:

Principles of file system organization for BEM projects

In a BEM project, the code is broken down into small independent parts, to make working with individual blocks easier. Before they are sent to the browser, the files are assembled and optimized. That way we separate the human-manipulated code from the code that is sent to the browser.

In the file system, the codebase of BEM project is organized according to the following principles:

A block implementation is divided into separate files

A file set for a block (e.g., input.css, input.js) is determined by the technologies that make up the implementation of the block.

Why?

Optional elements and modifiers are stored in separate files

Why?

Files are grouped by meaning and not by type

Block files are grouped together based on common naming rules. For convenience, they can be grouped into a block directory.

Why?

A project is divided into redefinition levels

The final implementation of a block can be split into redefinition levels.

Why?

File system organization of a BEM project

For every block, there's a directory in the file system. The directory is named after the block.

blocks/
    input/     # input block directory
    button/    # button block directory

A block implementation is divided into separate files known as technology files. The files all have the same name as the block. The extension of each file corresponds to its technology.

blocks/
    input/
        input.css       # input block implementation in CSS
        input.js        # input block implementation in JavaScript
    button/
        button.css
        button.js
        button.png

Names of files and directories for BEM entities are based on the naming convention:

Modifiers and elements are stored in separate files and are grouped into accordingly named block subdirectories.

blocks/
    input/
        _type/                        # type modifier directory
            input_type_search.css     # Implementation of modifier type
                                      # with value search in CSS technology
        __box/                        # box element directory
            input__box.css
        input.css
        input.js
    button/
        button.css
        button.js
        button.png

If there are modifiers that differ in value (e.g., popup_target_anchor.extension and popup_target_position.extension), the shared code can be stored in a separate file (popup_target.extension) with no modifier value included in the name.

blocks/
    popup/
        _target/
            popup_target.css            # Common code of  modifier target
            popup_target_anchor.css     # Modifier target with value anchor
            popup_target_position.css   # Modifier target with value position
        _visible/
            popup_visible.css           # Boolean modifier visible
    popup.css
    popup.js

Real-life examples

Examples of using redefinition levels

The implementation of a block can be divided into redefinition levels.

Let's take a few examples:

Linking a library

A library can be linked to a project as a separate level. Blocks can be modified (extended or redefined) at another project level. During the build process the original block implementation will be linked from the library level and the redefined one from the project level.

Such an arrangement allows us to preserve changes made to the blocks if the library gets updated — the library source code will be updated while the specific implementation of the project blocks will remain the same because it is stored at a different level.

library.blocks/
    button/
        button.css    # CSS implementation in the linked library (height 20px)
project.blocks/
    button/
        button.css    # Redefinition of CSS implementation (height 24px)

Dividing a project into platforms

A project is divided into platforms (mobile and desktop) and into respective redefinition levels in the file system. The common level contains the implementation of blocks that is common to both platforms. The desktop and mobile levels contain platform-specific block implementations.

Let's look at an example:

common.blocks/
    button/
        button.css    # Generic CSS implementation of the button
desktop.blocks/
    button/
        button.css    # Desktop platform-specific button features
mobile.blocks/
    button/
        button.css    # Mobile platform-specific button features

During the build process, all the generic CSS rules for the button will be included in the desktop.css file from the common level, and the redefined rules from the desktop level.

@import(common.blocks/button/button.css);    /* Generic CSS rules */
@import(desktop.blocks/button/button.css);   /* Desktop platform-specific */

The mobile.css file will include the generic CSS rules for the button from the common level and the redefined rules from the mobile level.

@import(common.blocks/button/button.css);    /* Generic CSS rules */
@import(mobile.blocks/button/button.css);    /* Mobile platform-specific */
If you notice a mistake or want something to supplement the article, you can always write to us at GitHub, or correct an article using prose.io.