Feature Components¶
Last Updated: 2025-01-22
Feature components are application-specific components that compose UI primitives to create reusable business features.
Overview¶
Feature components:
- Combine UI components
- Implement business logic
- Handle user interactions
- Integrate with Server Actions
- Provide reusable patterns
Component Patterns¶
Server Component (Default)¶
// components/property-list.tsx
import { PropertyCard } from '@/components/property-card'
import type { PropertyListItem } from '@/lib/types'
interface PropertyListProps {
properties: PropertyListItem[]
}
export function PropertyList({ properties }: PropertyListProps) {
if (properties.length === 0) {
return <div>No properties found</div>
}
return (
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{properties.map((property) => (
<PropertyCard key={property.id} property={property} />
))}
</div>
)
}
Client Component¶
// components/search-input.tsx
'use client'
import { useState } from 'react'
import { Input } from '@/components/ui/input'
import { useDebouncedCallback } from 'use-debounce'
interface SearchInputProps {
onSearch: (query: string) => void
debounce?: number
}
export function SearchInput({ onSearch, debounce = 300 }: SearchInputProps) {
const [query, setQuery] = useState('')
const debouncedSearch = useDebouncedCallback(
(value: string) => {
onSearch(value)
},
debounce
)
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
const value = e.target.value
setQuery(value)
debouncedSearch(value)
}
return (
<Input
type="search"
placeholder="Search properties..."
value={query}
onChange={handleChange}
/>
)
}
Composition¶
// components/dashboard-header.tsx
import { SearchInput } from '@/components/search-input'
import { UserNav } from '@/components/user-nav'
interface DashboardHeaderProps {
user: {
name: string
email: string
}
onSearch: (query: string) => void
}
export function DashboardHeader({ user, onSearch }: DashboardHeaderProps) {
return (
<header className="flex items-center justify-between border-b px-6 py-4">
<div className="flex-1">
<SearchInput onSearch={onSearch} />
</div>
<UserNav user={user} />
</header>
)
}
Best Practices¶
- Keep components focused and single-purpose
- Use TypeScript for props
- Extract reusable logic to hooks
- Compose from UI primitives
- Add loading and error states
- Include accessibility attributes
- Test component behavior