From react
Create well-structured, reusable React components with TypeScript. Use when building new UI components, following React best practices, or scaffolding component files with tests.
How this skill is triggered — by the user, by Claude, or both
Slash command
/react:create-componentopusThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
This command helps you create well-structured, reusable React components for Tevm-based applications, with proper TypeScript typing and integration with Ethereum functionality.
This command helps you create well-structured, reusable React components for Tevm-based applications, with proper TypeScript typing and integration with Ethereum functionality.
What this command does NOT do:
When to REJECT:
ultrathink: you'd perform the following steps
Output Format:
[✅/❌] Command: create-component $ARGUMENTS
## Summary
- Component created: [name]
- Files generated: [count]
- TypeScript types: [defined]
- Tests: [created]
## Actions Taken
1. Created component file at [path]
2. Generated test file at [path]
3. Created index.ts for re-exports
4. [Created CSS module] (if needed)
## Next Steps
1. Review component implementation
2. Run tests to verify functionality
3. Import component in your application
claude < .claude/create-component
When you run this command, I will:
Before running this command, it helps to prepare:
I'll help you create a React component that follows best practices by:
React components in Tevm applications typically follow this structure:
components/
└── ComponentName/
├── ComponentName.tsx # Main component implementation
├── ComponentName.test.tsx # Component tests
├── ComponentName.module.css # Styling (if needed)
└── index.ts # Re-export for cleaner imports
Here's a template for a typical component:
// ComponentName.tsx
import { useState, useEffect } from 'react'
import type { FC } from 'react'
import { useMemoryClient } from 'tevm/memory-client'
import styles from './ComponentName.module.css'
/**
* Props for the ComponentName component
*/
export interface ComponentNameProps {
/** Description of prop1 */
prop1: string
/** Description of prop2, which is optional */
prop2?: number
/** Callback function */
onChange?: (value: string) => void
}
/**
* ComponentName - Brief description of what this component does
*
* Detailed description of the component's purpose, usage context,
* and any important behaviors or limitations.
*
* @example
* ```tsx
* <ComponentName
* prop1="example"
* prop2={42}
* onChange={(value) => console.log(value)}
* />
* ```
*/
export const ComponentName: FC<ComponentNameProps> = ({
prop1,
prop2 = 0, // Default value for optional prop
onChange,
}) => {
const [state, setState] = useState('')
const client = useMemoryClient()
useEffect(() => {
// Example effect to interact with Tevm
const fetchData = async () => {
try {
// Example contract interaction
const result = await client.getBalance({
address: prop1,
})
setState(result.toString())
onChange?.(result.toString())
} catch (error) {
console.error('Error in ComponentName:', (error as Error).message)
}
}
fetchData()
}, [prop1, client, onChange])
return (
<div className={styles.container}>
<h2>{prop1}</h2>
{prop2 > 0 && <p>Value: {prop2}</p>}
<p>Balance: {state}</p>
</div>
)
}
// ComponentName.test.tsx
import { render, screen, waitFor } from '@testing-library/react'
import { ComponentName } from './ComponentName'
import { MemoryClientProvider, createMemoryClient } from 'tevm/memory-client'
// Mock the Tevm client
jest.mock('tevm/memory-client', () => {
const actual = jest.requireActual('tevm/memory-client')
return {
...actual,
useMemoryClient: () => ({
getBalance: jest.fn().mockResolvedValue(BigInt(1000000000000000000))
})
}
})
describe('ComponentName', () => {
const client = createMemoryClient()
it('renders with required props', async () => {
render(
<MemoryClientProvider client={client}>
<ComponentName prop1="0x123..." />
</MemoryClientProvider>
)
expect(screen.getByText('0x123...')).toBeInTheDocument()
await waitFor(() => {
expect(screen.getByText('Balance: 1000000000000000000')).toBeInTheDocument()
})
})
it('calls onChange when data is loaded', async () => {
const onChange = jest.fn()
render(
<MemoryClientProvider client={client}>
<ComponentName
prop1="0x123..."
onChange={onChange}
/>
</MemoryClientProvider>
)
await waitFor(() => {
expect(onChange).toHaveBeenCalledWith('1000000000000000000')
})
})
})
// index.ts
export * from './ComponentName'
/* ComponentName.module.css */
.container {
padding: 1rem;
border: 1px solid #eaeaea;
border-radius: 0.5rem;
margin-bottom: 1rem;
}
For components that interact with specific contracts:
import { useContract } from '../hooks/useContract'
import { MyContractAbi } from '../contracts/MyContract'
export const ContractComponent: FC<{ address: string }> = ({ address }) => {
const contract = useContract({
address,
abi: MyContractAbi,
})
const [data, setData] = useState(null)
useEffect(() => {
const fetchData = async () => {
const result = await contract.read.myMethod()
setData(result)
}
fetchData()
}, [contract])
const handleAction = async () => {
await contract.write.performAction()
}
return (
<div>
<p>Data: {data?.toString()}</p>
<button onClick={handleAction}>Perform Action</button>
</div>
)
}
For components that display block or transaction data:
import { useBlock } from '../hooks/useBlock'
export const BlockInfo: FC<{ blockNumber?: bigint }> = ({ blockNumber }) => {
const { data, loading, error } = useBlock({ blockNumber })
if (loading) return <p>Loading...</p>
if (error) return <p>Error: {error.message}</p>
return (
<div>
<h3>Block {data.number.toString()}</h3>
<p>Timestamp: {new Date(Number(data.timestamp) * 1000).toLocaleString()}</p>
<p>Gas Used: {data.gasUsed.toString()}</p>
</div>
)
}
For your component, I'll provide:
A simple component that displays an account's balance:
export const BalanceDisplay: FC<{ address: string }> = ({ address }) => {
const client = useMemoryClient()
const [balance, setBalance] = useState<bigint>(BigInt(0))
useEffect(() => {
const getBalance = async () => {
const result = await client.getBalance({ address })
setBalance(result)
}
getBalance()
}, [address, client])
return (
<div>
<p>Address: {address}</p>
<p>Balance: {formatEther(balance)} ETH</p>
</div>
)
}
A form component for submitting transactions:
export const TransactionForm: FC<{ onSubmit?: (txHash: string) => void }> = ({ onSubmit }) => {
const client = useMemoryClient()
const [to, setTo] = useState('')
const [value, setValue] = useState('')
const [sending, setSending] = useState(false)
const handleSubmit = async (e: FormEvent) => {
e.preventDefault()
if (!to) return
try {
setSending(true)
const txHash = await client.sendTransaction({
to,
value: parseEther(value || '0'),
})
onSubmit?.(txHash)
} catch (error) {
console.error('Transaction error:', (error as Error).message)
} finally {
setSending(false)
}
}
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="to">To Address:</label>
<input
id="to"
value={to}
onChange={(e) => setTo(e.target.value)}
placeholder="0x..."
required
/>
</div>
<div>
<label htmlFor="value">Amount (ETH):</label>
<input
id="value"
type="number"
step="0.001"
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder="0.0"
/>
</div>
<button type="submit" disabled={sending}>
{sending ? 'Sending...' : 'Send Transaction'}
</button>
</form>
)
}
A successful component should:
What type of component would you like to create today?
npx claudepluginhub alvis/.claude --plugin reactGenerates React/Vue components with TypeScript, tests, CSS modules, barrel exports, and project-pattern validation. Detects Next.js App Router and adjusts output accordingly.
Writes modern React components using TypeScript, hooks, Tailwind CSS, and best practices. Generates functional components, custom hooks, and composition patterns for performant UIs.
Guides writing and modifying React components with modern patterns, TypeScript, hooks for state and effects, component composition, and pitfalls to avoid. Triggers on .jsx/.tsx files or React planning.