frontend-ui-engineering
Builds high-quality React 19 UIs following strict SmartFinance design and performance conventions.
Install
mkdir -p .claude/skills/frontend-ui-engineering-pm4-smartfinance && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/14632" && unzip -o skill.zip -d .claude/skills/frontend-ui-engineering-pm4-smartfinance && rm skill.zipInstalls to .claude/skills/frontend-ui-engineering-pm4-smartfinance
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Builds production-quality React 19 UIs that match SmartFinance conventions. Use when creating or modifying components, layouts, forms, charts, or any user-facing interface. Use when accessibility, semantic HTML, or design-token compliance is at risk.Key capabilities
- →Build production-quality React 19 UIs
- →Use Zustand for client state management
- →Use TanStack Query for server state management
- →Enforce TypeScript strictness
- →Prioritize semantic HTML over ARIA
- →Ensure WCAG 2.1 AA accessibility compliance
How it works
This skill guides the development of React 19 UIs by enforcing specific architectural patterns, state management solutions (Zustand, TanStack Query), TypeScript strictness, semantic HTML, and WCAG 2.1 AA accessibility standards.
Inputs & outputs
When to use frontend-ui-engineering
- →Creating accessible React components
- →Implementing data-driven UI layouts
- →Building production-grade finance dashboards
About this skill
Frontend UI Engineering (SmartFinance)
Adapted from addyosmani/agent-skills — frontend-ui-engineering. Project specifics below.
Project Context
- React 19 (
react@^19.2.0). Useuse()overuseContext. Render<Context>directly as a provider. - TypeScript strict. No
any, no type assertions unless unavoidable. - Vite + Tailwind + CSS variables. Design tokens via
hsl(var(--primary))etc. No CSS-in-JS runtime. - TanStack Query for server state. Zustand for client state. Never mix.
fetchonly viasrc/lib/api.ts. No Axios.- No barrel files. Import directly.
- Recharts for charts.
react-routerfor routing (noreact-router-dom).- No business logic in components. Components receive data and render.
- Tests with Vitest +
@testing-library/react,@testing-library/user-event.
Component Architecture
Earn the abstraction
Inline JSX is fine. Don't extract a wrapper / layout / "atom" component until there are two or more consumers OR the inline JSX has real logic worth naming.
Colocation
Component-local types, helpers, and styles live next to the component. Promote to shared modules only on the second consumer.
One file per component
src/components/BudgetProgressWidget.tsx // component + local helpers
src/components/BudgetProgressWidget.test.tsx // tests
No index.ts re-exports.
Composition over configuration
// Yes
<Card>
<CardHeader><CardTitle>Budgets</CardTitle></CardHeader>
<CardContent>{children}</CardContent>
</Card>
// No — explodes into prop bombs
<Card title="Budgets" headerVariant="lg" content={<…/>} bodyPadding="md" />
Prop typing
- ≤3 fields: inline.
function Foo({ id, name }: { id: string; name: string }). - More: a named
Propsinterface in the same file. - Never
React.FC. Type the function, not the component. - Discriminated unions for prop variants over boolean flags.
Semantic HTML First
Reach for the right HTML element before adding ARIA.
| Use | Not |
|---|---|
<button type="button"> | <div role="button" tabIndex={0} onKeyDown={…}> |
<nav> | <div className="nav"> |
<main>, <section>, <article>, <aside> | nested <div> |
<dialog> (or Radix Dialog) | <div role="dialog"> |
<label htmlFor="x"> + <input id="x"> | floating text + bare input |
<form> with onSubmit | <div> + click-handler-on-button |
Native semantics give keyboard navigation, focus management, and screen-reader behavior for free. PR #93 left a drop zone as <div role="button"> — a real <button> would have removed the manual onKeyDown and tabIndex.
Accessibility (WCAG 2.1 AA)
- Color contrast ≥ 4.5:1 for text. Tailwind tokens already satisfy when used as designed.
- Keyboard reachability for every interactive element.
Tabcycles,Enter/Spaceactivates. - Visible focus ring. Don't
outline: nonewithout a replacement. aria-labelfor icon-only buttons.aria-live="polite"for non-blocking status (success / error toasts).role="alert"for blocking error messages.- Form errors announced near the input, with
aria-describedbylinking to the message. - Dialogs / popovers trap focus and restore it on close.
- Charts are visual sugar — pair with the underlying number in text. Recharts containers should never be the only source of information.
- Decorative SVGs get
aria-hidden="true". - Test with keyboard only at least once per feature.
State
Server state — TanStack Query
const { data, isLoading, error } = useBudgets({ period: "MONTHLY" });
- Always use the
apiutility asqueryFn(handles credentials, error normalization). - Query keys are descriptive arrays:
["budgets", { period }],["transactions", { page, filter }]. - Mutations invalidate by prefix array to refresh nested keys:
invalidateQueries({ queryKey: ["budgets"] }). - Multi-key invalidation after a write (e.g., import) — list the keys in a constant and iterate, OR use
Promise.all(await) to surface failures. error instanceof ApiErrorto accessstatus/body.
Client state — Zustand
const sidebarOpen = useAppStore((s) => s.sidebarOpen);
- Always select the minimal slice.
useAppStore()(full store) re-renders on every change. - Synchronous actions only. No fetching from a Zustand action.
- No auth state in Zustand —
useAuth()is server state via TanStack Query.
Don't mix
- Never copy server data into Zustand to "simplify" reads. Subscribe via TanStack Query.
- Never fetch in a
useEffectto seed Zustand. UseuseQuery.
Effects — minimize
Most useEffect is unnecessary. Before writing one:
- Could this be derived during render? Then drop the effect.
- Is it a side effect of an event? Move it to the event handler.
- Is it server data? Use
useQuery/useMutation. - Is it subscribing to an external store? Use
useSyncExternalStore(or wrap in a hook). - Is it logging derived state? Configure
QueryCache({ onError })globally instead of per-component effect.
If after that an effect still belongs in a component, keep its dependency array tight and prefer AbortController for any async work.
Styling
- Tailwind utilities first.
- Use design tokens —
hsl(var(--primary)),bg-destructive,text-muted-foreground. Don't hardcode hex (#ef4444) when a token exists. - Dark-mode awareness: tokens flip automatically. Hardcoded colors break dark mode.
- CSS Modules acceptable when utility soup hurts readability.
- No CSS-in-JS runtime libraries.
Forms
- Native
<form onSubmit>over click-handler-on-button. - Server-side validation is the source of truth; client-side is UX.
- Disable submit during pending mutation (
isPending). - Show server errors near the field where possible. Use
role="alert"for top-level error messages.
Loading / Empty / Error — three states, always
Every data-driven component handles all three:
if (isLoading) return <Skeleton />;
if (error) return <ErrorBanner onRetry={refetch} />;
if (!data?.length) return <EmptyState />;
return <List items={data} />;
The "no data yet" state is not the same as "error". The "error" state is not the same as "empty".
Testing
QueryClientProvider+MemoryRouterwrappers in test setup helpers.- Mock
apifrom../lib/api, notfetch. - Prefer
@testing-library/user-eventoverfireEvent. - Assert on what the user sees (
getByRole,getByText), not ongetByTestIdif a role works. - Avoid
mockReturnValueOnceordering — switch tomockImplementationkeyed on argument when a hook is called multiple times.
Anti-rationalization
| Excuse | Counter |
|---|---|
| "I need a wrapper component for consistency." | Two consumers minimum. Until then, inline. |
| "Adding ARIA fixes accessibility." | Native HTML fixes accessibility. ARIA is for when native doesn't fit. |
| "I'll memoize everything." | useMemo costs too. Measure first. Most components don't need it. |
"An useEffect to log errors is fine." | TanStack Query exposes errors. Log via global handler, not per-component effect. |
"I'll use any here, it's just a chart." | Charts are user-facing. any propagates. Type it. |
| "It's only one missing focus ring." | One missing focus ring breaks keyboard users. |
Red flags in PRs
<div role="button">/<div onClick>instead of<button>.- Hardcoded color hex when a token exists.
useEffectthat only logs.- TanStack Query data copied into
useState. - Component file with both fetching and UI logic and form state — split.
- Inline
style={{ ... }}with token-replaceable values. - Missing loading or empty state on a data-driven view.
- New chart with no text equivalent for accessibility.
Verification before merge
- Component renders correctly in dev (
bun run --filter @smartfinance/frontend dev). - Keyboard-only walkthrough of the changed UI works (Tab, Enter/Space, Esc).
- Loading / empty / error all visually verified.
- No new hardcoded color literals where a token exists.
- No new
useEffectfor fetching or for purely-derived state. - No new
any. - Tests use
getByRole/getByLabelTextovergetByTestIdwhere possible. - Dark mode visually correct.
When not to use it
- →When not using React 19, Zustand, or TanStack Query
- →When business logic is intended to be in components
- →When using Axios or CSS-in-JS runtime
Limitations
- →Specific to React 19, Zustand, and TanStack Query
- →Enforces strict TypeScript usage
- →Prohibits business logic within components
How it compares
This skill provides a highly opinionated and structured approach to frontend UI engineering, adhering to specific project conventions and tools, unlike general React development practices.
Compared to similar skills
frontend-ui-engineering side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| frontend-ui-engineering (this skill) | 0 | 1mo | No flags | Advanced |
| ui-ux-expert-skill | 91 | 9mo | Review | Advanced |
| react-skills | 0 | 5mo | No flags | Intermediate |
| web-artifacts-builder | 49 | 3mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
ui-ux-expert-skill
fercracix33
Technical workflow for implementing accessible React user interfaces with shadcn/ui, Tailwind CSS, and TanStack Query. Includes 6-phase process with mandatory Style Guide compliance, Context7 best practices consultation, Chrome DevTools validation, and WCAG 2.1 AA accessibility standards. Use after Test Agent, Implementer, and Supabase agents complete their work.
react-skills
alexander-kastil
Build clean, accessible React components with TypeScript and Fluent UI. Use when creating new React components, converting designs to code, building reusable UI patterns, optimizing component performance, implementing accessibility guidelines, or structuring React projects. Supports component scaffo
web-artifacts-builder
anthropics
Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.
frontend-ui-dark-ts
microsoft
Build dark-themed React applications using Tailwind CSS with custom theming, glassmorphism effects, and Framer Motion animations. Use when creating dashboards, admin panels, or data-rich interfaces with a refined dark aesthetic.
designer-skills
llama-farm
Designer subsystem patterns for LlamaFarm. Covers React 18, TanStack Query, TailwindCSS, and Radix UI.
react-admin-panel
Survikrowa
React admin panel using Vite, TanStack Router, TanStack Query, and Tailwind CSS. Use this skill when working with the web admin interface in apps/web, creating admin features, forms, or data tables.