ACTIVATE when creating or refactoring React components, splitting large components, extracting hooks, or deciding Container vs Presentation. ACTIVATE for 'component split', 'Container/Presentation', 'extract hook', 'god component', 'prop drilling'. Covers: Container vs Presentation criteria, when to extract custom hooks (3+ related states), when to split markup (150+ lines), when to move logic to domain service, form section props convention, spotlight/opacity pattern. DO NOT use for: projects not using Container/Presentation (ask first), general React hooks API.
From frontendnpx claudepluginhub fabiensalles/claude-marketplace --plugin frontendThis skill uses the workspace's default tool permissions.
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Migrates code, prompts, and API calls from Claude Sonnet 4.0/4.5 or Opus 4.1 to Opus 4.5, updating model strings on Anthropic, AWS, GCP, Azure platforms.
Configures Istio traffic management with VirtualServices, DestinationRules for routing, canary/blue-green deployments, circuit breakers, load balancing, and fault injection in service meshes.
Apply only on projects that already follow Container/Presentation patterns. If the project does not use these patterns, ask the user before refactoring.
Container components:
ReceiptFormIsland — uses useReceiptForm(), renders DocumentAsForm or success screenPresentation components:
onChange, onSubmit, onFieldFocus)BailleurSection — receives landlordName, errors, emits onChangeExtract when 3 or more related state variables are managed together:
useState + useState + useState for related concerns → useFeatureName()Do NOT extract a hook for:
useStateSplit a component when:
Each extracted section should be 30-60 lines of JSX.
Move to domain/<concern>.service.ts when:
parseFloat(), arithmetic, or formatting appears inline in JSXinterface SectionProps {
// Section-specific data
fieldName: string;
// ...
// Error display
errors: Partial<Record<string, string>>;
// Spotlight/focus system
isActive: boolean;
// Event callbacks
onChange: (field: string, value: string | boolean) => void;
onFieldFocus: (field: string) => void;
onFieldBlur: (field: string) => void;
}
Use a declarative mapping (in domain service) instead of inline prefix matching:
// Domain service — pure mapping
const SECTION_FIELDS: Record<SectionKey, string[]> = {
bailleur: ['landlordName', 'landlordEmail'],
// ...
};
function isSectionActive(currentField: string, section: SectionKey): boolean {
if (!currentField) return true;
return SECTION_FIELDS[section].includes(currentField);
}
{(parseFloat(a) + parseFloat(b)).toFixed(2)} → extract to domain service