Styling Standards
June 15, 2026 · View on GitHub
Priority: Tailwind CSS + PrimeNG Theme
- Use Tailwind utility classes for layout, spacing, typography, colors, sizing, flexbox, and grid. Avoid custom SCSS when a Tailwind class exists.
- Use PrimeNG components instead of building custom UI (e.g.
p-button,p-inputText,p-card,p-dialog,p-table). PrimeNG theme tokens handle component styling automatically. - Minimize custom CSS — component
.scssfiles should be the exception, not the default. Most components should need zero or near-zero custom styles.
Tailwind Usage
<!-- ✅ Layout with Tailwind -->
<div class="flex items-center gap-4 p-4">
<span class="text-sm font-semibold text-color">Title</span>
<p-button label="Save" />
</div>
<!-- ✅ Responsive grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<p-card *ngFor="..." />
</div>
<!-- ❌ NEVER: custom CSS for what Tailwind handles -->
<div class="my-custom-flex-container">...</div>
When Custom SCSS Is Acceptable
Custom SCSS is only allowed for:
- PrimeNG component overrides (via
::ng-deepinside:host) - Complex animations or pseudo-element styles Tailwind cannot express
- Third-party library integration overrides
// ✅ PrimeNG override (scoped)
:host {
::ng-deep .p-datatable .p-datatable-header {
border-radius: var(--border-radius);
}
}
// ❌ NEVER: unscoped ::ng-deep
::ng-deep .p-button { color: red; }
// ❌ NEVER: custom SCSS for layout/spacing/colors
.my-container {
display: flex;
gap: 1rem;
padding: 16px;
color: #333;
}
SCSS Variables (when custom styles are needed)
@use "variables" as *;
.feature-overlay {
box-shadow: $shadow-m;
border: 1px solid $color-palette-gray-200;
}
Available Variables
- Spacing:
$spacing-0through$spacing-9 - Colors:
$color-palette-primary,$color-palette-gray-*, etc. - Shadows:
$shadow-s,$shadow-m,$shadow-l
Rules
- Tailwind first — use utility classes for layout, spacing, colors, typography, sizing.
- PrimeNG theme — rely on the theme for component styling; avoid overriding PrimeNG styles unless necessary.
- NEVER hardcode colors, spacing, or shadows in SCSS — use SCSS variables or Tailwind classes.
::ng-deepmust be scoped inside:host— never bare.- BEM naming (
Block__Element--Modifier) only when custom SCSS is truly needed. - Flat SCSS structure — no deeply nested selectors (max 3 levels).
- No
!importantunless justified with a comment.
Tags vs Chips
PrimeNG ships two visually similar but semantically different components. Pick by intent, not appearance.
p-tag— informative, read-only status display. Use it for anything that communicates state the user does not interact with directly: content status badges, locale labels, etc. Tags carry aseverity, so colors come from native severity states (configured once in thetagblock of the theme preset), never from per-template classes.p-chip— interactive or removable elements: filters, removable selections, anything the user can click or dismiss. Chips are mostly neutral gray and do not express severity.
Decision rule
-
Showing a contentlet status? Use the shared
<dot-contentlet-status-badge>component (libs/ui). It takes theDotContentStateand resolves the label, severity, and translation internally — do not hand-roll ap-tagfor contentlet statuses.<dot-contentlet-status-badge [state]="contentlet" /> -
Showing any other status / read-only state? Use
p-tagwith the matchingseverity(see mapping below). Example: the version-history timeline shows per-version states — not a contentletDotContentState— so it uses raw tags: this version is live →success, working copy →warn, experiment variant →info. -
Anything without a status — interactive, removable, or clickable items (filters, selections) — use
p-chip.
Severity mapping convention
| Severity | Status |
|---|---|
success | Published / live |
danger | Archived / deleted |
info | Revision / new |
warn | Draft |
Rules
- Always use
<dot-contentlet-status-badge>for contentlet statuses — never a rawp-tagorp-chip. - Locale/language labels use
p-tag severity="info"— locales are informative, never chips (e.g. the Locale column in Content Drive, the asset card language label). This applies to read-only locale display; interactive locale selectors are designed per area. - Never use
p-chipfor purely informational status — usep-tagwith aseverity. - Never add Tailwind
!importantcolor overrides (bg-green-100!,text-red-700!, etc.) to PrimeNG components. Rely on nativeseverityplus the preset color tokens intheme.config.ts.
See also
- ANGULAR_STANDARDS.md — Component rules, templates
- docs/frontend/README.md — Index of all frontend docs