component-patterns
React component patterns with Ark UI, forwardRef, and TypeScript for the design system
Installation
Suivez les instructions du dépôt pour votre agent. Consultez les fichiers et dépendances avant l’installation.
Voir la source ↗GuidesInstructions
Component Patterns
When to Use This Skill
- Creating a new component
- Wrapping Ark UI primitives
- Setting up TypeScript types for variants
- Understanding the component → recipe relationship
Standard Component Structure
src/components/Button/
├── Button.tsx # Component implementation
├── Button.stories.tsx # Storybook stories
└── index.ts # Barrel export
Component Template
// src/components/Button/Button.tsx
import { forwardRef } from 'react';
import { Button as ArkButton } from '@ark-ui/react';
import { button, type ButtonVariantProps } from 'styled-system/recipes';
import { cx } from 'styled-system/css';
export interface ButtonProps
extends React.ComponentPropsWithoutRef<typeof ArkButton>,
ButtonVariantProps {
/** Optional left icon */
leftIcon?: React.ReactNode;
/** Optional right icon */
rightIcon?: React.ReactNode;
}
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
(
{
variant,
size,
leftIcon,
rightIcon,
className,
children,
...props
},
ref
) => {
return (
<ArkButton
ref={ref}
className={cx(button({ variant, size }), className)}
{...props}
>
{leftIcon}
{children}
{rightIcon}
</ArkButton>
);
}
);
Button.displayName = 'Button';
Barrel Export Pattern
// src/components/Button/index.ts
export { Button } from './Button';
export type { ButtonProps } from './Button';
// src/components/index.ts
export * from './Button';
export * from './Card';
export * from './Dialog';
Ark UI Component Patterns
Simple Components (Button, Card)
import { Button as ArkButton } from '@ark-ui/react';
// Ark Button is a simple primitive, just wrap and style
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
(props, ref) => (
<ArkButton ref={ref} className={button(props)} {...props} />
)
);
Compound Components (Dialog, Menu)
import { Dialog as ArkDialog } from '@ark-ui/react';
// Ark Dialog is compound - has Trigger, Content, etc.
export const Dialog = {
Root: ArkDialog.Root,
Trigger: forwardRef<HTMLButtonElement, DialogTriggerProps>(
({ className, ...props }, ref) => (
<ArkDialog.Trigger
ref={ref}
className={cx(dialogTrigger(), className)}
{...props}
/>
)
),
Content: forwardRef<HTMLDivElement, DialogContentProps>(
({ className, ...props }, ref) => (
<ArkDialog.Positioner>
<ArkDialog.Content
ref={ref}
className={cx(dialogContent(), className)}
{...props}
/>
</ArkDialog.Positioner>
)
),
// ... other parts
};
TypeScript Patterns
Variant Props from Recipe
import type { ButtonVariantProps } from 'styled-system/recipes';
// ButtonVariantProps is auto-generated by Panda CSS
// It includes: { variant?: 'filled' | 'outlined' | ... ; size?: 'sm' | 'md' | 'lg' }
Polymorphic Components (as prop)
// For components that can render as different elements
type AsProps<T extends React.ElementType> = {
as?: T;
};
type PolymorphicProps<T extends React.ElementType, Props = {}> =
Props & AsProps<T> & Omit<React.ComponentPropsWithoutRef<T>, keyof Props | 'as'>;
Ref Forwarding with generics
// When the element type can change
const Card = forwardRef(
<T extends React.ElementType = 'div'>(
{ as, ...props }: CardProps<T>,
ref: React.ForwardedRef<Element>
) => {
const Component = as || 'div';
return <Component ref={ref} {...props} />;
}
) as <T extends React.ElementType = 'div'>(
props: CardProps<T> & { ref?: React.ForwardedRef<Element> }
) => React.ReactElement;
Storybook Stories Pattern
// src/components/Button/Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
title: 'Components/Button',
component: Button,
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['filled', 'outlined', 'text', 'elevated', 'tonal'],
},
size: {
control: 'select',
options: ['sm', 'md', 'lg'],
},
},
};
export default meta;
type Story = StoryObj<typeof Button>;
export const Filled: Story = {
args: {
children: 'Button',
variant: 'filled',
},
};
export const Outlined: Story = {
args: {
children: 'Button',
variant: 'outlined',
},
};
// Story for all variants
export const AllVariants: Story = {
render: () => (
<div style={{ display: 'flex', gap: '1rem', flexWrap: 'wrap' }}>
<Button variant="filled">Filled</Button>
<Button variant="outlined">Outlined</Button>
<Button variant="text">Text</Button>
<Button variant="elevated">Elevated</Button>
<Button variant="tonal">Tonal</Button>
</div>
),
};
Files to Reference
-
src/components/Button/Button.tsx- Existing implementation (for reference) - Ark UI docs: https://ark-ui.com/react/docs/overview/introduction
Exemples
Consultez les exemples du dépôt source.
Voir la source ↗Historique source
- Date d’indexation
- 2026-01-20
- Mise à jour de l’index
- 2026-01-26
- Branch
- main
Les dates concernent ce répertoire. Consultez le dépôt pour l’historique du code.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!