← Back to Learning Path JavaScript • Level 2 • Lesson 6 of 9
Level 2 progress 0% complete

Lesson 6: Common JS Grid Patterns

Real-world layouts you will use in production apps.

Card Grid Pattern

The most common pattern, a responsive card grid:

function createCardGrid(items) {
  const container = document.getElementById('cards');
  
  container.style.display = 'grid';
  container.style.gridTemplateColumns = 'repeat(auto-fit, minmax(280px, 1fr))';
  container.style.gap = '1.5rem';
  
  items.forEach(item => {
    const card = document.createElement('div');
    card.className = 'card';
    card.innerHTML = `
      <img src="${item.image}" alt="${item.title}">
      <h3>${item.title}</h3>
      <p>${item.description}</p>
    `;
    container.appendChild(card);
  });
}

This automatically adapts, as many columns as fit, minimum 280px each.

Dashboard Layout

Classic dashboard with header, sidebar, main, and footer:

function setupDashboard() {
  const container = document.getElementById('dashboard');
  
  container.style.display = 'grid';
  container.style.gridTemplateColumns = '250px 1fr';
  container.style.gridTemplateRows = '60px 1fr 40px';
  container.style.height = '100vh';
  container.style.gap = '0';
  
  // Header spans both columns
  const header = document.getElementById('header');
  header.style.gridColumn = '1 / -1';
  
  // Footer spans both columns
  const footer = document.getElementById('footer');
  footer.style.gridColumn = '1 / -1';
}
Grid Template Shorthand gridColumn = '1 / -1' means "from line 1 to the last line". It spans all columns.

Masonry-Style Grid

Pinterest-style layout with varying heights:

function createMasonry(items) {
  const container = document.getElementById('masonry');
  
  container.style.display = 'grid';
  container.style.gridTemplateColumns = 'repeat(auto-fill, minmax(250px, 1fr))';
  container.style.gridAutoRows = '10px'; // Small row height
  container.style.gap = '1rem';
  
  items.forEach((item, index) => {
    const card = document.createElement('div');
    
    // Calculate row span based on content height
    const span = Math.ceil(item.height / 10);
    card.style.gridRowEnd = `span ${span}`;
    
    card.innerHTML = `<img src="${item.image}">`;
    container.appendChild(card);
  });
}

Image Gallery with Lightbox

Grid gallery that opens clicked images:

function createGallery(images) {
  const container = document.getElementById('gallery');
  
  container.style.display = 'grid';
  container.style.gridTemplateColumns = 'repeat(auto-fit, minmax(200px, 1fr))';
  container.style.gap = '0.5rem';
  
  images.forEach((img, index) => {
    const item = document.createElement('div');
    item.innerHTML = `<img src="${img.thumb}" alt="${img.alt}">`;
    item.style.cursor = 'pointer';
    
    item.onclick = () => {
      openLightbox(img.full, index);
    };
    
    container.appendChild(item);
  });
}

function openLightbox(imageSrc, index) {
  // Your lightbox logic here
  console.log('Opening image:', imageSrc);
}

React Product Grid

E-commerce product grid with filtering:

function ProductGrid({ products, filter }) {
  const [columns, setColumns] = useState(4);
  
  const filtered = products.filter(p => 
    filter === 'all' || p.category === filter
  );
  
  return (
    <>
      <div className="controls">
        <button onClick={() => setColumns(2)}>2 Columns</button>
        <button onClick={() => setColumns(3)}>3 Columns</button>
        <button onClick={() => setColumns(4)}>4 Columns</button>
      </div>
      
      <div style={{
        display: 'grid',
        gridTemplateColumns: `repeat(${columns}, 1fr)`,
        gap: '2rem',
        padding: '2rem'
      }}>
        {filtered.map(product => (
          <ProductCard key={product.id} product={product} />
        ))}
      </div>
    </>
  );
}
React Tip In React, style objects use camelCase properties. Double curly braces: outer for JSX, inner for the object literal.

Form Grid Layout

Smart form layout with varying input widths:

function setupFormGrid() {
  const form = document.getElementById('form');
  
  form.style.display = 'grid';
  form.style.gridTemplateColumns = 'repeat(12, 1fr)';
  form.style.gap = '1rem';
  
  // Full width inputs
  document.getElementById('email').style.gridColumn = 'span 12';
  document.getElementById('address').style.gridColumn = 'span 12';
  
  // Half width inputs
  document.getElementById('firstName').style.gridColumn = 'span 6';
  document.getElementById('lastName').style.gridColumn = 'span 6';
  
  // One-third width inputs
  document.getElementById('city').style.gridColumn = 'span 4';
  document.getElementById('state').style.gridColumn = 'span 4';
  document.getElementById('zip').style.gridColumn = 'span 4';
}

Kanban Board

Project management board with columns:

function createKanban(columns) {
  const board = document.getElementById('kanban');
  
  board.style.display = 'grid';
  board.style.gridTemplateColumns = `repeat(${columns.length}, 300px)`;
  board.style.gap = '1rem';
  board.style.overflowX = 'auto';
  board.style.padding = '1rem';
  
  columns.forEach(column => {
    const col = document.createElement('div');
    col.className = 'kanban-column';
    col.innerHTML = `
      <h3>${column.title}</h3>
      <div class="tasks">
        ${column.tasks.map(task => `
          <div class="task">${task.name}</div>
        `).join('')}
      </div>
    `;
    board.appendChild(col);
  });
}

Calendar Grid

Month view calendar:

function createCalendar(month, year) {
  const cal = document.getElementById('calendar');
  
  cal.style.display = 'grid';
  cal.style.gridTemplateColumns = 'repeat(7, 1fr)';
  cal.style.gap = '1px';
  cal.style.backgroundColor = '#e5e7eb'; // Gap color
  
  // Add day headers
  const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
  days.forEach(day => {
    const header = document.createElement('div');
    header.textContent = day;
    header.className = 'cal-header';
    cal.appendChild(header);
  });
  
  // Add date cells (simplified)
  for (let i = 1; i <= 35; i++) {
    const cell = document.createElement('div');
    cell.className = 'cal-cell';
    cell.textContent = i <= 31 ? i : '';
    cal.appendChild(cell);
  }
}
Pro Pattern Set the grid container's backgroundColor to create "borders" between cells. Much simpler than styling each cell.

Blog Layout

Featured post plus regular posts:

function createBlog(posts) {
  const blog = document.getElementById('blog');
  
  blog.style.display = 'grid';
  blog.style.gridTemplateColumns = 'repeat(auto-fit, minmax(300px, 1fr))';
  blog.style.gap = '2rem';
  
  posts.forEach((post, index) => {
    const article = document.createElement('article');
    
    // First post spans 2 columns if possible
    if (index === 0) {
      article.style.gridColumn = 'span 2';
      article.className = 'featured';
    }
    
    article.innerHTML = `
      <img src="${post.image}">
      <h2>${post.title}</h2>
      <p>${post.excerpt}</p>
    `;
    
    blog.appendChild(article);
  });
}

Level 2 Complete

Excellent work. You now know:

In Level 3, you will learn advanced techniques: grid areas with gridTemplateAreas, animations, and CSS-in-JS libraries.

Practice Challenge

Build a responsive card grid that shows 1 column on mobile, 2 on tablet, and 4 on desktop. Add click handlers to each card.

Quick Check

Test your knowledge before completing Level 2. All 3 questions must be correct to continue.

1. What does gridColumn = '1 / -1' mean?

2. What is the advantage of repeat(auto-fit, minmax(250px, 1fr))?

3. How do you create "borders" between grid cells efficiently?

← Previous Lesson