Introduction to UI Components
UI components are the building blocks of modern interfaces. Well-designed components not only make your application look professional but also significantly improve user experience by providing consistent, intuitive interactions. This guide explores key UI components and best practices for designing them.
Button Design
Buttons are perhaps the most fundamental interactive element in any interface.
Button Hierarchy
Establish a clear button hierarchy:
- Primary buttons: Most important actions (e.g., Submit, Purchase)
- Secondary buttons: Alternative options (e.g., Save for later, Cancel)
- Tertiary buttons: Less common actions (e.g., View details)
// Example of button component with different variants
function Button({ variant = 'primary', children, ...props }) {
const styles = {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
tertiary: 'bg-transparent text-blue-600 hover:underline',
}
return (
<button className={`rounded px-4 py-2 font-medium ${styles[variant]}`} {...props}>
{children}
</button>
)
}
Button States
Design for all interactive states:
- Default: The normal appearance
- Hover: When the cursor is over the button
- Focus: When the button is focused via keyboard
- Active/Pressed: When the button is being clicked
- Disabled: When the button is not interactive
Best Practices
- Use descriptive action verbs on buttons (e.g., "Create Account" instead of "Submit")
- Maintain adequate spacing between multiple buttons
- Ensure sufficient contrast for accessibility
- Keep button sizes large enough for touch interfaces
- Use icons to reinforce button actions when appropriate
Form Design
Forms are often the most critical interaction point for users.
Input Fields
Design clear, user-friendly input fields:
function TextField({ label, error, ...props }) {
return (
<div className="mb-4">
<label className="mb-2 block font-medium text-gray-700">{label}</label>
<input
className={`w-full rounded border px-3 py-2 focus:ring-2 focus:outline-none ${error ? 'border-red-500 focus:ring-red-200' : 'border-gray-300 focus:ring-blue-200'}`}
{...props}
/>
{error && <p className="mt-1 text-sm text-red-500">{error}</p>}
</div>
)
}
Form Layout
Organize form elements effectively:
- Group related fields together
- Use single-column layouts when possible
- Align labels and inputs consistently
- Show inline validation to provide immediate feedback
- Use progressive disclosure for complex forms
Error Handling
Design helpful error messages:
- Place error messages close to the problematic field
- Use color, icons, and text to communicate errors
- Write specific, actionable error messages
- Provide guidance on how to fix the error
Navigation Components
Navigation is crucial for helping users find their way around your application.
Navigation Bars
Design clear, consistent navigation:
function Navbar() {
return (
<nav className="bg-white shadow-sm">
<div className="mx-auto max-w-6xl px-4">
<div className="flex h-16 justify-between">
<div className="flex items-center">
<a href="/" className="text-xl font-bold text-gray-800">
Logo
</a>
<div className="hidden md:ml-6 md:flex md:space-x-4">
<a href="/features" className="px-3 py-2 text-gray-700 hover:text-gray-900">
Features
</a>
<a href="/pricing" className="px-3 py-2 text-gray-700 hover:text-gray-900">
Pricing
</a>
<a href="/about" className="px-3 py-2 text-gray-700 hover:text-gray-900">
About
</a>
</div>
</div>
<div className="flex items-center">
<button className="rounded bg-blue-600 px-4 py-2 text-white">Sign Up</button>
</div>
</div>
</div>
</nav>
)
}
Breadcrumbs
Help users understand their location within the application:
function Breadcrumbs({ items }) {
return (
<nav aria-label="Breadcrumb">
<ol className="flex space-x-2 text-sm">
{items.map((item, index) => (
<li key={index} className="flex items-center">
{index > 0 && <span className="mx-2 text-gray-400">/</span>}
{index === items.length - 1 ? (
<span className="text-gray-600">{item.label}</span>
) : (
<a href={item.href} className="text-blue-600 hover:underline">
{item.label}
</a>
)}
</li>
))}
</ol>
</nav>
)
}
Card Components
Cards are versatile containers that group related content.
Card Design Principles
- Maintain consistent padding and spacing
- Use subtle shadows to create depth
- Keep card content focused on a single topic
- Provide clear interaction affordances for clickable cards
function Card({ title, description, image, actionLabel, onClick }) {
return (
<div className="overflow-hidden rounded-lg bg-white shadow-md">
{image && <img src={image} alt={title} className="h-48 w-full object-cover" />}
<div className="p-5">
<h3 className="mb-2 text-xl font-semibold">{title}</h3>
<p className="mb-4 text-gray-600">{description}</p>
{actionLabel && (
<button onClick={onClick} className="font-medium text-blue-600 hover:underline">
{actionLabel}
</button>
)}
</div>
</div>
)
}
Modal and Dialog Components
Modals focus user attention on a specific task.
Modal Design Best Practices
- Include a clear title that describes the modal's purpose
- Provide an obvious way to close the modal (e.g., X button, Cancel button)
- Maintain focus within the modal for keyboard users
- Consider the modal size relative to the screen size
function Modal({ isOpen, onClose, title, children }) {
if (!isOpen) return null
return (
<div className="bg-opacity-50 fixed inset-0 flex items-center justify-center bg-black p-4">
<div
className="max-h-[90vh] w-full max-w-md overflow-auto rounded-lg bg-white shadow-xl"
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
>
<div className="flex items-center justify-between border-b p-4">
<h2 id="modal-title" className="text-xl font-semibold">
{title}
</h2>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-600"
aria-label="Close"
>
✕
</button>
</div>
<div className="p-4">{children}</div>
</div>
</div>
)
}
Accessibility Considerations
Ensure your UI components are accessible to all users:
- Use semantic HTML elements
- Ensure keyboard navigability
- Provide adequate color contrast
- Include appropriate ARIA attributes
- Test with screen readers
// Example of an accessible dropdown menu
function Dropdown({ label, items }) {
const [isOpen, setIsOpen] = useState(false)
return (
<div className="relative">
<button
onClick={() => setIsOpen(!isOpen)}
aria-haspopup="true"
aria-expanded={isOpen}
className="rounded border px-4 py-2"
>
{label}
</button>
{isOpen && (
<ul role="menu" className="absolute mt-1 w-full rounded border bg-white shadow-lg">
{items.map((item, index) => (
<li key={index} role="menuitem">
<a href={item.href} className="block px-4 py-2 hover:bg-gray-100">
{item.label}
</a>
</li>
))}
</ul>
)}
</div>
)
}
Designing for Design Systems
For larger applications, consider a component-based design system:
- Create a visual language with consistent patterns
- Document component usage and variations
- Establish naming conventions
- Set up a component library that teams can easily reference
- Use tools like Storybook to showcase and test components
Conclusion
Well-designed UI components create a cohesive, intuitive user experience. By following these best practices, you can create interfaces that are not only visually appealing but also functional and accessible.
Remember that the best UI components are those that users barely notice—they should feel natural and help users accomplish their goals efficiently. Continually test your components with real users and iterate based on feedback.