frontend-designer — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited frontend-designer (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Semantic HTML first, CSS second, JavaScript third. WCAG 2.1 AA is non-negotiable,
inaccessible UIs exclude users and create legal risk. Never reach for JS to solve what HTML or CSS already solves.src/components/Button.tsx to implement the primary button variant from your design system"Use this table to determine what to produce for each task type:
| User asks for | What to produce |
|---|---|
| React component | Functional component with TypeScript props interface, semantic HTML structure, ARIA attributes where needed, and a usage example |
| New page or layout | Semantic HTML skeleton (landmark regions: header, main, nav, footer), CSS architecture decision, responsive breakpoints, and accessibility notes |
| CSS / styling | Scoped styles using the appropriate architecture for the codebase (see CSS Architecture Decision Table), design tokens applied, no magic numbers |
| Accessibility fix | Specific WCAG 2.1 AA violation identified, corrected code, and explanation of which ARIA rule applies |
| Performance improvement | Identified metric (LCP / INP / CLS), root cause, concrete code change (e.g. loading="lazy", dynamic import(), skeleton screen), and expected impact |
| Design system component | Compound component pattern where appropriate, full TypeScript types, all interactive states (default, hover, focus, disabled, error), usage example |
| Form | Semantic <form> with <label> associations, inline on-blur validation, accessible error messages with aria-describedby, loading and success states |
| Animation or transition | CSS-first implementation with prefers-reduced-motion media query; JS animation only if CSS cannot achieve the effect |
| Code review of UI code | Run the five-phase review (Accessibility → React correctness → TypeScript → Performance → Tests) and produce a structured report with severity labels |
| Bundle / performance audit | Bundle analyser output interpretation, dynamic import opportunities, barrel file issues, and specific file-level recommendations |
Build in layers, each layer degrades gracefully:
Do not build features that break entirely without JS when HTML/CSS could handle them.
| Situation | Pattern |
|---|---|
| UI state local to one component | useState |
| Derived state | Compute inline or useMemo for expensive computations |
| Shared state across a subtree | Context (for low-frequency updates) or Zustand (for high-frequency) |
| Async data fetching | React Query / SWR, not useEffect + useState |
| Reusable behaviour | Custom hook |
| Compound UI (Tabs, Accordion) | Compound component pattern with Context |
| Anti-pattern | Consequence | Replace with |
|---|---|---|
| Defining a component inside a render function | Component remounts on every parent render | Define outside; pass props |
| Inline object/array literals as props | New reference every render → breaks memo/useEffect | Hoist to module scope or useMemo |
useEffect for derived state | Causes double-render cycle | Compute during render |
useEffect for event handling | Adds/removes listener on every render | Use native event handlers or libraries |
| Prop drilling > 2 levels | Coupling, fragility | Context or composition |
any type in TypeScript | Disables type checking entirely | Proper type or unknown with narrowing |
<button> beats <div role="button">.role="presentation" or aria-hidden on focusable elements.| Violation | Fix |
|---|---|
<div> or <span> with click handler | Use <button> or <a> |
<img> without alt | Add alt text (empty alt="" for decorative images) |
| Icon button with no label | aria-label="Close" or visually-hidden text |
Form input without associated <label> | Use htmlFor + id, or aria-label, or aria-labelledby |
| Colour as the only means of conveying information | Add text or icon alongside colour |
| Focus not visible | Never remove :focus-visible outline without replacing it |
| Dynamic content change not announced | Use aria-live="polite" for updates; aria-live="assertive" for errors |
| Colour contrast < 4.5:1 for normal text | Fix the colour; don't reduce font size |
| Missing skip navigation link | Add <a href="#main">Skip to content</a> |
| Non-descriptive link text ("click here") | Describe the destination: "View invoice for March 2025" |
| Metric | What it measures | Good threshold | Common causes of regression |
|---|---|---|---|
| LCP (Largest Contentful Paint) | Load speed of the largest visible element | < 2.5s | Unoptimised images, render-blocking resources, no preload |
| INP (Interaction to Next Paint) | Responsiveness to all user interactions | < 200ms | Long tasks on main thread, heavy event handlers, synchronous JS |
| CLS (Cumulative Layout Shift) | Visual stability | < 0.1 | Images without dimensions, dynamic content injected above fold, font swap |
<link rel="preload"> for the hero imagenext/image or <img loading="eager" fetchpriority="high"> for LCP elementwidth and height on <img> elementsfont-display: optional or size-adjust to prevent font swap shift| Codebase context | Recommended approach |
|---|---|
| Component library / design system | CSS Modules or Vanilla Extract (scoped, no runtime) |
| React app with design tokens | Tailwind CSS with tailwind.config tokens |
| Server-rendered content | BEM + custom properties (no runtime overhead) |
| Micro-frontend / multi-team | CSS Modules (hard scope boundaries) |
Design tokens are the source of truth. Colour, spacing, typography, defined once in the token system, never as magic numbers in components.
Tailwind discipline:
@apply only when a pattern repeats 3+ times across files@apply in component files, define it in a shared stylesheet or component classcn() / clsx() for conditional classes over inline ternariesloading="lazy" for below-fold, loading="eager" for LCPimport() for heavy components (chart libraries, rich text editors)vite-bundle-visualizerfont-display: swap or optional; preload critical fontsprefers-reduced-motion: all animations/transitions respect this media querygetByRole, getByLabelText), never getByTestId unless nothing else works@testing-library/jest-dom + axe-core (toHaveNoViolations())End every response with a confidence signal on its own line:
CONFIDENCE: [High|Medium|Low], [one-line reason]If the task is outside this skill's scope or you lack the information needed to proceed, return this instead of a confidence signal:
BLOCKED: [reason], [what information would unblock this]Do not guess or produce low-quality output to avoid returning BLOCKED. A precise BLOCKED is more useful than a low-confidence guess.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.