10 CSS Components Every Web Developer Needs — With Complete Code Examples

Walk through any modern website and you'll find the same UI elements appearing over and over: a styled button, a content card, a top navigation bar, an alert message, a modal dialog. These aren't accidents — they're the fundamental building blocks of web interfaces. This guide covers the 10 most essential CSS components for web development, explains why each one matters, shows complete code in both plain CSS and Tailwind, and links to free copy-paste examples for every variant you'll need.

10

core CSS components that appear in almost every web project

401+

free variations available at UnblockDevs CSS Components

2

formats for every component: Tailwind CSS and plain CSS

<1 min

to find, preview, and copy any component — no account needed

1

Buttons — The Most Fundamental CSS Component

Every web page has at least one button. Buttons trigger the most important user actions: submitting a form, starting a checkout, confirming a deletion, opening a modal. Despite their apparent simplicity, a well-designed button system handles a surprising number of states: default, hover, focus (keyboard navigation), active (being clicked), disabled, and loading.

The most common mistake with CSS buttons is styling only the default state and ignoring the rest. A button that looks fine normally but has no visible focus ring fails accessibility tests and frustrates keyboard users.

cssComplete CSS button — all states handled
/* The base button — reset browser defaults, establish shared styles */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.625rem 1.25rem;
  border-radius: 0.5rem;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1;
  border: 1px solid transparent;
  cursor: pointer;
  transition: all 0.15s ease;
  text-decoration: none;  /* if used as <a> */
  user-select: none;
}

/* Primary variant */
.btn-primary {
  background: #2563eb;
  color: #fff;
  border-color: #2563eb;
}
.btn-primary:hover        { background: #1d4ed8; border-color: #1d4ed8; }
.btn-primary:focus-visible {
  outline: 2px solid #2563eb;
  outline-offset: 2px;   /* visible ring for keyboard navigation */
}
.btn-primary:active       { transform: scale(0.97); }
.btn-primary:disabled     { opacity: 0.55; cursor: not-allowed; pointer-events: none; }

/* Ghost variant */
.btn-ghost {
  background: transparent;
  color: #3f3f46;
  border-color: #d4d4d8;
}
.btn-ghost:hover         { background: #f4f4f5; }
.btn-ghost:focus-visible { outline: 2px solid #94a3b8; outline-offset: 2px; }

/* Danger variant */
.btn-danger {
  background: #dc2626;
  color: #fff;
  border-color: #dc2626;
}
.btn-danger:hover { background: #b91c1c; }

Loading State Best Practice

For async actions (form submit, API call), replace the button text with a spinner and setdisabled to prevent double-submits. Use CSS animate-spin (Tailwind) or a @keyframes rotation on the spinner SVG — never a JavaScript setInterval.
2

Cards — The Universal Content Container

Cards group related information into a visually distinct, scannable unit. They're used for products, articles, user profiles, pricing tiers, statistics, features — anything that benefits from visual separation. The key properties that make a card feel polished are a subtle border, a light background, rounded corners, and a soft shadow.

cssCard component with hover elevation effect
/* Base card */
.card {
  background: #fff;
  border: 1px solid #e4e4e7;     /* zinc-200 */
  border-radius: 0.75rem;         /* 12px */
  padding: 1.25rem;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.07);
  transition: box-shadow 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}

/* Hover state — "lift" effect */
.card:hover {
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
  border-color: #d4d4d8;          /* slightly darker border on hover */
  transform: translateY(-2px);
}

/* Card sub-elements */
.card-image {
  width: 100%;
  border-radius: 0.5rem;
  object-fit: cover;
  margin-bottom: 1rem;
}
.card-category {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #2563eb;
  margin-bottom: 0.5rem;
}
.card-title {
  font-size: 0.9375rem;
  font-weight: 700;
  color: #18181b;
  line-height: 1.3;
}
.card-body {
  font-size: 0.8125rem;
  color: #71717a;
  line-height: 1.65;
  margin-top: 0.375rem;
}
.card-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid #f4f4f5;
}
3

Navigation Bar — First Component Built, Most Visible

The navbar is usually the first component on the page and the one users interact with most. A good navbar is sticky (scrolls with the page), clearly marks the current page, is accessible to keyboard users, and collapses gracefully on mobile.

cssSticky navbar with active state and mobile-ready structure
/* Sticky header that stays at the top while scrolling */
.navbar {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 1.5rem;
  height: 64px;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(8px);    /* frosted glass effect */
  border-bottom: 1px solid #e4e4e7;
}

.navbar-logo {
  font-weight: 800;
  font-size: 1.0625rem;
  color: #18181b;
  text-decoration: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.navbar-links {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

.navbar-link {
  font-size: 0.875rem;
  font-weight: 500;
  color: #52525b;
  text-decoration: none;
  transition: color 0.15s;
}
.navbar-link:hover { color: #18181b; }

/* Active page — shows which page you're on */
.navbar-link.is-active {
  color: #2563eb;
  font-weight: 600;
}

/* Hide links on mobile, show hamburger */
@media (max-width: 767px) {
  .navbar-links { display: none; }
  .navbar-hamburger { display: flex; }
}
4

Modal / Dialog — For Confirmations and Focused Tasks

Modals interrupt the user's flow to demand attention: "Are you sure you want to delete this?" or "Enter your payment details." They should be used sparingly — only when the task genuinely needs a focused, interrupting UI. For non-critical information, use a tooltip or inline message instead.

Quick fact

Accessible modals need focus trapping (Tab key stays inside the modal), close-on-Escape behavior, a backdrop that closes the modal on click, and role="dialog" with aria-modal="true"for screen readers.

cssModal backdrop and panel with accessible attributes
/* Backdrop — full screen overlay */
.modal-backdrop {
  position: fixed;
  inset: 0;                       /* top:0, right:0, bottom:0, left:0 */
  z-index: 50;
  background: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(2px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;

  /* Animation — fade in from invisible */
  animation: fadeIn 0.15s ease;
}

/* Panel — the white box */
.modal-panel {
  position: relative;
  background: #fff;
  border-radius: 1rem;
  padding: 1.5rem;
  width: 100%;
  max-width: 448px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2);

  /* Slide up animation */
  animation: slideUp 0.2s ease;
}

.modal-title {
  font-size: 1rem;
  font-weight: 700;
  color: #18181b;
}
.modal-body {
  font-size: 0.875rem;
  color: #52525b;
  margin-top: 0.5rem;
  line-height: 1.6;
}
.modal-actions {
  display: flex;
  gap: 0.75rem;
  justify-content: flex-end;
  margin-top: 1.5rem;
}

@keyframes fadeIn  { from { opacity: 0 } to { opacity: 1 } }
@keyframes slideUp { from { transform: translateY(12px); opacity: 0 } to { transform: translateY(0); opacity: 1 } }
5

Forms & Inputs — Where Users Give You Data

Form components are the most difficult to style consistently because each browser has its own default appearance for form elements. The approach that works best across browsers: use CSSappearance: none to strip browser defaults, then apply your own styles from scratch.

cssCross-browser consistent form input styles
/* Text input — reset and re-style */
.form-input {
  display: block;
  width: 100%;
  padding: 0.625rem 1rem;
  font-size: 0.875rem;
  color: #18181b;
  background: #fff;
  border: 1px solid #d4d4d8;
  border-radius: 0.5rem;
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
  appearance: none;             /* remove browser-native styling */
  -webkit-appearance: none;
}
.form-input::placeholder { color: #a1a1aa; }
.form-input:focus {
  border-color: #93c5fd;        /* blue-300 */
  box-shadow: 0 0 0 3px rgba(147, 197, 253, 0.4);  /* soft focus ring */
}
.form-input:invalid:not(:placeholder-shown) {
  border-color: #fca5a5;        /* red-300 */
  box-shadow: 0 0 0 3px rgba(252, 165, 165, 0.3);
}

/* Label */
.form-label {
  display: block;
  font-size: 0.875rem;
  font-weight: 500;
  color: #3f3f46;
  margin-bottom: 0.375rem;
}

/* Helper / error text */
.form-helper { font-size: 0.75rem; color: #71717a; margin-top: 0.375rem; }
.form-error  { font-size: 0.75rem; color: #dc2626; margin-top: 0.375rem; }

/* Toggle switch */
.toggle {
  position: relative;
  display: inline-flex;
  width: 2.5rem;
  height: 1.375rem;
}
.toggle input { opacity: 0; width: 0; height: 0; }
.toggle-track {
  position: absolute; inset: 0;
  background: #d4d4d8;
  border-radius: 9999px;
  cursor: pointer;
  transition: background 0.2s;
}
.toggle input:checked + .toggle-track { background: #2563eb; }
.toggle-thumb {
  position: absolute;
  left: 2px; top: 2px;
  width: 1rem; height: 1rem;
  background: #fff;
  border-radius: 50%;
  transition: transform 0.2s;
  box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
.toggle input:checked ~ .toggle-thumb { transform: translateX(1.125rem); }
6

Alert / Notification Components

Alerts communicate outcomes: a form submitted successfully, a payment failed, an action is irreversible. They need instant visual recognition — users shouldn't need to read the text to know if something succeeded or failed. Use color (green/red/amber/blue) combined with an icon to create immediate semantic clarity.

cssAlert component system — four semantic types
/* Base alert */
.alert {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.875rem 1rem;
  border-radius: 0.75rem;
  border-width: 1px;
  border-style: solid;
  font-size: 0.875rem;
  line-height: 1.5;
}

.alert-icon { font-size: 1rem; line-height: 1.5; flex-shrink: 0; }

.alert-title { font-weight: 600; }
.alert-message { margin-top: 0.125rem; opacity: 0.85; font-size: 0.8125rem; }

/* Success */
.alert-success {
  background: #f0fdf4;     /* green-50 */
  border-color: #bbf7d0;   /* green-200 */
  color: #14532d;          /* green-900 */
}

/* Error */
.alert-error {
  background: #fef2f2;     /* red-50 */
  border-color: #fecaca;   /* red-200 */
  color: #7f1d1d;          /* red-900 */
}

/* Warning */
.alert-warning {
  background: #fffbeb;     /* amber-50 */
  border-color: #fde68a;   /* amber-200 */
  color: #78350f;          /* amber-900 */
}

/* Info */
.alert-info {
  background: #eff6ff;     /* blue-50 */
  border-color: #bfdbfe;   /* blue-200 */
  color: #1e3a8a;          /* blue-900 */
}
7

Tables — Making Data Readable

HTML tables have a bad reputation — earned mostly by their misuse for layouts in the early 2000s. For actual tabular data, tables are the right semantic element. The challenge is styling them to be readable, striped for row distinction, and responsive on small screens.

cssStyled responsive data table
/* Table wrapper — enables horizontal scroll on mobile */
.table-wrapper {
  width: 100%;
  overflow-x: auto;
  border-radius: 0.75rem;
  border: 1px solid #e4e4e7;
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
  white-space: nowrap;          /* prevent text wrapping in cells */
}

/* Header */
.data-table thead {
  background: #f9f9f9;
  border-bottom: 1px solid #e4e4e7;
}
.data-table th {
  padding: 0.75rem 1rem;
  text-align: left;
  font-size: 0.75rem;
  font-weight: 700;
  color: #71717a;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* Rows */
.data-table tbody tr {
  border-bottom: 1px solid #f4f4f5;
  transition: background 0.1s;
}
.data-table tbody tr:hover { background: #fafafa; }
.data-table tbody tr:last-child { border-bottom: none; }

.data-table td {
  padding: 0.875rem 1rem;
  color: #3f3f46;
  vertical-align: middle;
}

/* Status badge inside table cell */
.badge-active   { color: #16a34a; background: #dcfce7; padding: 0.2rem 0.6rem; border-radius: 9999px; font-size: 0.7rem; font-weight: 700; }
.badge-inactive { color: #dc2626; background: #fee2e2; padding: 0.2rem 0.6rem; border-radius: 9999px; font-size: 0.7rem; font-weight: 700; }
.badge-pending  { color: #d97706; background: #fef3c7; padding: 0.2rem 0.6rem; border-radius: 9999px; font-size: 0.7rem; font-weight: 700; }
8

Progress Bars — Communicating Loading and Completion

Progress bars have two use cases: deterministic (showing how far along a process is — file upload, form completion, onboarding steps) and indeterminate (showing that something is happening when you don't know the duration — page loading, API call). Both need different CSS approaches.

cssDeterminate and indeterminate progress bars
/* ─── Deterministic progress bar ────────────────────────────────── */
.progress-bar {
  width: 100%;
  height: 0.5rem;
  background: #e4e4e7;          /* track color */
  border-radius: 9999px;
  overflow: hidden;
}
.progress-bar-fill {
  height: 100%;
  background: #2563eb;          /* fill color */
  border-radius: 9999px;
  transition: width 0.4s ease;  /* smooth update when % changes */
}

/* Usage: set width via inline style or a CSS custom property */
/* <div class="progress-bar-fill" style="width: 68%"></div> */


/* ─── Indeterminate (loading) bar ───────────────────────────────── */
.progress-indeterminate {
  width: 100%;
  height: 0.25rem;
  background: #dbeafe;          /* blue-100 */
  border-radius: 9999px;
  overflow: hidden;
  position: relative;
}
.progress-indeterminate::after {
  content: '';
  position: absolute;
  top: 0;
  left: -40%;
  width: 40%;
  height: 100%;
  background: #2563eb;
  border-radius: 9999px;
  animation: indeterminate 1.4s ease infinite;
}
@keyframes indeterminate {
  0%   { left: -40%; }
  60%  { left: 100%; }
  100% { left: 100%; }
}
9

Dropdown Menus — Context Actions and Navigation

Dropdown menus appear when users click a trigger (a button, a user avatar, a "More options" icon). They require careful CSS positioning: the menu must appear directly below (or beside) the trigger, stay on top of other content (z-index), and close when the user clicks outside.

cssDropdown menu — positioning and animation
/* Trigger button + dropdown wrapper */
.dropdown {
  position: relative;
  display: inline-block;
}

/* The menu panel — hidden by default */
.dropdown-menu {
  position: absolute;
  top: calc(100% + 0.5rem);    /* 8px below the trigger */
  left: 0;
  z-index: 40;
  min-width: 12rem;
  background: #fff;
  border: 1px solid #e4e4e7;
  border-radius: 0.75rem;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1), 0 1px 6px rgba(0, 0, 0, 0.06);
  padding: 0.375rem;

  /* Hidden state */
  opacity: 0;
  transform: scale(0.96) translateY(-4px);
  pointer-events: none;
  transition: opacity 0.15s, transform 0.15s;
  transform-origin: top left;
}

/* Shown state — toggled with JS by adding .is-open class */
.dropdown.is-open .dropdown-menu {
  opacity: 1;
  transform: scale(1) translateY(0);
  pointer-events: auto;
}

/* Menu items */
.dropdown-item {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  width: 100%;
  padding: 0.5rem 0.75rem;
  border-radius: 0.5rem;
  font-size: 0.8125rem;
  font-weight: 500;
  color: #3f3f46;
  text-align: left;
  background: transparent;
  border: none;
  cursor: pointer;
  transition: background 0.1s;
  text-decoration: none;
}
.dropdown-item:hover { background: #f4f4f5; }
.dropdown-item.is-danger { color: #dc2626; }
.dropdown-item.is-danger:hover { background: #fef2f2; }

.dropdown-divider {
  height: 1px;
  background: #f4f4f5;
  margin: 0.375rem 0;
}
10

Sidebar Navigation — For Dashboards and Apps

The final essential component is the app sidebar — a persistent vertical navigation panel for dashboards, admin panels, and multi-section applications. Sidebars need a clear active state, icon + label layout, section grouping with headers, and a collapsed/mobile behavior.

cssSidebar navigation — full implementation
/* Sidebar container */
.sidebar {
  width: 240px;
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: #fff;
  border-right: 1px solid #e4e4e7;
  padding: 1rem 0.75rem;
  overflow-y: auto;
  flex-shrink: 0;

  /* Hide scrollbar visually — still scrollable */
  scrollbar-width: none;
}
.sidebar::-webkit-scrollbar { display: none; }

/* Logo / header area */
.sidebar-header {
  padding: 0.5rem 0.75rem 1rem;
  border-bottom: 1px solid #f4f4f5;
  margin-bottom: 0.75rem;
}

/* Section label */
.sidebar-section-label {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #a1a1aa;
  padding: 0 0.75rem;
  margin: 1rem 0 0.375rem;
}

/* Nav item */
.sidebar-item {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  width: 100%;
  padding: 0.5rem 0.75rem;
  border-radius: 0.5rem;
  font-size: 0.8125rem;
  font-weight: 500;
  color: #52525b;
  text-decoration: none;
  background: transparent;
  border: none;
  cursor: pointer;
  transition: all 0.1s;
  text-align: left;
}
.sidebar-item:hover { background: #f4f4f5; color: #18181b; }

/* Active (current page) */
.sidebar-item.is-active {
  background: #eff6ff;           /* blue-50 */
  color: #1d4ed8;                /* blue-700 */
  font-weight: 600;
}

/* Item icon */
.sidebar-item-icon { width: 1rem; height: 1rem; flex-shrink: 0; opacity: 0.7; }
.sidebar-item.is-active .sidebar-item-icon { opacity: 1; }

/* Badge count (notification dot) */
.sidebar-item-badge {
  margin-left: auto;
  background: #e4e4e7;
  color: #3f3f46;
  font-size: 0.6875rem;
  font-weight: 700;
  padding: 0.1rem 0.4rem;
  border-radius: 9999px;
}
.sidebar-item.is-active .sidebar-item-badge {
  background: #bfdbfe;           /* blue-200 */
  color: #1d4ed8;
}

See All 10 Components in Action

Every component in this guide — plus 391 more — is available with live interactive previews at UnblockDevs CSS UI Components. Buttons, cards, navbars, modals, forms, tables, progress bars, dropdowns, sidebars, and 26 more categories. Both Tailwind and plain CSS. No signup required.

Buttons need all 5 states

Default, hover, focus, active, and disabled. Missing the focus state fails keyboard accessibility. Missing the loading state leads to double-submissions.

Cards use border + shadow + radius

The three properties that make a card feel polished: a 1px border, a soft box-shadow, and rounded corners. The hover "lift" effect (translateY + stronger shadow) adds delight.

Navbars should be sticky and frosted

Sticky positioning keeps navigation accessible while scrolling. backdrop-filter: blur() creates the frosted glass effect that modern apps use to keep the navbar visible over content.

Modals need focus trapping + Escape close

Use JavaScript to trap the Tab key inside the modal and to listen for the Escape key. Without this, keyboard users can navigate behind the modal — a critical accessibility failure.

Strip form defaults with appearance: none

Browser-native form element styles vary dramatically between Chrome, Firefox, and Safari. Use appearance: none on inputs, selects, and checkboxes to start from a clean baseline.

Progress bars must animate smoothly

Add transition: width 0.4s ease to progress fill elements. When you update the width via JS or inline style, it will animate smoothly rather than snapping to the new value.

Frequently Asked Questions