BEM

Every component in ln follows the Block Element Modifier convention, namespaced with a configurable prefix.

What is BEM

BEM stands for Block, Element, Modifier. It is a naming convention for CSS classes that makes the relationship between HTML and CSS explicit and predictable.

  • Block — a standalone component: .ln-button
  • Element — a part of a block that has no meaning on its own: .ln-button__icon
  • Modifier — a variant or state of a block or element: .ln-button--solid

Naming pattern

All block classes are prefixed with $prefix (default ln-). Elements use double underscores and modifiers use double dashes.

texttext
.{prefix}{block}
.{prefix}{block}__{element}
.{prefix}{block}--{modifier}
.{prefix}{block}__{element}--{modifier}

In practice:

index.htmlhtml
<button class="ln-button ln-button--solid ln-button--lg">
  <span class="ln-button__icon">…</span>
  <span class="ln-button__label">Save</span>
</button>

The prefix

The ln- prefix namespaces every block class to avoid collisions with other CSS. Override it via the Sass source:

styles.scssscss
@use 'ln/scss' with (
  $prefix: 'my-'
);

// .my-button, .my-card, .my-alert, etc.

Utility classes (.d-flex, .m-3, etc.) and helper classes (.h1, .text-display-1, etc.) are not prefixed — they follow their own short-name conventions.

Sass mixins

The library uses three Sass mixins from tools/_bem.scss to generate the class names. Every block file follows the same pattern:

styles.scssscss
@use '../tools/bem' as b;

@include b.block('card') {
  // .ln-card { … }

  @include b.element('body') {
    // .ln-card__body { … }
  }

  @include b.modifier('horizontal') {
    // .ln-card--horizontal { … }
  }
}

The block mixin emits .#{$prefix}#{$name}, so changing the prefix renames every class at compile time.

Cascade layers

All block styles are emitted inside the blocks cascade layer. The full layer order is:

styles.csscss
@layer reset, tokens, base, layout, blocks, helpers, utilities;

This means utilities and helpers always override block defaults without needing specificity tricks. A .d-flex utility on a block element wins by layer order, not by selector weight.

Guidelines

  • Never style a block class from outside its own file — reach for a modifier or utility instead.
  • Elements belong to the block, not to other elements. Avoid nesting elements: .ln-card__body__title is wrong — use .ln-card__title.
  • Modifiers are additive. The base block class is always present: class="ln-button ln-button--solid", never just class="ln-button--solid".
  • Responsive modifiers use an @{bp} suffix: .ln-button--lg@md applies the large size from the md breakpoint up.

Further reading

Reference

PatternExampleDescription
.prefix-block.ln-buttonBlock root class
.prefix-block__element.ln-button__iconChild element of a block
.prefix-block--modifier.ln-button--solidVariant or state
.prefix-block--modifier@bp.ln-button--lg@mdResponsive modifier