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):
// 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):
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 (
<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/.
Scan to join WeChat group