Back to Freecodecamp

Build a Reusable Footer

curriculum/challenges/english/blocks/lab-reusable-footer/673b02b03134b04637bf7055.md

latest5.7 KB
Original Source

--description--

Objective: Fulfill the user stories below and get all the tests to pass to complete the lab.

User Stories:

  1. You should export a Footer component.

  2. Your Footer component should return a footer element that contains all the other elements.

  3. Your footer element should have:

    • At least three unordered lists, each with at least two list items.
    • At least one paragraph element with a copyright © symbol.
    • At least three links with the href value set to # and the link content set to an icon or text of your choice.

--hints--

You should export a Footer component.

js
assert.isFunction(window.index.Footer);

Your Footer component should return a footer element.

js
const footer = document.getElementById('root').firstElementChild;
assert.equal(footer.tagName, 'FOOTER');

Your Footer component should only contain a single footer element.

js
assert.lengthOf(document.querySelectorAll('footer'), 1);

Your footer element should not have any siblings.

js
assert.lengthOf(document.getElementById('root').children, 1);

Your footer element should contain at least three unordered lists.

js
assert.isAtLeast(document.querySelectorAll('ul').length, 3);

Each of your unordered lists should have at least two list items.

js
const uls = [...document.querySelectorAll('ul')];
uls.forEach(ul => {
    assert.isAtLeast(ul.querySelectorAll('li').length, 2);
  }
);

Your footer should have at least one paragraph element.

js
assert.isAtLeast(document.querySelectorAll('p').length, 1);

You should have a copyright (©) symbol within one of your paragraphs.

js
const texts = [...document.querySelectorAll('p')].map(p => p.textContent);
const hasCopyright = texts.some(text => text.includes('©'));
assert.isTrue(hasCopyright);

Your footer should have at least three links with the href value set to #.

js
const links = document.querySelectorAll('a[href="#"]');
assert.isAtLeast(links.length, 3);

None of your links should be empty.

js
const links = [...document.querySelectorAll('a[href="#"]')];
links.forEach(link => {
    assert.isNotEmpty(link.textContent);
  }
);

--seed--

--seed-contents--

html
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Reusable Footer Component</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      src="index.jsx"
    ></script>
    <link rel="stylesheet" href="styles.css" />
  </head>

  <body>
    <div id="root"></div>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      data-presets="react"
      data-type="module"
    >
      import { Footer } from './index.jsx';
      ReactDOM.createRoot(document.getElementById('root')).render(<Footer />);
    </script>
  </body>
</html>
css
jsx

--solutions--

html
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Reusable Footer Component</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      src="index.jsx"
    ></script>
    <link rel="stylesheet" href="styles.css" />
  </head>

  <body>
    <div id="root"></div>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      data-presets="react"
      data-type="module"
    >
      import { Footer } from './index.jsx';
      ReactDOM.createRoot(document.getElementById('root')).render(<Footer />);
    </script>
  </body>
</html>
css
.footer {
  background-color: #e3e1eb;
  padding: 20px;
  text-align: center;
  border-top: 1px solid #e5e7eb;
  font-family: Arial, sans-serif;
}

.footer-section {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  justify-content: center;
  margin-bottom: 20px;
  align-items: center;
}

.footer ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.footer li {
  margin-bottom: 10px;
}

.footer a {
  text-decoration: none;
  color: #1f2937;
}

.footer a:hover {
  color: #6366f1;
}

.footer p {
  color: #6b7280;
  margin-top: 20px;
}

.footer-icons {
  margin-top: 20px;
  display: flex;
  justify-content: center;
}

.footer-icons a {
  margin: 0 10px;
  font-size: 24px;
  color: #6b7280;
  text-decoration: none;
}

.footer-icons a:hover {
  color: #6366f1;
}
jsx
export const Footer = () => (
  <footer className='footer'>
    <div className='footer-section'>
      <ul>
        <li>
          <a href='#'>Fitness Dashboard</a>
        </li>
        <li>
          <a href='#'>Services</a>
        </li>
      </ul>
      <ul>
        <li>
          <a href='#'>Watch Videos</a>
        </li>
        <li>
          <a href='#'>Discord</a>
        </li>
      </ul>
      <ul>
        <li>
          <a href='#'>Privacy Policy</a>
        </li>
        <li>
          <a href='#'>Terms & Conditions</a>
        </li>
      </ul>
    </div>
    <p>© 2024 Fitness Dashboard. All Rights Reserved.</p>
    <div className='footer-icons'>
      <a href='#'>&#x1F3AE;</a>
      <a href='#'>&#x1F426;</a>
      <a href='#'>&#x1F4BB;</a>
      <a href='#'>&#x1F3C0;</a>
    </div>
  </footer>
);