Conventions

Naming classes

Every framework class starts with ng- and uses dashes for every level. No BEM, no arbitrary names: states, modifiers and colour tokens are closed sets.

The naming grammar is strict on purpose: reading a class tells you what it is (component, sub-element, variant or modifier) without opening the stylesheet — and tooling can rely on the pattern.

Component pattern

_ng_component.scss
.ng-<name>                  /* component base       — .ng-card                */
.ng-<name>-<sub>            /* sub-element          — .ng-card-head           */
.ng-<name>-<variant>        /* semantic variant     — .ng-btn-primary         */
.ng-<name>-<variant>-<mod>  /* variant + modifier   — .ng-btn-primary-outline */

Sub-elements nest with dashes, one level at a time — never BEM separators (__, --):

_ng_card.scss
.ng-card
.ng-card-head
.ng-card-head-left
.ng-card-body
.ng-card-section
.ng-card-foot
ng-card__headng-card-head ✅ — dash levels, no BEM.
ng-btn-outline-primaryng-btn-primary-outline ✅ — modifier comes after the colour.
card-headng-card-head ✅ — the ng- prefix is never dropped.

State classes

States are applied alongside the component class (class="ng-tab is-active"), usually by the component JS. The set is closed — never invent new ones:

is-activeActive state (current tab, selected sidebar link).
is-openOpen (dropdown, popover, modal, sidebar drawer).
is-hiddenHidden (page-loader after fade out).
is-loadingLoading in progress (button with auto-disable).
is-disabledDisabled (sub-elements that cannot take the disabled attribute).
is-selectedSelected (list item, table row).
is-errorError (input validation).
is-submenu-activeSidebar submenu open.

Has classes

has-errorField wrapper with a validation error.
has-iconContainer with an inner icon.

Modifier classes

Plain modifiers sit next to the component class and tweak one aspect:

hover.ng-card.hover — hover effect variant.
bordered.ng-list.bordered — border between items.
divided.ng-list.divided — divider between items.
selectable.ng-list.selectable — clickable items, single active.
removable.ng-chip.removable — chip with close button.
dismissible.ng-alert.dismissible — alert with close button.
dark.ng-page-loader.dark — dark backdrop variant.
right.ng-overlay.right — drawer from the right.
with-arrow.ng-popover.with-arrow — popover with visible arrow.

Colour tokens

Colour variants always use a token from the palette, as a suffix: ng-btn-primary, ng-badge-info, ng-alert-warning. Arbitrary colour names don't exist.

Semantic

primary
secondary
success
info
warning
danger
mute

Extended

blue
blue-sky
green
lime
aguagreen
indigo
purple
purple-heart
cyan
magenta
yellow

Variant suffixes

Treatment modifiers are a closed set too, and always come after the colour:

-outlineBorder + transparent background.
-softSoft tinted background + coloured text.
-ghostMinimal: no background, no border.
-linkLooks like a link, behaves like a button.
-squareComponent-specific square variant (e.g. ng-toggle-square).

Shapes are plain modifiers instead: quad (icon-only square) and circle sit next to the class — ng-btn ng-btn-primary quad.

naming.html
<button type="button" class="ng-btn ng-btn-primary">Solid</button>
<button type="button" class="ng-btn ng-btn-primary-outline">Outline</button>
<button type="button" class="ng-btn ng-btn-primary-soft">Soft</button>
<button type="button" class="ng-btn ng-btn-primary-ghost">Ghost</button>
<button type="button" class="ng-btn ng-btn-primary-link">Link</button>
<button type="button" class="ng-btn ng-btn-primary quad" aria-label="Settings">
    <i class="ph ph-gear"></i>
</button>

Scoped CSS variables

Each component declares its knobs with an abbreviated prefix; globals live in _ng_variables.scss. Never create a variable without the --ng- prefix.

_ng_popover.scss
.ng-popover {
    --ng-pop-bg: var(--ng-surface, #fff);
    --ng-pop-shadow: 0 4px 16px rgba(0,0,0,.15);
}

/* globals live in _ng_variables.scss; scoped knobs use the
   component abbreviation: --ng-pop-*, --ng-snackbar-*, --ng-range-* */