Blog / CSS/JS

Essential CSS/JS Utilities

A complete collection of essential CSS and JavaScript utilities to accelerate your modern web development. Utility classes, JS functions, CSS reset, animations and dark mode.

Introduction

Every modern web project relies on a set of fundamental building blocks: utility CSS classes for rapid layout, reusable JavaScript functions for common logic, and solid foundations like a clean CSS reset.

In this article, we have gathered the most essential utilities that every front-end developer should have in their toolbox. Each snippet is ready to be copied and integrated into your projects.

💡
Good to know

These utilities are intentionally lightweight and dependency-free. You can use them individually or combine them in a dedicated utils.css / utils.js file.

1. CSS utility classes

Utility classes allow quickly building layouts without writing specific CSS. Here are the three most used categories.

Spacing system

A consistent spacing system is the foundation of any design system. Use custom properties to ensure visual harmony across the entire project.

spacing.css
/* Spacing system based on a 4px scale */
:root {
  --space-1: 0.25rem;  /* 4px */
  --space-2: 0.5rem;   /* 8px */
  --space-3: 1rem;     /* 16px */
  --space-4: 1.5rem;   /* 24px */
  --space-5: 2rem;     /* 32px */
  --space-6: 3rem;     /* 48px */
  --space-8: 4rem;     /* 64px */
}

/* Margin utilities */
.mt-1 { margin-top: var(--space-1); }
.mt-2 { margin-top: var(--space-2); }
.mt-3 { margin-top: var(--space-3); }
.mt-4 { margin-top: var(--space-4); }
.mb-3 { margin-bottom: var(--space-3); }
.mb-4 { margin-bottom: var(--space-4); }

/* Padding utilities */
.p-2 { padding: var(--space-2); }
.p-3 { padding: var(--space-3); }
.p-4 { padding: var(--space-4); }
.px-3 { padding-inline: var(--space-3); }
.py-3 { padding-block: var(--space-3); }

/* Gap utilities */
.gap-1 { gap: var(--space-1); }
.gap-2 { gap: var(--space-2); }
.gap-3 { gap: var(--space-3); }
.gap-4 { gap: var(--space-4); }

Flexbox utilities

These classes cover 90% of flex layout needs. Combine them to create complex layouts with just a few classes.

flex.css
/* Flexbox utilities */
.flex { display: flex; }
.inline-flex { display: inline-flex; }
.flex-col { flex-direction: column; }
.flex-wrap { flex-wrap: wrap; }
.items-center { align-items: center; }
.items-start { align-items: flex-start; }
.justify-center { justify-content: center; }
.justify-between { justify-content: space-between; }
.flex-1 { flex: 1; }
.shrink-0 { flex-shrink: 0; }

/* Shortcut for full centering */
.center {
  display: flex;
  align-items: center;
  justify-content: center;
}

Grid utilities

CSS Grid simplifies complex layouts. These utilities cover the most common grids with a responsive approach.

grid.css
/* Grid utilities */
.grid { display: grid; }
.grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
.grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
.grid-cols-4 { grid-template-columns: repeat(4, 1fr); }
.col-span-2 { grid-column: span 2; }

/* Auto-responsive grid without media queries */
.grid-auto {
  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax(280px, 1fr)
  );
  gap: var(--space-4, 1.5rem);
}
💡
Tip

The .grid-auto class with auto-fit and minmax() creates a grid that automatically adapts to the number of columns without any media query. It is one of the most powerful CSS patterns.

2. JavaScript utility functions

These JavaScript functions cover the most common needs in front-end development. They are lightweight, dependency-free and compatible with all modern browsers.

Debounce

Debounce delays the execution of a function until the user stops acting for a given delay. Ideal for search fields and window resizing.

debounce.js
function debounce(fn, delay = 300) {
  let timeout;
  return (...args) => {
    clearTimeout(timeout);
    timeout = setTimeout(() => fn(...args), delay);
  };
}

// Usage: real-time search
const searchInput = document.querySelector('#search');
searchInput.addEventListener('input', debounce((e) => {
  fetchResults(e.target.value);
}, 250));

Throttle

Throttle ensures that a function executes only once per time interval, even if called continuously. Perfect for scroll and mousemove events.

throttle.js
function throttle(fn, limit = 100) {
  let waiting = false;
  return (...args) => {
    if (!waiting) {
      fn(...args);
      waiting = true;
      setTimeout(() => waiting = false, limit);
    }
  };
}

// Usage: update on scroll
window.addEventListener('scroll', throttle(() => {
  updateScrollProgress();
}, 100));

Copy to Clipboard

An async/await function to copy text to the clipboard with clean error handling.

clipboard.js
async function copyToClipboard(text) {
  try {
    await navigator.clipboard.writeText(text);
    return true;
  } catch (err) {
    // Fallback for older browsers
    const textarea = document.createElement('textarea');
    textarea.value = text;
    textarea.style.position = 'fixed';
    textarea.style.opacity = '0';
    document.body.appendChild(textarea);
    textarea.select();
    document.execCommand('copy');
    document.body.removeChild(textarea);
    return true;
  }
}

LocalStorage helpers

A wrapper around localStorage with automatic JSON serialization and error handling.

storage.js
const storage = {
  get(key, fallback = null) {
    try {
      const item = localStorage.getItem(key);
      return item ? JSON.parse(item) : fallback;
    } catch {
      return fallback;
    }
  },

  set(key, value) {
    try {
      localStorage.setItem(key, JSON.stringify(value));
      return true;
    } catch {
      return false;
    }
  },

  remove(key) {
    localStorage.removeItem(key);
  },

  clear() {
    localStorage.clear();
  }
};

// Usage
storage.set('user', { name: 'Alice', theme: 'dark' });
const user = storage.get('user', {});
⚠️
Warning

localStorage is synchronous and limited to about 5 MB per domain. Do not use it to store large volumes of data. For larger needs, prefer IndexedDB.

3. Modern CSS Reset

A modern CSS reset is essential for ensuring consistent rendering across browsers. Here is an optimized version that fixes common issues while retaining useful default values.

reset.css
/* Box sizing global */
*, *::before, *::after {
  box-sizing: border-box;
}

/* Margin reset */
* {
  margin: 0;
}

/* Base body */
body {
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* Responsive media by default */
img, picture, video, canvas, svg {
  display: block;
  max-width: 100%;
}

/* Font inheritance for inputs */
input, button, textarea, select {
  font: inherit;
}

/* Prevent text overflow */
p, h1, h2, h3, h4, h5, h6 {
  overflow-wrap: break-word;
}

/* Root stacking context for portals */
#root, #__next {
  isolation: isolate;
}

/* Visible focus for accessibility */
:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

This reset is inspired by the work of Josh Comeau and Andy Bell. It is intentionally minimalist: it fixes problematic behaviors without removing the browser's useful styles.

📝
Note

The isolation: isolate rule on the root creates a new stacking context, which avoids z-index issues with modals and React/Vue portals.

4. Animation helpers

Subtle animations make an interface lively and pleasant. Here are reusable CSS and JavaScript helpers for the most common animations.

CSS animations: fadeIn and slideUp

animations.css
/* Keyframes reutilisables */
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

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

@keyframes scaleIn {
  from {
    opacity: 0;
    transform: scale(0.95);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

/* Animation utility classes */
.animate-fade-in {
  animation: fadeIn 0.3s ease-out;
}

.animate-slide-up {
  animation: slideUp 0.4s ease-out;
}

.animate-scale-in {
  animation: scaleIn 0.2s ease-out;
}

/* Transitions fluides */
.transition {
  transition: all 0.2s ease;
}

.transition-slow {
  transition: all 0.4s ease;
}

/* Respect user preferences */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

JavaScript Observer for scroll animations

Use the IntersectionObserver to trigger animations when elements enter the viewport.

scroll-animate.js
function animateOnScroll(selector, animClass, options = {}) {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        entry.target.classList.add(animClass);
        observer.unobserve(entry.target);
      }
    });
  }, {
    threshold: options.threshold || 0.1,
    rootMargin: options.rootMargin || '0px'
  });

  document.querySelectorAll(selector).forEach((el) => {
    observer.observe(el);
  });
}

// Usage
animateOnScroll('.card', 'animate-slide-up');

5. Dark mode toggle

Implement a clean dark mode with CSS custom properties and a JavaScript toggle. This approach respects the user's system preferences and persists the choice in localStorage.

CSS variables for both themes

theme.css
/* Theme clair (defaut) */
:root {
  --bg: #ffffff;
  --bg-card: #f8f9fa;
  --text: #1a1a2e;
  --text-muted: #6b7280;
  --border: rgba(0, 0, 0, 0.1);
  --primary: #6366f1;
  --shadow: 0 2px 8px rgba(0,0,0,0.08);
}

/* Theme sombre */
[data-theme="dark"] {
  --bg: #0a0a0f;
  --bg-card: #12121a;
  --text: #ffffff;
  --text-muted: #a1a1aa;
  --border: rgba(255, 255, 255, 0.08);
  --primary: #818cf8;
  --shadow: 0 2px 8px rgba(0,0,0,0.3);
}

/* Smooth transition between themes */
body {
  background: var(--bg);
  color: var(--text);
  transition: background 0.3s ease, color 0.3s ease;
}

JavaScript toggle

theme-toggle.js
class ThemeToggle {
  constructor() {
    this.theme = this.getStoredTheme() || this.getSystemTheme();
    this.apply();
  }

  getSystemTheme() {
    return window.matchMedia('(prefers-color-scheme: dark)')
      .matches ? 'dark' : 'light';
  }

  getStoredTheme() {
    return localStorage.getItem('theme');
  }

  apply() {
    document.documentElement.setAttribute('data-theme', this.theme);
  }

  toggle() {
    this.theme = this.theme === 'dark' ? 'light' : 'dark';
    localStorage.setItem('theme', this.theme);
    this.apply();
  }
}

// Initialisation
const themeToggle = new ThemeToggle();

// Bind to button
document.querySelector('#theme-btn')
  .addEventListener('click', () => themeToggle.toggle());
💡
Avoiding the theme flash

Place the theme detection script in the <head> (before the page renders) to avoid the default theme "flash" on load. A simple document.documentElement.setAttribute('data-theme', localStorage.getItem('theme') || 'light') is enough.

Best practices

Before integrating these utilities into your projects, here are some essential recommendations to get the most out of them.

Organization

  • Separate your files: keep CSS utilities in a dedicated file (utils.css) and JS functions in a module (utils.js)
  • Document your classes: add comments describing each group of utilities to make it easier for the team to get started
  • Prefix if needed: if working with an existing framework, prefix your classes (e.g. .u-flex) to avoid conflicts

Performance

  • Load only what you use: only copy the utilities you need into your project
  • Prefer CSS transitions over JavaScript animations when possible, they are more performant as they are GPU-managed
  • Use will-change sparingly: this property reserves GPU resources, only apply it to elements that are truly animated

Maintainability

  • Stay consistent: choose a naming convention (BEM, utility, functional) and stick to it throughout the project
  • Test across all browsers: check compatibility, especially for CSS custom properties and the Clipboard API
  • Version your utilities: treat them as an internal dependency with a changelog to track changes

Conclusion

These utilities form a solid foundation for any modern web project. By integrating them into your workflow, you will save considerable time on repetitive tasks and ensure consistency across your codebase.

The key is to start small: choose the utilities that meet your immediate needs, then enrich your collection over time. With time, you will build a personalized toolbox perfectly adapted to your way of working.

🎨
Go further

Find CSS effects and components ready to use in our effects library, with one-click copyable code.