Modern apps are built on reusable UI components. Whether you’re working in React, Angular, Vue, or plain HTML/CSS/JS, the core idea stays the same:
✅ Build small, accessible, reusable components
✅ Make them consistent (styles + behavior)
✅ Support validation, errors, and states
✅ Keep them composable (work well together)
In this blog, we’ll cover how to create custom UI components like:
- popover
- button
- radio-button, checkbox
- text-input, date-input
- dropdown, dropdown-option
- label, error, note
- link, message
- checkbox-group
- accordion
- toggle, toggle-group
- tabs, tab, tab-panel
This guide focuses on:
🎯 structure + behavior + accessibility + styling patterns
(You can implement these in any framework easily.)
1) UI Component Design Rules (Before Writing Code)
✅ 1.1 Component API (Props / Inputs)
Every component should support:
idnamevaluedisabledrequiredreadonly-
aria-*support className / customClassonChange / onClick / onBlur
✅ 1.2 Component States
Make sure every component supports:
- Default
- Hover
- Focus (keyboard focus visible)
- Active/Pressed
- Disabled
- Error
- Loading (if applicable)
✅ 1.3 Accessibility (Non-Negotiable)
Follow these rules:
- Use correct semantic tags (
button,input,label) - Always connect label with input using
forandid - Use
aria-invalidandaria-describedbyfor errors - Keyboard navigation must work
- Focus outline must be visible
2) Button Component
What it does
A button triggers actions like submit, open modal, save form, etc.
Key Features
✅ Variants (primary/secondary/ghost)
✅ Sizes (sm/md/lg)
✅ Loading state
✅ Disabled state
✅ Accessible click handling
Example Structure
<button class="btn btn-primary" type="button">
Save
</button>
Best Practices
- Use
<button>not<div> - Always specify
type="button"unless it’s a form submit button - Support
disabled
3) Text Input Component
What it does
Captures user text: name, email, password, etc.
Structure
<label for="email">Email</label>
<input id="email" type="text" placeholder="Enter email" />
<p class="note">We’ll never share your email.</p>
<p class="error">Email is required.</p>
Validation Support
Use:
aria-invalid="true"-
aria-describedby="email-error"
<input id="email" aria-invalid="true" aria-describedby="email-error" />
<p id="email-error" class="error">Invalid email</p>
4) Date Input Component
What it does
Captures a date value (DOB, booking date, etc.)
Option 1: Native Date Input
<label for="dob">Date of Birth</label>
<input id="dob" type="date" />
Pros:
✅ simple
✅ mobile-friendly
Cons:
❌ inconsistent UI across browsers
Option 2: Custom Date Picker
For consistent UI, build a popover-based calendar (covered in Popover section).
5) Label Component
Labels improve accessibility and usability.
Rules
- Always clickable
- Always linked to input using
for
<label for="username" class="label">Username</label>
6) Error Component
Errors should be:
- visible
- readable
- accessible
<p class="error" role="alert">Password must be 8 characters</p>
Accessibility Tip
Use role="alert" so screen readers announce it immediately.
7) Note Component
Notes are helpful messages below inputs.
<p class="note">Password must contain a number and symbol.</p>
8) Link Component
A link navigates somewhere.
Use correct semantic tag
<a href="/privacy" class="link">Privacy Policy</a>
For button-like links
If it performs an action, use <button> instead.
9) Message Component (Info / Success / Warning / Error)
Use message banners for system feedback.
<div class="message message-success" role="status">
Profile updated successfully!
</div>
Types:
infosuccesswarningerror
10) Checkbox Component
Structure
<label class="checkbox">
<input type="checkbox" />
Accept terms
</label>
Custom Checkbox Styling Pattern
Hide native checkbox visually but keep accessible.
.checkbox input {
position: absolute;
opacity: 0;
}
Then render a custom box.
11) Checkbox Group Component
Checkbox group allows selecting multiple options.
<fieldset>
<legend>Select skills</legend>
<label><input type="checkbox" /> Angular</label>
<label><input type="checkbox" /> React</label>
<label><input type="checkbox" /> Terraform</label>
</fieldset>
Accessibility
Use <fieldset> + <legend> for grouped controls.
12) Radio Button Component
Radio buttons allow selecting one option from many.
<fieldset>
<legend>Choose a plan</legend>
<label><input type="radio" name="plan" value="basic" /> Basic</label>
<label><input type="radio" name="plan" value="pro" /> Pro</label>
</fieldset>
Rules:
- Same
name= same group - Only one can be selected
13) Toggle Component
Toggle is a switch-like checkbox.
Structure
<label class="toggle">
<input type="checkbox" />
<span class="toggle-ui"></span>
Dark mode
</label>
Behavior
- ON/OFF state
- keyboard accessible
- works like checkbox underneath
14) Toggle Group Component
Toggle group works like:
- segmented control
- multiple toggles in a row
Single selection (like radio)
Example: “Day / Week / Month”
<div class="toggle-group" role="radiogroup">
<button role="radio" aria-checked="true">Day</button>
<button role="radio" aria-checked="false">Week</button>
<button role="radio" aria-checked="false">Month</button>
</div>
15) Accordion Component
Accordion expands/collapses content.
Structure
<div class="accordion">
<button class="accordion-trigger" aria-expanded="false">
What is Terraform?
</button>
<div class="accordion-panel" hidden>
Terraform is Infrastructure as Code...
</div>
</div>
Behavior Rules
- clicking trigger toggles panel
- use
aria-expanded - panel uses
hiddenattribute
16) Tabs Component (tabs, tab, tab-panel)
Tabs allow switching between sections.
Structure
<div class="tabs">
<div role="tablist" aria-label="Settings Tabs">
<button role="tab" aria-selected="true" aria-controls="tab-panel-1" id="tab-1">
Profile
</button>
<button role="tab" aria-selected="false" aria-controls="tab-panel-2" id="tab-2">
Security
</button>
</div>
<div role="tabpanel" id="tab-panel-1" aria-labelledby="tab-1">
Profile content here...
</div>
<div role="tabpanel" id="tab-panel-2" aria-labelledby="tab-2" hidden>
Security content here...
</div>
</div>
Keyboard Support (Important)
Tabs should support:
- Left/Right arrows to move focus
- Enter/Space to activate
- Home/End keys to jump
17) Dropdown Component (dropdown + dropdown-option)
Dropdown is one of the trickiest components.
Option A: Native Select (Recommended)
<label for="country">Country</label>
<select id="country">
<option>India</option>
<option>USA</option>
<option>Canada</option>
</select>
Pros:
✅ fully accessible
✅ mobile friendly
Cons:
❌ limited styling
Option B: Custom Dropdown (Advanced)
Custom dropdown requires:
- button trigger
- popover listbox
- keyboard navigation
- active option highlight
Basic structure:
<div class="dropdown">
<button aria-haspopup="listbox" aria-expanded="false">
Select Country
</button>
<ul role="listbox" hidden>
<li role="option">India</li>
<li role="option">USA</li>
<li role="option">Canada</li>
</ul>
</div>
Keyboard support:
- Arrow Up/Down to navigate
- Enter to select
- Escape to close
18) Popover Component (Most Useful Component)
Popover is a floating panel used for:
- dropdown menu
- date picker
- tooltip-like content
- action menu
Structure
<div class="popover">
<button aria-expanded="false">Open</button>
<div class="popover-content" hidden>
Popover content here...
</div>
</div>
Behavior Rules
✅ Open on click
✅ Close on outside click
✅ Close on Escape
✅ Trap focus if it behaves like a dialog
19) Styling Strategy (Reusable CSS System)
A clean CSS structure:
- base styles
- variants
- utilities
Example class naming:
-
.btn,.btn-primary,.btn-outline -
.input,.input-error -
.message-success,.message-error
Example CSS Skeleton
.btn {
padding: 10px 14px;
border-radius: 10px;
cursor: pointer;
border: 1px solid transparent;
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.input {
padding: 10px;
border-radius: 10px;
border: 1px solid #ccc;
}
.input:focus {
outline: 2px solid #000;
}
20) Recommended Component Build Order
If you're building a design system, follow this order:
- Button
- Text Input
- Label + Error + Note
- Checkbox + Radio
- Toggle
- Message
- Popover
- Dropdown
- Accordion
- Tabs
- Date Picker
Final Thoughts
Building custom UI components is one of the best ways to level up as a frontend engineer.
Once you master these building blocks, you can create:
✅ consistent UI libraries
✅ reusable design systems
✅ scalable enterprise apps
And your app will look and behave professionally across screens and devices.
Top comments (0)