Skip to main content

Footer

Reusable Footer - Three Column Layout with Navigation, Social and Contacts (Screenshot Desktop)

The Project

Footer is a React component that represents my first unguided exercise after learning the basics of JSX syntax and componentization.

It was extremely useful as an exercise because freeCodeCamp had taught me how to create a navbar, but not a footer. Well, the concepts translate with extreme similarity: same logic of semantic lists, same separation between structure (JSX) and style (CSS), same declarative approach.

Source Code

{/* DESIGN
------
* This file contains the React structure for the Footer component
* The architecture follows this semantic and functional flow:
*
* Architectural decisions (Layout strategy):
* - I realized that the original reference design (simoneamico.com) utilized a 2-column layout
* - To satisfy the strict lab constraint ("At least three unordered lists"), I logically split the
* content into "Navigation", "Social", and "Contacts"
* - This approach allows the component to pass validation tests while maintaining logical grouping
* and visual hierarchy
*
* Semantic structure (Accessibility):
* - I chose the HTML5 <footer> tag as the top-level semantic landmark
* - I encapsulated link groups in <ul> elements to ensure accessibility, as screen readers
* interpret these specifically as navigational lists
* - The copyright section is isolated in a ".footer-bottom" container to allow for separate
* spacing and styling logic
*
* Implementation details:
* - All links use href="#" placeholders as mandated by the lab requirements
* - The "footer-columns" wrapper is designed to support CSS Flexbox or Grid for responsive alignment.
*/}

{/*
* freeCodeCamp instructions:
* 1. You should export a Footer component. ✔️
* 2. Your Footer component should return a footer element. ✔️
* 3. Your Footer component should only contain a single footer element. ✔️
* 4. Your footer element should not have any siblings. ✔️
* 5. Your footer element should contain at least three unordered lists. ✔️
* 6. Each of your unordered lists should have at least two list items. ✔️
* 7. Your footer should have at least one paragraph element. ✔️
* 8. You should have a copyright (©) symbol within one of your paragraphs. ✔️
* 9. Your footer should have at least three links with the href value set to #. ✔️
* 10. None of your links should be empty. ✔️
*/}

export const Footer = () => {
return (
<footer>

{/*
* Container wrapper designed for CSS Grid/Flexbox alignment.
* Even though this lab focuses on HTML structure, this div
* prepares the layout for the 3-column responsive design.
*/}

<div className="footer-columns">

{/* Section 1: Main navigation */}
<div className="footer-section">
<h4>NAVIGATION</h4>
<ul>
<li><a href="#">Featured</a></li>
<li><a href="#">Path</a></li>
<li><a href="#">Vademecum</a></li>
<li><a href="#">Bookshelf</a></li>
</ul>
</div>

{/* Section 2: Social links (split from contacts to meet list quota) */}
<div className="footer-section">
<h4>SOCIAL</h4>
<ul>
<li><a href="#">Origin Story</a></li>
<li><a href="#">LinkedIn</a></li>
</ul>
</div>

{/* Section 3: Direct contacts and legal */}
<div className="footer-section">
<h4>CONTACTS</h4>
<ul>
<li><a href="#">Email</a></li>
<li><a href="#">Privacy Policy</a></li> {/* added "Privacy Policy" to satisfy "at least 2 items" rule */}
</ul>
</div>
</div>

{/* Copyright Section */}
<div className="footer-bottom">
<p>Copyright © 2026 Simone Amico.</p>
<p>Built with freeCodeCamp.</p>
</div>
</footer>
);
}

Design: Hybrid between Light and Dark Mode

I opted to replicate the footer of the simoneamico.com site (Docusaurus), but I didn't want to make it identical because that one already exists.
I played with a visual hybrid between the site's Light and Dark mode: "Espresso & Amber" palette (dark variant of "Coffee & Sand"), three-column layout, but with a skeuomorphic twist that simulates a "dark wood frame" (#7c6148) wrapping the "espresso content" (#423121).

It was the CSS that dressed the footer as if it were at the bottom of a card/application, but the component itself remains standalone, keeping intact the task required by freeCodeCamp: pure semantic structure, exportable and reusable.

Note on shared CSS: I kept navbar styles (from the previous project) in the file to have a coherent design system. Navbar and Footer share the same tokens (colors, spacing, z-index), so it makes sense to keep them in the same CSS instead of duplicating variables. It's the same approach I would use in a real project.

What I Learned

Divide et Impera (Layout Strategy):

  • The reference design uses a 2-column layout, but freeCodeCamp required "at least three <ul> lists". I logically divided the content into "Navigation", "Social" and "Contacts" to satisfy the constraint while maintaining visual hierarchy and logical grouping.
  • This choice isn't just formal: it prepares the component for a data-driven future (instead of writing three <ul> by hand, I'll pass an array of sections as prop and use .map()).

HTML5 Semantics and Accessibility:

  • Mandatory use of the <footer> tag as a first-level semantic landmark (screen readers immediately recognize the context).
  • <ul> lists to group links: not just freeCodeCamp validation, but explicit signal to assistive tech that it's navigation.
  • .footer-bottom separation for copyright: spacing/styling logic isolated from the rest, preparing the ground for more complex responsive layouts.

Design Tokens and Single Source of Truth:

  • I centralized everything in CSS :root variables (colors, 8pt grid spacing, typography, z-index, transitions). Modifying the theme means touching a single point, not 50 scattered files.
  • Consistent naming convention: --color-primary, --space-md, --radius-lg. This mentally prepares for the "Props" concept in React: instead of hardcoding values, you pass references to a system.

Responsive Layout (Grid Auto-Fit):

  • grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)): CSS Grid pattern that automatically adapts the number of columns based on available width. It's the CSS version of React's "responsive by default".
  • On mobile (@media screen and (max-width: 768px)), I force grid-template-columns: 1fr for vertical stack. I also removed body padding and border-radius to go from "framed app" to "fullscreen native experience".

Overflow Clipping and Border Radius:

  • overflow: hidden on the #root container is crucial: it forces navbar and footer (which have square corners) to respect the parent container's border-radius, avoiding the "corner bleed" artifact.
  • This is a pattern that will come in handy when I need to manage child components that shouldn't "overflow" from the parent's boundaries.

Hover State with pure CSS vs React State:

  • I managed the navbar dropdown with CSS :hover (display: nonedisplay: flex). Performant and JS-free, perfect for a lab.
  • But I added a comment in the code: "In production React, this would be managed via State (isOpen)". I understood that CSS hover doesn't work on mobile (no hover with finger) and isn't keyboard-controllable. React State solves both.

Sticky Footer Technique:

  • margin-top: auto on footer inside a container display: flex; flex-direction: column; min-height: 95vh: modern technique for "footer stuck at bottom" without absolute positioning. The footer auto-pushes itself to the viewport bottom, even if content is scarce.

CDN Architecture vs Vite (Engine Room):

  • I analyzed the pre-packaged index.html from freeCodeCamp: it loads React/ReactDOM via CDN (streaming) instead of local bundle, and uses Babel Standalone as a "simultaneous translator" that converts JSX into JS directly in the browser.
  • It's the opposite of Vite: instead of "cooking" the code on my computer before sending it to the browser, the "cooking" happens live in the user's browser. Convenient for labs, but not scalable in production (too much overhead).

Link Placeholder (href="#") and Technical Debt:

  • All links use href="#" as required by the lab. I understood that this is "intentional technical debt": in a real React SPA, these would become <Link to="/path"> (React Router) for navigation without reload.
  • Here too, the current structure is "React-ready": just replace <a> with <Link> component and pass routes as prop.

Animation FadeIn with @keyframes:

  • Dropdown menu uses animation: fadeIn 0.2s instead of just transition, because I want to control both opacity AND transform (translateY). Transition only handles single properties that change, Keyframes orchestrate sequences.

Mobile-First Mindset:

  • I wrote desktop-first CSS (for visual convenience during development), but I understood that in production you start from mobile (@media (min-width: 768px)) for Progressive Enhancement. Now that I've seen both approaches, I understand why mobile-first is standard.

Reflections

By now you know it's always like this: when I do unguided exercises like Certification Projects or these Labs (which are essentially Certification Projects with pre-packaged index.html), I find little to say in READMEs precisely because I said everything in the source code in various comments.


Next:
Learning to work with Props, Conditional Rendering and Lists in React, to then apply everything in the Profile Card Component