Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/diegoromemora27-creator/HTMLCSSEXPLAIN/llms.txt

Use this file to discover all available pages before exploring further.

This reference provides common code patterns used throughout the ML Store project, organized by category.

State Management Patterns

Centralized State Object

interface AppState {
  status: LoadingState;
  products: Product[];
  error: string | null;
}

let appState: AppState = {
  status: LoadingState.Idle,
  products: [],
  error: null
};
Benefits:
  • Single source of truth
  • Easy to debug (check one object)
  • Simple to save/restore (localStorage)
  • Predictable state changes
Usage:
// Update state
appState.status = LoadingState.Loading;
appState.products = data;

// Check state
if (appState.status === LoadingState.Success) {
  renderProducts();
}

Enum for Status

enum LoadingState {
  Idle = "IDLE",
  Loading = "LOADING",
  Success = "SUCCESS",
  Error = "ERROR"
}

// Use in switch statement
switch (appState.status) {
  case LoadingState.Loading:
    showSpinner();
    break;
  case LoadingState.Success:
    renderProducts();
    break;
  case LoadingState.Error:
    showError();
    break;
}
Using enums prevents typos and provides autocomplete. Better than magic strings!

DOM Manipulation Patterns

Generic Element Selector

function getElement<T extends HTMLElement>(selector: string): T {
  const element = document.querySelector<T>(selector);
  if (!element) {
    throw new Error(`Element not found: ${selector}`);
  }
  return element;
}

// Usage with type safety
const button = getElement<HTMLButtonElement>("#load-btn");
const input = getElement<HTMLInputElement>("#search");
const grid = getElement<HTMLDivElement>("#products-grid");
Without generics:
const button = document.querySelector("#load-btn");
button.disabled = true;  // ✗ Error: Property 'disabled' may not exist
With generics:
const button = getElement<HTMLButtonElement>("#load-btn");
button.disabled = true;  // ✓ TypeScript knows it's a button

Event Delegation

function setupAddToCartButtons(): void {
  const grid = getElement<HTMLDivElement>("#products-grid");
  
  grid.addEventListener("click", (event: MouseEvent) => {
    const target = event.target as HTMLElement;
    const button = target.closest("[data-action='add-to-cart']");
    
    if (button) {
      const card = button.closest("[data-product-id]");
      if (card) {
        const productId = parseInt(card.getAttribute("data-product-id")!);
        addToCart(productId);
      }
    }
  });
}
One listener for all buttons - works with dynamically added elements
Uses closest() to find parent elements
Reads data from data-* attributes

API Integration Patterns

Fetch with Error Handling

async function fetchProducts(limit: number = 20): Promise<Product[]> {
  const url = `${API_URL}?limit=${limit}`;
  console.log(`Fetching: ${url}`);
  
  const response = await fetch(url);
  
  if (!response.ok) {
    throw new Error(`HTTP error: ${response.status}`);
  }
  
  const data = await response.json() as Product[];
  console.log(`Products received: ${data.length}`);
  
  return data;
}

Loading Pattern with Try/Catch

async function loadProducts(): Promise<void> {
  try {
    // Set loading state
    appState.status = LoadingState.Loading;
    appState.error = null;
    updateUI();
    
    // Fetch data
    const data = await fetchProducts(20);
    
    // Success
    appState.status = LoadingState.Success;
    appState.products = data;
    updateUI();
    
  } catch (error) {
    // Error handling
    appState.status = LoadingState.Error;
    appState.error = error instanceof Error 
      ? error.message 
      : "Unknown error";
    updateUI();
    
    console.error("Error loading products:", error);
  }
}
Flow:
  1. Set loading state → Show spinner
  2. Fetch data (await)
  3. Success → Update state with data
  4. Error → Catch and set error state
  5. Always call updateUI() to reflect changes
Benefits:
  • User sees loading feedback
  • Errors are handled gracefully
  • UI always reflects current state

Data Structure Patterns

Map for Key-Value Storage

const cart: Map<number, number> = new Map();
// Map<productId, quantity>

function addToCart(productId: number): void {
  const currentQty = cart.get(productId) || 0;
  cart.set(productId, currentQty + 1);
  updateCartBadge();
}

function removeFromCart(productId: number): void {
  cart.delete(productId);
  updateCartBadge();
}

function getCartTotal(): number {
  let total = 0;
  for (const qty of cart.values()) {
    total += qty;
  }
  return total;
}
Use Map instead of objects when:
  • Keys are numbers or need to be non-strings
  • You need .size, .has(), .delete() methods
  • You frequently add/remove entries

Array Transformation with Map/Join

function renderProducts(): void {
  const grid = getElement<HTMLDivElement>("#products-grid");
  
  grid.innerHTML = appState.products
    .map(product => createProductCardHTML(product))
    .join('');
  
  setupAddToCartButtons();
}
Pattern: Array → map to HTML strings → join → set innerHTML

Template Patterns

Template Literals for HTML

function createProductCardHTML(product: Product): string {
  const formattedPrice = product.price.toLocaleString('es-MX', {
    style: 'currency',
    currency: 'MXN'
  });
  
  const imageUrl = product.images[0] || 'https://placehold.co/400x300';
  const cleanImageUrl = imageUrl.replace(/["\[\]]/g, '');
  
  return `
    <article class="product-card" data-product-id="${product.id}">
      <figure class="product-card__figure">
        <img 
          src="${cleanImageUrl}" 
          alt="${product.title}"
          class="product-card__image"
          loading="lazy"
          onerror="this.src='https://placehold.co/400x300?text=Error'"
        />
      </figure>
      <div class="product-card__content">
        <span class="product-card__category">${product.category.name}</span>
        <h3 class="product-card__title">${product.title}</h3>
        <p class="product-card__price">
          ${formattedPrice}
          <span class="product-card__shipping">Envío gratis</span>
        </p>
        <button type="button" class="product-card__btn" data-action="add-to-cart">
          Agregar al carrito
        </button>
      </div>
    </article>
  `;
}
Be careful with XSS when using template literals with user data. Always escape or sanitize if needed.

BEM Naming Pattern

Block Element Modifier Structure

<!-- Block -->
<header class="header">
  
  <!-- Element -->
  <div class="header__container">
    
    <!-- Element -->
    <div class="header__logo">
      <a href="/" class="header__logo-link">
        
        <!-- Element -->
        <span class="header__logo-text">ML</span>
        <span class="header__logo-subtitle">Store</span>
      </a>
    </div>
    
    <!-- Element with Modifier -->
    <a href="#" class="header__nav-link header__nav-link--cart">
      Carrito
    </a>
    
  </div>
</header>
Naming Rules:
  • Block: .block
  • Element: .block__element
  • Modifier: .block__element--modifier

Block

Independent component.header, .product-card, .footer

Element

Part of block (__).header__logo, .product-card__image

Modifier

Variation (—).button--primary, .card--featured

Combined

Base + modifierclass="button button--large"

CSS Patterns

Custom Properties (Variables)

:root {
  /* Colors */
  --color-primary: #FFE600;
  --color-secondary: #3483FA;
  
  /* Spacing */
  --spacing-sm: 0.5rem;
  --spacing-md: 1rem;
  --spacing-lg: 1.5rem;
  
  /* Transitions */
  --transition-fast: 150ms ease;
}

/* Usage */
.button {
  background-color: var(--color-primary);
  padding: var(--spacing-md);
  transition: all var(--transition-fast);
}

Flexbox Centering

/* Horizontal and vertical centering */
.container {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Horizontal spacing */
.nav {
  display: flex;
  gap: var(--spacing-md);
}

/* Flex item that grows */
.search {
  flex: 1;
  min-width: 0;
}

Responsive Grid

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: var(--spacing-lg);
}
Automatically responsive without media queries!

Smooth Transitions

.card {
  transition: transform var(--transition-base),
              box-shadow var(--transition-base);
}

.card:hover {
  transform: translateY(-8px);
  box-shadow: var(--shadow-lg);
}

Error Handling Patterns

Graceful Degradation

function showNotification(message: string, type: 'success' | 'error'): void {
  const notification = document.createElement('div');
  notification.className = `notification notification--${type}`;
  notification.textContent = message;
  
  document.body.appendChild(notification);
  
  setTimeout(() => {
    notification.remove();
  }, 3000);
}

// Usage
try {
  await loadProducts();
  showNotification('Products loaded!', 'success');
} catch (error) {
  showNotification('Failed to load products', 'error');
}

Fallback Values

// Image fallback
const imageUrl = product.images[0] || 'https://placehold.co/400x300';

// Default parameter
function fetchProducts(limit: number = 20): Promise<Product[]> {
  // ...
}

// Nullish coalescing
const quantity = cart.get(productId) || 0;

// Optional chaining
const categoryName = product?.category?.name ?? 'Unknown';

Performance Patterns

Lazy Loading Images

<img 
  src="product.jpg"
  alt="Product"
  loading="lazy"
/>

Debouncing (Concept)

function debounce<T extends (...args: any[]) => any>(
  func: T,
  wait: number
): (...args: Parameters<T>) => void {
  let timeout: number | undefined;
  
  return function(...args: Parameters<T>) {
    clearTimeout(timeout);
    timeout = window.setTimeout(() => func(...args), wait);
  };
}

// Usage
const debouncedSearch = debounce((query: string) => {
  searchProducts(query);
}, 300);

searchInput.addEventListener('input', (e) => {
  debouncedSearch((e.target as HTMLInputElement).value);
});

Accessibility Patterns

ARIA Labels

<button 
  type="submit" 
  class="search-button" 
  aria-label="Search products"
>
  <svg><!-- Icon --></svg>
</button>

Keyboard Navigation

element.addEventListener('keydown', (event: KeyboardEvent) => {
  if (event.key === 'Enter' || event.key === ' ') {
    event.preventDefault();
    handleAction();
  }
});

Focus Management

button:focus-visible,
a:focus-visible {
  outline: 2px solid var(--color-secondary);
  outline-offset: 2px;
}

Validation Patterns

Form Validation

<input 
  type="email"
  name="email"
  required
  pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$"
/>

Type Guards

function isProduct(obj: any): obj is Product {
  return (
    typeof obj === 'object' &&
    typeof obj.id === 'number' &&
    typeof obj.title === 'string' &&
    typeof obj.price === 'number'
  );
}

// Usage
if (isProduct(data)) {
  // TypeScript knows data is Product here
  console.log(data.title);
}

Testing Patterns

Manual Testing Helpers

// Log state changes
function updateState(newState: Partial<AppState>): void {
  console.log('State before:', { ...appState });
  Object.assign(appState, newState);
  console.log('State after:', { ...appState });
  updateUI();
}

// Debug helper
function debugCart(): void {
  console.table(Array.from(cart.entries()).map(([id, qty]) => ({
    productId: id,
    quantity: qty
  })));
}

Code Organization

Module Pattern

// constants.ts
export const API_URL = "https://api.example.com";
export const MAX_PRODUCTS = 50;

// types.ts
export interface Product { /* ... */ }
export enum LoadingState { /* ... */ }

// utils.ts
export function getElement<T>(...) { /* ... */ }

// main.ts
import { API_URL } from './constants';
import { Product, LoadingState } from './types';
import { getElement } from './utils';

Best Practices Summary

State Management

  • Use centralized state object
  • Use enums for status
  • Update UI on state change

DOM Manipulation

  • Use event delegation
  • Type your elements with generics
  • Use data attributes for metadata

API Calls

  • Always handle errors
  • Show loading states
  • Validate responses

Code Style

  • Use BEM for CSS classes
  • Use TypeScript types
  • Keep functions small and focused

Next Steps

Project Tutorial

See these patterns in action

TypeScript Types

TypeScript reference

CSS Properties

CSS reference guide

Build docs developers (and LLMs) love