rsBEM v2.0.0

rRoute / Root
sScoped / Strict
BEMBlock Element Modifier

A layered CSS naming system for MVC projects.

Three layers β€” one convention β€” zero ambiguity.

πŸ—οΈ The Three Layers

LayerNamePatternScope
1 Template (rsBEM) folder-file__element--modifier Styles for a single .tpl file
2 Component (BEM) block__element--modifier Shared, reusable UI components
3 Utility prefix-value Single-purpose global helper classes

Decision Flowchart

Is this style for a single template file?
β”œβ”€β”€ YES β†’ Layer 1 (Template / rsBEM)
β”‚         .sale-return_request__save-btn
└── NO β†’ Is it a reusable UI component (library or project-specific)?
         β”œβ”€β”€ YES β†’ Layer 2 (Component / BEM)
         β”‚         .modal__header  .btn--pri  .admin-heading__title
         └── NO β†’ Is it a single-purpose CSS property?
                  └── YES β†’ Layer 3 (Utility)
                            .d-flex  .padding-sm  .text-center

πŸ“ Layer 1: Template (rsBEM)

[folder]sale
-
[file_name]return_request
__
[element-name]process-step
--[modifier]active

Why hyphen as the separator? Underscores are used within folder and file names (snake_case). The hyphen (-) is reserved exclusively as the folder↔file separator, making parsing unambiguous.

Segment Separator Case Description
folder start preserves original Template directory name (keeps snake_case if the directory uses it)
file_name - after folder preserves original Template file name (keeps snake_case if the file uses it)
element-name __ kebab-case Describes what the element is
modifier -- kebab-case State or variant

πŸ”— File Mapping

The class prefix maps 1:1 to the template path. A Ctrl + Shift + F search on any class locates both the template and its styles.

view/sale/return_request.tpl β†’ .sale-return_request__…
view/catalog/product_form.tpl β†’ .catalog-product_form__…
view/common/dashboard.tpl β†’ .common-dashboard__…

Multi-Word Folder

view/user_settings/profile_form.tpl β†’ .user_settings-profile_form__…

Nested Folder

When templates live in nested directories, each folder segment is separated by a hyphen β€” the same separator used between folder and file. The last segment before __ is always the file:

view/marketplace/partner/claim.tpl β†’ .marketplace-partner-claim__…

🧠 Core Principles

1. Flat Hierarchy β€” No DOM Nesting

The HTML tree is not mirrored in class names. The element name describes what it is, not where it sits.

❌ .sale-return_request__form_footer_save_btn (DOM-coupled)

βœ… .sale-return_request__save-btn (flat identity)

2. Semantic Grouping β€” Hyphens Group, Underscores Separate

Hyphens express logical grouping within element names. Underscores are not used for sub-elements.

❌ __process_bubble (false hierarchy)

βœ… __process-bubble (semantic group)

3. Descriptive Names β€” No Ambiguity

Element names are specific enough to understand without surrounding context.

❌ __step (which step?)

βœ… __process-step (clear intent)

βœ… Correct vs ❌ Incorrect

βœ… Correct

Flat, scoped, descriptive:

  • .sale-return_request__save-btn
  • .sale-return_request__process-step--done
  • .user_settings-profile_form__avatar
  • .marketplace-partner-claim__status-badge

❌ Incorrect

Generic, nested, or vague:

  • .btn-save (which page?)
  • ...__form_footer_btn (nested)
  • .user-settings-profile_form__… (folder converted to kebab)

πŸ”€ rsBEM vs BEM

AspectBEMrsBEM
Block namingFree-formFile-route prefix
File locationUnknown from classReadable from class name
ScopeComponent-scopedFile/template-scoped
ReusabilityCross-projectWithin project
SearchabilityRequires conventionBuilt-in (grep friendly)

βš™οΈ Stylelint Rule

{
  "rules": {
    "selector-class-pattern": [
      "^[a-z][a-z0-9]*(?:_[a-z0-9]+)*(?:-[a-z][a-z0-9]*(?:_[a-z0-9]+)*)+__[a-z][a-z0-9]*(?:-[a-z0-9]+)*(?:--[a-z0-9]+(?:-[a-z0-9]+)*)?$",
      {
        "message": "Class names must follow rsBEM: [folder]-[file_name]__[element-name]--[modifier]"
      }
    ]
  }
}

🧩 Layer 2: Component (Standard BEM)

Shared, reusable UI components (library or project). No file-path prefix β€” just standard BEM.

RuleCorrectIncorrect
Sub-elements use __ .tooltip__arrow .tooltip-arrow
Modifiers use -- .tooltip--top .tooltip.top
Block name is kebab-case .slide-menu__header .slide-menu-header

Examples: .modal__header, .btn--pri, .switch__slider, .tab__head--active, .admin-heading__title, .status--danger

πŸ”§ Layer 3: Utility

Single-purpose, composable classes. Pattern: prefix-value. No BEM structure.

CategoryPrefixExamples
Displayd-d-flex, d-grid, d-none
Flexflex-flex-center, flex-col, flex-gap-md
Paddingpadding-padding-sm, padding-y-md
Marginmargin-margin-sm, margin-t-md
Texttext-text-center, text-upper, text-nowrap
Font Sizefsi-fsi-14, fsi-16, fsi-20
Font Weightfwe-fwe-semibold, fwe-bold
Imageimg-img-responsive, img-circle
Theme Colortc-tc-pri-500, tc-text-dark-1
Theme BGtbc-tbc-pri-100, tbc-grey-300
Width / Heightw- / h-w-full, h-auto
Positionpos-pos-relative, pos-absolute
Cursorcursor-cursor-pointer, cursor-default

Three layers cover everything: Template (rsBEM) for page-specific styles, Component (BEM) for shared UI, Utility for atomic classes.

rsBEM v2.0.0 β€” 2025. A layered CSS naming system for MVC projects.