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-<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
.ng-card-head
.ng-card-head-left
.ng-card-body
.ng-card-section
.ng-card-foot
ng-card__head ❌ | ng-card-head ✅ — dash levels, no BEM. |
|---|---|
ng-btn-outline-primary ❌ | ng-btn-primary-outline ✅ — modifier comes after the colour. |
card-head ❌ | ng-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-active | Active state (current tab, selected sidebar link). |
|---|---|
is-open | Open (dropdown, popover, modal, sidebar drawer). |
is-hidden | Hidden (page-loader after fade out). |
is-loading | Loading in progress (button with auto-disable). |
is-disabled | Disabled (sub-elements that cannot take the disabled attribute). |
is-selected | Selected (list item, table row). |
is-error | Error (input validation). |
is-submenu-active | Sidebar submenu open. |
Has classes
has-error | Field wrapper with a validation error. |
|---|---|
has-icon | Container 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:
-outline | Border + transparent background. |
|---|---|
-soft | Soft tinted background + coloured text. |
-ghost | Minimal: no background, no border. |
-link | Looks like a link, behaves like a button. |
-square | Component-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.
<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 {
--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-* */