From frontend-angular
Angular styling patterns including Prismatic Angular (org default UI library), Angular Material, Bootstrap, SCSS scoped styles, ViewEncapsulation, Tailwind, responsive design, and theming with CSS custom properties.
How this skill is triggered — by the user, by Claude, or both
Slash command
/frontend-angular:angular-stylingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
`@Vensure-Devops-QA/prismatic-angular` is the organization's default UI library for Angular projects. Use it before reaching for Angular Material or other libraries.
@Vensure-Devops-QA/prismatic-angular is the organization's default UI library for Angular projects. Use it before reaching for Angular Material or other libraries.
npm install @Vensure-Devops-QA/prismatic-angular
// app.config.ts
import { providePrismatic } from '@Vensure-Devops-QA/prismatic-angular';
export const appConfig: ApplicationConfig = {
providers: [
providePrismatic({ theme: 'light' }),
],
};
Import the global token stylesheet in styles.scss:
@use '@Vensure-Devops-QA/prismatic-angular/tokens' as tokens;
@use '@Vensure-Devops-QA/prismatic-angular/base';
import { PrismaticButtonModule, PrismaticInputModule } from '@Vensure-Devops-QA/prismatic-angular';
@Component({
standalone: true,
imports: [PrismaticButtonModule, PrismaticInputModule],
template: `
<prs-input label="Email" [(ngModel)]="email" type="email" />
<prs-button variant="primary" (click)="submit()">Submit</prs-button>
`,
})
export class LoginFormComponent {
email = signal('');
submit() { /* ... */ }
}
Reference design tokens via CSS custom properties. Do not hard-code colors, spacing, or typography values — always use tokens.
.card {
background: var(--prs-color-surface-default);
border: 1px solid var(--prs-color-border-default);
border-radius: var(--prs-radius-md);
padding: var(--prs-spacing-4);
color: var(--prs-color-text-primary);
font-family: var(--prs-font-family-base);
}
.card__title {
font-size: var(--prs-font-size-lg);
font-weight: var(--prs-font-weight-semibold);
margin-bottom: var(--prs-spacing-2);
}
Use Angular Material when Prismatic does not cover a needed component.
ng add @angular/material
// app.config.ts
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
export const appConfig: ApplicationConfig = {
providers: [provideAnimationsAsync()],
};
Define a custom theme in styles.scss:
@use '@angular/material' as mat;
// Define typography
$my-typography: mat.define-typography-config(
$font-family: 'Inter, sans-serif',
);
// Define palette
$my-primary: mat.define-palette(mat.$indigo-palette, 600);
$my-accent: mat.define-palette(mat.$pink-palette, A200);
// Build theme
$my-theme: mat.define-light-theme((
color: (primary: $my-primary, accent: $my-accent),
typography: $my-typography,
density: 0,
));
@include mat.all-component-themes($my-theme);
import { MatButtonModule } from '@angular/material/button';
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
@Component({
standalone: true,
imports: [MatButtonModule, MatInputModule, MatFormFieldModule, ReactiveFormsModule],
template: `
<mat-form-field appearance="outline">
<mat-label>Email</mat-label>
<input matInput type="email" [formControl]="emailControl" />
</mat-form-field>
<button mat-raised-button color="primary" (click)="submit()">
Submit
</button>
`,
})
export class FormComponent { }
Use CDK for behavior without pre-styled components (overlays, drag-and-drop, virtual scrolling, a11y).
import { DragDropModule } from '@angular/cdk/drag-drop';
import { ScrollingModule } from '@angular/cdk/scrolling';
import { A11yModule } from '@angular/cdk/a11y';
For projects using Bootstrap as the CSS framework, use ng-bootstrap for Angular-native components.
npm install @ng-bootstrap/ng-bootstrap bootstrap
// app.config.ts
import { provideNgbDateAdapter } from '@ng-bootstrap/ng-bootstrap';
// Import Bootstrap SCSS in styles.scss
// styles.scss
@import 'bootstrap/scss/bootstrap';
import { NgbModalModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
Each component has its own scoped SCSS file. Angular's view encapsulation prevents style leakage by default.
@Component({
selector: 'app-product-card',
standalone: true,
templateUrl: './product-card.component.html',
styleUrl: './product-card.component.scss',
})
export class ProductCardComponent { }
// product-card.component.scss
// Use CSS custom properties for values that vary (theming, states)
:host {
display: block;
--card-border-color: var(--prs-color-border-default);
}
// Host-context modifier
:host([variant='featured']) {
--card-border-color: var(--prs-color-brand-primary);
}
.product-card {
border: 1px solid var(--card-border-color);
padding: var(--prs-spacing-4);
}
.product-card__title {
font-size: var(--prs-font-size-lg);
}
::ng-deep::ng-deep pierces the view encapsulation boundary and causes global style leaks. It is deprecated.
Instead of ::ng-deep, prefer:
ViewEncapsulation.None option only on layout/wrapper components with global scope intentstyles.scss using the component's public selector// BAD — do not do this
::ng-deep .mat-mdc-form-field { border-radius: 8px; }
// GOOD — override via CSS custom property (if the library exposes it)
.my-form {
--mdc-outlined-text-field-container-shape: 8px;
}
| Mode | Behavior | When to Use |
|---|---|---|
Emulated (default) | Adds attribute selectors to scope styles | Most components |
ShadowDom | Uses native Shadow DOM | Web components, max isolation |
None | No encapsulation, global styles | Layout shells, global theme wrappers |
@Component({
encapsulation: ViewEncapsulation.None, // only when truly needed
...
})
For projects using Tailwind CSS:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init
// tailwind.config.js
module.exports = {
content: ['./src/**/*.{html,ts}'],
theme: { extend: {} },
plugins: [],
};
/* styles.scss */
@tailwind base;
@tailwind components;
@tailwind utilities;
Combine Tailwind utilities with Prismatic tokens:
<div class="flex flex-col gap-4 p-6 rounded-lg"
style="background: var(--prs-color-surface-default)">
<h2 class="text-xl font-semibold" style="color: var(--prs-color-text-primary)">
Title
</h2>
</div>
Do not mix Tailwind color utilities with Prismatic color tokens on the same element — use one system per project. Prefer Prismatic tokens when both are available.
Use CSS custom properties and media queries for responsive layouts. Angular CDK BreakpointObserver for programmatic breakpoint detection.
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
@Component({ standalone: true, ... })
export class AppShellComponent {
private breakpointObserver = inject(BreakpointObserver);
isMobile = toSignal(
this.breakpointObserver.observe([Breakpoints.Handset]).pipe(
map(result => result.matches)
),
{ initialValue: false }
);
}
<app-sidebar *ngIf="!isMobile()" />
<app-bottom-nav *ngIf="isMobile()" />
// _breakpoints.scss
$bp-sm: 640px;
$bp-md: 768px;
$bp-lg: 1024px;
$bp-xl: 1280px;
@mixin respond-to($bp) {
@media (min-width: $bp) { @content; }
}
.grid {
display: grid;
grid-template-columns: 1fr;
@include respond-to($bp-md) {
grid-template-columns: repeat(2, 1fr);
}
@include respond-to($bp-lg) {
grid-template-columns: repeat(3, 1fr);
}
}
Support light/dark modes and org-level theming via CSS custom properties.
// styles.scss — base theme (light)
:root {
--color-bg-primary: #ffffff;
--color-bg-secondary: #f8f9fa;
--color-text-primary: #1a1a1a;
--color-text-secondary: #6b7280;
--color-brand: #6366f1;
--color-border: #e5e7eb;
}
// Dark mode
@media (prefers-color-scheme: dark) {
:root {
--color-bg-primary: #0f0f0f;
--color-bg-secondary: #1a1a1a;
--color-text-primary: #f9fafb;
--color-text-secondary: #9ca3af;
--color-brand: #818cf8;
--color-border: #374151;
}
}
// Class-based theme switching
.theme-dark {
--color-bg-primary: #0f0f0f;
// ...
}
@Injectable({ providedIn: 'root' })
export class ThemeService {
private theme = signal<'light' | 'dark'>('light');
readonly currentTheme = this.theme.asReadonly();
toggleTheme() {
const next = this.theme() === 'light' ? 'dark' : 'light';
this.theme.set(next);
document.documentElement.className = `theme-${next}`;
localStorage.setItem('theme', next);
}
initTheme() {
const saved = localStorage.getItem('theme') as 'light' | 'dark' | null;
const preferred = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
const theme = saved ?? preferred;
this.theme.set(theme);
document.documentElement.className = `theme-${theme}`;
}
}
npx claudepluginhub gagandeepp/software-agent-teams --plugin frontend-angularGuides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Enforces test-driven development: write failing test first, then minimal code to pass. Use when implementing features or bugfixes.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.