Skip to main content

Overview

The Siloé Perú website uses vanilla JavaScript (no frameworks) for all interactive features. The JavaScript code is embedded directly in index.html (lines 726-856) and handles:
  • Section navigation system
  • 3D flip card interactions
  • Form validation
  • Smooth scrolling
The website uses plain JavaScript (ES5/ES6) with no external dependencies, making it lightweight and easy to understand.

Code Structure

All JavaScript is wrapped in a DOMContentLoaded event listener to ensure the DOM is fully loaded:
index.html (lines 730-855)
document.addEventListener('DOMContentLoaded', function() {
    // All interactive code here
});

Getting DOM References

The script starts by grabbing references to all navigation buttons and section containers (lines 734-741):
index.html
const btnVoluntarios = document.getElementById('btn-voluntarios');
const btnClow = document.getElementById('btn-clow');
const btnAliados = document.getElementById('btn-aliados');
const btnNosotros = document.getElementById('btn-nosotros');

const seccionVoluntariado = document.getElementById('seccion-voluntariado');
const seccionClow = document.getElementById('seccion-clow');
const seccionAliados = document.getElementById('seccion-aliados');
const seccionNosotros = document.getElementById('seccion-nosotros');

Debug Logging

The code includes helpful console logs for debugging (lines 743-752):
index.html
console.log('✓ Elementos obtenidos:', {
    btnVoluntarios: !!btnVoluntarios,
    btnClow: !!btnClow,
    btnAliados: !!btnAliados,
    btnNosotros: !!btnNosotros,
    seccionVoluntariado: !!seccionVoluntariado,
    seccionClow: !!seccionClow,
    seccionAliados: !!seccionAliados,
    seccionNosotros: !!seccionNosotros
});
Open your browser’s Console (F12) to see these debug messages and verify that all elements are found correctly.

Section Switching Function

The core navigation logic is in the mostrarSeccion() function (lines 755-793):
index.html
function mostrarSeccion(nombre) {
    console.log('Mostrando sección:', nombre);
    
    // Ocultar todas las secciones
    seccionVoluntariado.classList.remove('seccion-activa');
    seccionVoluntariado.classList.add('seccion-inactiva');
    seccionClow.classList.remove('seccion-activa');
    seccionClow.classList.add('seccion-inactiva');
    seccionAliados.classList.remove('seccion-activa');
    seccionAliados.classList.add('seccion-inactiva');
    seccionNosotros.classList.remove('seccion-activa');
    seccionNosotros.classList.add('seccion-inactiva');
    
    // Remover estado activo de todos los botones
    btnVoluntarios.classList.remove('nav-btn-active');
    btnClow.classList.remove('nav-btn-active');
    btnAliados.classList.remove('nav-btn-active');
    btnNosotros.classList.remove('nav-btn-active');
    
    // Mostrar la sección seleccionada
    if (nombre === 'voluntarios') {
        seccionVoluntariado.classList.remove('seccion-inactiva');
        seccionVoluntariado.classList.add('seccion-activa');
        btnVoluntarios.classList.add('nav-btn-active');
    } else if (nombre === 'clow') {
        seccionClow.classList.remove('seccion-inactiva');
        seccionClow.classList.add('seccion-activa');
        btnClow.classList.add('nav-btn-active');
    } else if (nombre === 'aliados') {
        seccionAliados.classList.remove('seccion-inactiva');
        seccionAliados.classList.add('seccion-activa');
        btnAliados.classList.add('nav-btn-active');
    } else if (nombre === 'nosotros') {
        seccionNosotros.classList.remove('seccion-inactiva');
        seccionNosotros.classList.add('seccion-activa');
        btnNosotros.classList.add('nav-btn-active');
    }
    
    // Scroll suave hacia arriba
    window.scrollTo({ top: 0, behavior: 'smooth' });
}

How It Works

1

Hide All Sections

Removes seccion-activa and adds seccion-inactiva to all section containers
2

Deactivate All Buttons

Removes nav-btn-active class from all navigation buttons
3

Show Selected Section

Based on the section name parameter, adds seccion-activa to the target section and nav-btn-active to its button
4

Scroll to Top

Smoothly scrolls the page to the top using window.scrollTo({ top: 0, behavior: 'smooth' })

Event Listeners

Each button has a click event listener (lines 796-823):
index.html
if (btnVoluntarios) {
    btnVoluntarios.addEventListener('click', function(e) {
        e.preventDefault();
        mostrarSeccion('voluntarios');
    });
}

if (btnClow) {
    btnClow.addEventListener('click', function(e) {
        e.preventDefault();
        mostrarSeccion('clow');
    });
}

if (btnAliados) {
    btnAliados.addEventListener('click', function(e) {
        e.preventDefault();
        mostrarSeccion('aliados');
    });
}

if (btnNosotros) {
    btnNosotros.addEventListener('click', function(e) {
        e.preventDefault();
        mostrarSeccion('nosotros');
    });
}
e.preventDefault() prevents the default button behavior. The if checks ensure the code doesn’t crash if an element is missing.

Flip Card Interaction

Selecting All Flip Cards

The script selects all flip cards using querySelectorAll (lines 832-833):
index.html
const flipCards = document.querySelectorAll('.galeria-flip-card');
let currentFlipped = null; // Track currently flipped card

Click Event Handler

Each flip card gets a click listener (lines 836-853):
index.html
flipCards.forEach(card => {
    card.addEventListener('click', function() {
        // Si hay una tarjeta ya volteada y es diferente a esta
        if (currentFlipped && currentFlipped !== this) {
            // Voltear la anterior hacia atrás
            currentFlipped.classList.remove('flipped');
        }
        
        // Alternar la clase 'flipped' en la tarjeta actual
        this.classList.toggle('flipped');
        
        // Actualizar la referencia a la tarjeta volteada
        if (this.classList.contains('flipped')) {
            currentFlipped = this;
        } else {
            currentFlipped = null;
        }
    });
});

How Flip Cards Work

1

Check for Previously Flipped Card

If another card is already flipped and it’s not the current one, unflip it by removing the flipped class
2

Toggle Current Card

Uses classList.toggle('flipped') to flip or unflip the clicked card
3

Update State

Updates the currentFlipped variable to track which card (if any) is currently flipped
This ensures only one card is flipped at a time, creating a clean user experience.

State Management

The code uses a simple state management pattern:
let currentFlipped = null;  // Tracks which flip card is currently flipped
This variable is:
  • Set to the card element when a card is flipped
  • Set to null when the card is unflipped
  • Used to check if another card needs to be unflipped first

Smooth Scrolling

The navigation system includes smooth scrolling to top:
window.scrollTo({ top: 0, behavior: 'smooth' });
window.scrollTo({ top: 0, behavior: 'smooth' });
Supported in Chrome, Firefox, Safari (modern), Edge

Event Delegation Pattern

The code uses direct event listeners on each element rather than event delegation. This is appropriate given:
  • Fixed number of navigation buttons (4)
  • Fixed number of sections (4)
  • Flip cards are selected once on page load
For dynamically added content, you would want to use event delegation on a parent element instead.

Browser Compatibility

The JavaScript uses modern but widely supported features:
FeatureBrowser Support
addEventListenerAll modern browsers
classList.add/remove/toggleAll modern browsers
querySelectorAllAll modern browsers
forEachAll modern browsers
Arrow functionsES6+ (transpile for IE11)
const/letES6+ (transpile for IE11)
If you need to support Internet Explorer 11, consider using Babel to transpile the ES6 syntax to ES5.

Adding New Interactive Features

Example: Adding a “Back to Top” Button

1

Add HTML Button

<button id="back-to-top" class="back-to-top-btn"></button>
2

Add CSS Styling

.back-to-top-btn {
    position: fixed;
    bottom: 100px;
    right: 30px;
    display: none;
    z-index: 999;
}

.back-to-top-btn.visible {
    display: block;
}
3

Add JavaScript Logic

const backToTopBtn = document.getElementById('back-to-top');

window.addEventListener('scroll', function() {
    if (window.pageYOffset > 300) {
        backToTopBtn.classList.add('visible');
    } else {
        backToTopBtn.classList.remove('visible');
    }
});

backToTopBtn.addEventListener('click', function() {
    window.scrollTo({ top: 0, behavior: 'smooth' });
});

Debugging Tips

Console Logging

Add strategic console.log statements:
console.log('Button clicked:', buttonName);
console.log('Current section:', currentSection);
console.log('Flipped card:', card);

Browser DevTools

Use browser DevTools to:
  • Set breakpoints in the Sources panel
  • Inspect element references in the Console
  • Monitor event listeners in the Elements panel
  • Watch variable values during execution

Common Issues

Symptom: Cannot read property 'addEventListener' of nullSolution:
  • Check that element IDs match exactly
  • Verify script runs after DOM is loaded
  • Check for typos in getElementById() calls
Symptom: Click does nothingSolution:
  • Check Console for JavaScript errors
  • Verify event listeners are attached
  • Make sure element isn’t being covered by another element
  • Check z-index values
Symptom: Visual state doesn’t changeSolution:
  • Verify CSS classes are defined in style.css
  • Check class names for typos
  • Inspect element in DevTools to see which classes are applied
  • Check for CSS specificity conflicts

Performance Considerations

Efficient Selectors

Use getElementById (fastest) when possible instead of querySelector

Event Throttling

For scroll events, consider throttling to reduce function calls

Minimize Reflows

Batch DOM changes together to minimize browser reflows

Remove Unused Code

Remove console.log statements in production for slight performance gain

Next Steps

Responsive Design

Learn about mobile-first responsive patterns

Navigation Component

Deep dive into the navigation system component

Flip Cards Component

Explore the 3D flip card implementation

Content Customization

Customize text and messaging

Build docs developers (and LLMs) love