--- name: fpkit-developer description: Guide for building applications with @fpkit/acss components. This skill should be used when composing custom React components from fpkit primitives, validating CSS variable naming conventions, extending fpkit components with custom behavior, or ensuring accessibility compliance in fpkit-based applications. Use when the user needs help with component composition patterns, CSS customization, or accessibility testing. Not for developing the @fpkit/acss library itself. version: 0.1.5 --- # FPKit Developer A Claude Code skill for building applications with **@fpkit/acss** components. --- ## Purpose This skill helps developers: - **Compose custom components** from fpkit primitives - **Validate CSS variables** against fpkit conventions - **Maintain accessibility** when building with fpkit - **Follow best practices** for component composition **This skill is for:** Developers using @fpkit/acss in their applications **Not for:** Developing the @fpkit/acss library itself (use `fpkit-component-builder` for that) --- ## Workflow When a user requests a new component or feature, follow this workflow: ### Step 1: Analyze the Request Understand what the user needs: - What is the component supposed to do? - What user interactions are required? - Are there similar fpkit components? **Ask clarifying questions** if the requirements are unclear. --- ### Step 2: Check for Existing fpkit Components Review the [@fpkit/acss component catalog](https://github.com/shawn-sandy/acss/tree/main/packages/fpkit/src/components) or [Storybook](https://fpkit.netlify.app): **Available components:** - **Buttons:** Button (with `aria-disabled` pattern, focus management, performance optimized) - **Links:** Link (auto security for external links, ref forwarding, prefetch support) - **Cards:** Card, CardHeader, CardTitle, CardContent, CardFooter - **Forms:** Input, Field, FieldLabel, FieldInput - **Layout:** Header, Main, Footer, Aside, Nav - **Typography:** Heading, Text - **Dialogs:** Dialog, Modal - **Feedback:** Alert, Badge, Tag - **Data:** Table, List - **Interactive:** Details, Popover - **Icons:** Icon library **Decision tree:** ``` 1. CHECK: Does fpkit have the exact component? ✓ YES → Use it directly, customize with CSS variables (Skip to Step 6: Accessibility) ✗ NO → Continue to next check 2. CHECK: Can it be built by composing 2+ fpkit components? ✓ YES → Proceed to Step 3 (Composition) ✗ NO → Continue to next check 3. CHECK: Can an existing fpkit component be extended/wrapped? ✓ YES → Proceed to Step 4 (Extension) ✗ NO → Continue to next check 4. BUILD: Component requires custom implementation → Proceed to Step 5 (Custom Implementation) ``` --- ### Step 3: Compose from fpkit Components **Create a new component file** that imports and combines fpkit components: ```tsx // components/StatusButton.tsx import { Button, Badge } from '@fpkit/acss' export interface StatusButtonProps extends React.ComponentProps { status: 'active' | 'inactive' | 'pending' } export const StatusButton = ({ status, children, ...props }: StatusButtonProps) => { return ( ) } ``` **Guidelines:** - Import fpkit components using named imports - Extend fpkit component prop types with TypeScript - Spread `...props` to preserve all fpkit functionality - Keep composition simple (≤ 3 levels deep) **Reference:** See `references/composition.md` for patterns and examples --- ### Step 4: Extend fpkit Components **Wrap an fpkit component** to add custom behavior: ```tsx // components/LoadingButton.tsx import { Button, type ButtonProps } from '@fpkit/acss' import { useState } from 'react' export interface LoadingButtonProps extends ButtonProps { loading?: boolean onClickAsync?: (e: React.MouseEvent) => Promise } export const LoadingButton = ({ loading, onClickAsync, children, ...props }: LoadingButtonProps) => { const [isLoading, setIsLoading] = useState(loading) const handleClick = async (e: React.MouseEvent) => { if (onClickAsync) { setIsLoading(true) try { await onClickAsync(e) } finally { setIsLoading(false) } } } return ( ) } ``` **Guidelines:** - **Extend fpkit prop types** (don't replace them) - **Preserve all fpkit functionality** (aria-disabled, focus management, etc.) - **Add custom logic** around fpkit components - **Maintain accessibility** - fpkit Button automatically handles: - `aria-disabled` pattern for better keyboard accessibility - Focus management (stays in tab order when disabled) - Event prevention when disabled - Automatic className merging for `.is-disabled` styling --- ### Step 5: Custom Implementation If the component is truly custom and can't use fpkit: 1. **Follow fpkit patterns:** - Use semantic HTML - Add proper ARIA attributes - Support keyboard navigation - Use rem units (not px) - Define CSS variables for theming 2. **Create styles (if needed):** ```scss // components/CustomComponent.scss .custom-component { padding: var(--custom-padding, 1rem); border-radius: var(--custom-radius, 0.375rem); background: var(--custom-bg, white); // Use rem units only! margin-bottom: 1rem; // NOT 16px gap: 0.5rem; // NOT 8px } ``` 3. **Validate CSS variables** (for custom styles): ```bash python scripts/validate_css_vars.py components/ ``` **Reference:** See `references/css-variables.md` for naming conventions --- ### Step 6: Ensure Accessibility **Check accessibility compliance:** - [ ] Uses semantic HTML (` ) } ``` **Key patterns demonstrated:** - Import fpkit components with named imports - Extend fpkit prop types with TypeScript - Spread `...props` to preserve fpkit functionality - Simple composition (2 components combined) --- ### More Complex Examples For production-ready implementations with state management, validation, and advanced patterns: - **IconButton** (Container + Content Pattern) See `references/composition.md` → Pattern 1: Container Component with Content Demonstrates: Icon positioning, flexible layout, semantic structure - **ConfirmButton** (Stateful Wrapper Pattern) See `references/composition.md` → Pattern 4: Enhanced Wrapper with State Demonstrates: Dialog integration, async actions, confirmation flows - **LoadingButton** (Async State Management) See SKILL.md → Step 4: Extend fpkit Components (lines 117-156) Demonstrates: Loading states, async handlers, disabled state management - **TagInput** (Compound Composition Pattern) See `references/composition.md` → Pattern 5: Compound Components Demonstrates: Multi-component orchestration, keyboard events, array state --- ## Best Practices ### ✅ Do - **Compose from fpkit** - Start with fpkit components to inherit built-in accessibility - **Extend prop types** - Use TypeScript to extend fpkit types (preserves type safety) - **Preserve accessibility** - fpkit uses `aria-disabled` for better keyboard accessibility - **Use `onClick` for events** - Captures keyboard, mouse, touch, and assistive tech - **Use CSS variables** - Customize with variables, not hardcoded styles - **Validate CSS** - Run validation script on custom styles - **Document compositions** - Document fpkit components used in JSDoc - **Test integration** - Test how composed components work together - **Add tooltips to disabled buttons** - fpkit's `aria-disabled` pattern allows this! ### ❌ Don't - **Don't duplicate fpkit** - If it exists in fpkit, use it - **Don't break accessibility** - Maintain ARIA and keyboard navigation - **Don't use `onPointerDown` alone** - It doesn't fire for keyboard users - **Don't override `disabled` handling** - Trust fpkit's `aria-disabled` pattern - **Don't use px units** - Always use rem - **Don't over-compose** - Keep composition depth ≤ 3 levels - **Don't nest interactive elements** - No `