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 or Storybook:
Available components:
- •Buttons: Button (with
aria-disabledpattern, 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:
// components/StatusButton.tsx
import { Button, Badge } from '@fpkit/acss'
export interface StatusButtonProps extends React.ComponentProps<typeof Button> {
status: 'active' | 'inactive' | 'pending'
}
export const StatusButton = ({ status, children, ...props }: StatusButtonProps) => {
return (
<Button {...props}>
{children}
<Badge variant={status}>{status}</Badge>
</Button>
)
}
Guidelines:
- •Import fpkit components using named imports
- •Extend fpkit component prop types with TypeScript
- •Spread
...propsto 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:
// 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<void>
}
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 (
<Button
{...props}
disabled={isLoading || props.disabled}
onClick={handleClick}
>
{isLoading ? 'Loading...' : children}
</Button>
)
}
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-disabledpattern for better keyboard accessibility - •Focus management (stays in tab order when disabled)
- •Event prevention when disabled
- •Automatic className merging for
.is-disabledstyling
- •
Step 5: Custom Implementation
If the component is truly custom and can't use fpkit:
- •
Follow fpkit patterns:
- •Use semantic HTML
- •Add proper ARIA attributes
- •Support keyboard navigation
- •Use rem units (not px)
- •Define CSS variables for theming
- •
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 } - •
Validate CSS variables (for custom styles):
bashpython 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 (
<button>,<nav>, etc.) - • All interactive elements are keyboard accessible
- • Proper ARIA attributes (
aria-label,aria-describedby, etc.) - • Visible focus indicators
- • Color contrast meets WCAG AA (4.5:1 for normal text)
- • Screen reader friendly (meaningful labels)
Test:
- •Navigate with keyboard only (Tab, Enter, Escape)
- •Use automated testing (jest-axe)
- •Check Storybook a11y addon (if documenting in Storybook)
Reference: See references/accessibility.md for patterns
Step 7: Document the Component (Optional)
When creating a reusable component for a team:
Create a Storybook story:
// components/StatusButton.stories.tsx
import type { Meta, StoryObj } from '@storybook/react'
import { StatusButton } from './StatusButton'
const meta = {
title: 'Components/StatusButton',
component: StatusButton,
tags: ['autodocs'],
} satisfies Meta<typeof StatusButton>
export default meta
type Story = StoryObj<typeof meta>
export const Active: Story = {
args: {
status: 'active',
children: 'Server Status',
},
}
export const Inactive: Story = {
args: {
status: 'inactive',
children: 'Server Status',
},
}
Reference Documentation
Quick Reference Search
When searching reference files for specific patterns, use these grep commands:
# Find composition patterns by type grep -i "pattern.*:" references/composition.md # Find specific composition examples grep -i "iconbutton\|confirmbutton\|taginput" references/composition.md # Find CSS variables by component grep -i "\-\-btn\|--alert\|--card" references/css-variables.md # Find CSS variable naming rules grep -i "naming\|convention\|pattern" references/css-variables.md # Find ARIA patterns and attributes grep -i "aria-\|role=" references/accessibility.md # Find WCAG requirements grep -i "wcag\|contrast\|level aa" references/accessibility.md # Find testing patterns grep -i "describe\|test\|expect\|render" references/testing.md # Find Storybook configuration grep -i "meta\|story\|args" references/storybook.md # Find architecture patterns grep -i "polymorphic\|as prop\|compound" references/architecture.md
Composition Patterns
Read references/composition.md when composing components. Covers:
- •Decision tree (compose vs extend vs create)
- •5 common composition patterns with code examples
- •Real-world examples (IconButton, ConfirmButton, TagInput)
- •Anti-patterns to avoid (nesting depth, polymorphism misuse)
- •TypeScript prop type patterns
Common questions → Reference sections:
- •"How do I combine multiple fpkit components?" → Patterns 1-3
- •"Should I compose or extend?" → Decision Tree
- •"How deep can I nest components?" → Anti-Patterns (≤3 levels)
- •"How do I type extended props?" → TypeScript Support
CSS Variables
Read references/css-variables.md for customization guidance. Covers:
- •Naming convention (
--component-property) - •Discovery techniques (DevTools inspection, IDE autocomplete)
- •Customization strategies (global theme, scoped overrides)
- •Complete variable reference for Button, Alert, Card, and other components
- •Framework integration patterns (React inline styles, CSS Modules, styled-components)
Common questions → Reference sections:
- •"What CSS variables does Button support?" → Component Reference: Button
- •"How do I customize globally vs per-component?" → Customization Strategies
- •"How do I find available variables?" → Discovery Techniques
- •"Can I use variables with styled-components?" → Framework Integration
Accessibility
Read references/accessibility.md for WCAG compliance guidance. Covers:
- •WCAG 2.1 Level AA compliance requirements
- •ARIA patterns and attributes for interactive components
- •Keyboard navigation requirements (Tab, Enter, Escape, Arrow keys)
- •Form accessibility (labels, error messages, validation)
- •Color contrast requirements (4.5:1 normal text, 3:1 large text)
- •Testing approaches (manual keyboard testing + automated jest-axe)
Common questions → Reference sections:
- •"What ARIA attributes do I need?" → ARIA Patterns
- •"How do I make keyboard navigation work?" → Keyboard Navigation
- •"What's the minimum color contrast?" → Color Contrast (4.5:1)
- •"How do I test accessibility?" → Testing with jest-axe
Architecture
Read references/architecture.md to understand fpkit design patterns. Covers:
- •Polymorphic UI component foundation (render as different elements)
- •Understanding the
asprop for semantic flexibility - •Simple vs compound component patterns (when to use each)
- •TypeScript support and prop type inference
- •Styling architecture (data attributes for variants, CSS variables for theming)
- •Props patterns and conventions (spreading, forwarding refs)
Common questions → Reference sections:
- •"What is the
asprop?" → Polymorphic Components - •"When should I use compound components?" → Component Patterns
- •"How does prop spreading work?" → Props Patterns
- •"How are variants implemented?" → Styling Architecture
Testing
Read references/testing.md for component testing strategies. Covers:
- •Vitest and React Testing Library setup and configuration
- •Testing composed components (integration vs unit tests)
- •Query best practices (prefer getByRole, getByLabelText over getByTestId)
- •Event testing patterns (user clicks, keyboard interactions, form submissions)
- •Accessibility testing with jest-axe (automated a11y checks)
- •Async testing and loading states (waitFor, findBy queries)
Common questions → Reference sections:
- •"How do I test composed components?" → Testing Composed Components
- •"What query should I use?" → Query Best Practices (prefer getByRole)
- •"How do I test keyboard events?" → Event Testing
- •"How do I test accessibility?" → jest-axe Integration
Storybook
Read references/storybook.md for documentation strategies. Covers:
- •Storybook setup and configuration (addons, plugins)
- •Story structure and patterns (CSF 3.0 format)
- •Documenting composed components (props tables, descriptions)
- •CSS variable customization stories (controls, args)
- •Interactive testing with play functions (user-event)
- •Accessibility testing in Storybook (a11y addon)
Common questions → Reference sections:
- •"How do I document a composed component?" → Documenting Composed Components
- •"How do I show CSS variable options?" → CSS Variable Customization
- •"How do I add interactive tests?" → Play Functions
- •"How do I test accessibility in Storybook?" → A11y Addon
Tools
CSS Variable Validation
Validate custom CSS variables against fpkit conventions:
# Validate a file python scripts/validate_css_vars.py components/Button.scss # Validate a directory python scripts/validate_css_vars.py styles/ # Validate current directory python scripts/validate_css_vars.py
What it checks:
- •✅ Naming pattern:
--{component}-{property} - •✅ rem units (not px)
- •✅ Approved abbreviations: bg, fs, fw, radius, gap
- •✅ Full words for: padding, margin, color, border, display, width, height
Examples
Quick reference examples demonstrating key patterns. For detailed implementations and advanced patterns, see references/composition.md.
Example: Simple Composition (StatusButton)
Combining Button + Badge to show status:
import { Button, Badge } from '@fpkit/acss'
export interface StatusButtonProps extends React.ComponentProps<typeof Button> {
status: 'active' | 'inactive' | 'pending'
}
export const StatusButton = ({ status, children, ...props }: StatusButtonProps) => {
return (
<Button {...props}>
{children}
<Badge variant={status}>{status}</Badge>
</Button>
)
}
Key patterns demonstrated:
- •Import fpkit components with named imports
- •Extend fpkit prop types with TypeScript
- •Spread
...propsto 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-disabledfor better keyboard accessibility - •Use
onClickfor 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-disabledpattern 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
onPointerDownalone - It doesn't fire for keyboard users - •Don't override
disabledhandling - Trust fpkit'saria-disabledpattern - •Don't use px units - Always use rem
- •Don't over-compose - Keep composition depth ≤ 3 levels
- •Don't nest interactive elements - No
<button>inside<a> - •Don't ignore polymorphism - Use
asprop instead of wrapping - •Don't manually add
rel="noopener"to external links - fpkit Link does this automatically
Troubleshooting
CSS Variables Not Applying
- •Check specificity - ensure the selector has equal or higher specificity
- •Check cascade order - import fpkit CSS before custom overrides
- •Check typos - variable names are case-sensitive
Component Not Keyboard Accessible
- •Ensure using semantic HTML (
<button>, not<div>) - •Add
role,tabIndex, and keyboard handlers if needed - •Check focus indicators are visible
- •Test with Tab, Enter, Space, Escape keys
TypeScript Errors
- •Extend fpkit prop types:
interface MyProps extends ButtonProps - •Import types:
import { Button, type ButtonProps } from '@fpkit/acss' - •Spread props correctly:
<Button {...props}>
Resources
- •fpkit Documentation - Complete guides
- •Storybook - Component examples
- •npm Package - Installation and API
- •GitHub - Source code and issues
Compatible with @fpkit/acss v0.1.x
This skill is designed for applications using @fpkit/acss version 1.x. For version-specific documentation, check the npm package documentation in node_modules/@fpkit/acss/docs/.