Skip to content

Footer

A footer is located on the bottom of a website. A typical footer contains:

  • Links to general information pages (e.g. About, Contact)
  • Links to legal pages (e.g. Terms of Service, Privacy Policy)
  • Links to social media
  • Copyright notice

Tests

E2E Test

Before implementing the navigation bar we will create an E2E test in Qase. Add a new test case to the "Web Exclusive" suite named "Navigation Bar":

Footer Test 1

Footer Test 2

Integration Tests

There is nothing for us to test at the integration level as the footer has no logic or any kind of code.

Unit Tests

There is nothing for us to test at the unit level since the footer has no logic or any kind of code.

Production Code

Our footer will link to pages that don't exist yet, e.g. the about page. For the time being we need to create empty pages in our Phoenix project so that these links work. In later sections of this guide we will fill these empty pages with content.

Templates

We will now create the HTML templates for our new pages. Create the following files in the directory lib/epic_fantasy_forge_web/controllers/page_html/:

  • about.html.heex
  • acceptable_use_policy.html.heex
  • contact.html.heex
  • cookie_policy.html.heex
  • privacy_policy.html.heex
  • terms_of_service.html.heex
  • third_party.html.heex

The new files can remain empty for now.

Controllers

Update lib/epic_fantasy_forge_web/controllers/page_controller.ex to include the new pages. You can also re-order the existing functions in the file to be in alphabetical order. Finally, your page_controller.ex should look something like this:

page_controller.ex
defmodule EpicFantasyForgeWeb.PageController do
  use EpicFantasyForgeWeb, :controller

  def about(conn, _params) do
    render(conn, :about, layout: {EpicFantasyForgeWeb.Layouts, :website})
  end

  def acceptable_use_policy(conn, _params) do
    render(conn, :acceptable_use_policy,
      layout: {EpicFantasyForgeWeb.Layouts, :website}
    )
  end

  def contact(conn, _params) do
    render(conn, :contact, layout: {EpicFantasyForgeWeb.Layouts, :website})
  end

  def cookie_policy(conn, _params) do
    render(conn, :cookie_policy,
      layout: {EpicFantasyForgeWeb.Layouts, :website}
    )
  end

  def download(conn, _params) do
    render(conn, :download, layout: {EpicFantasyForgeWeb.Layouts, :website})
  end

  def home(conn, _params) do
    render(conn, :home, layout: {EpicFantasyForgeWeb.Layouts, :website})
  end

  def privacy_policy(conn, _params) do
    render(conn, :privacy_policy,
      layout: {EpicFantasyForgeWeb.Layouts, :website}
    )
  end

  def terms_of_service(conn, _params) do
    render(conn, :terms_of_service,
      layout: {EpicFantasyForgeWeb.Layouts, :website}
    )
  end

  def third_party(conn, _params) do
    render(conn, :third_party, layout: {EpicFantasyForgeWeb.Layouts, :website})
  end
end

Router

Now open lib/epic_fantasy_forge_web/router.ex and add routes for the new pages. You can also re-order the existing routes to be in alphabetical order. Finally, the routes in your router.ex should look something like this:

router.ex
    get "/", PageController, :home
    get "/about", PageController, :about
    get "/acceptable-use-policy", PageController, :acceptable_use_policy
    get "/app", AppController, :app
    get "/contact", PageController, :contact
    get "/cookie-policy", PageController, :cookie_policy
    get "/download", PageController, :download
    get "/privacy-policy", PageController, :privacy_policy
    get "/terms-of-service", PageController, :terms_of_service
    get "/third-party", PageController, :third_party

HTML

Inside the lib/epic_fantasy_forge_web/components/web/templates directory create a file named footer.html.heex and populate it with the below content:

footer.html.heex
<footer class="bg-gray-900">
  <div class="mx-auto max-w-7xl px-6 py-4 sm:py-6 lg:px-8 lg:py-8">
    <div class="mt-12 border-t border-white/10 pt-6">
      <div class="mt-0 grid grid-cols-2 gap-8 xl:col-span-2">
        <div class="md:grid md:grid-cols-2 md:gap-8">
          <div>
            <h3 class="text-sm/6 font-semibold text-white">Author</h3>
            <ul role="list" class="mt-6 space-y-4">
              <li>
                <a
                  href="/about"
                  class="text-sm/6 text-gray-400 hover:text-white"
                >
                  About
                </a>
              </li>
              <li>
                <a
                  href="/contact"
                  class="text-sm/6 text-gray-400 hover:text-white"
                >
                  Contact
                </a>
              </li>
            </ul>
          </div>
          <div class="mt-10 md:mt-0">
            <h3 class="text-sm/6 font-semibold text-white">Project</h3>
            <ul role="list" class="mt-6 space-y-4">
              <li>
                <a
                  href="https://epicfantasyforge.featurebase.app/changelog"
                  target="_blank"
                  rel="noopener noreferrer"
                  class="text-sm/6 text-gray-400 hover:text-white"
                >
                  Changelog
                </a>
              </li>
              <li>
                <a
                  href="/third-party"
                  class="text-sm/6 text-gray-400 hover:text-white"
                >
                  Third-party
                </a>
              </li>
            </ul>
          </div>
        </div>
        <div class="md:grid md:grid-cols-2 md:gap-8">
          <div>
            <h3 class="text-sm/6 font-semibold text-white">Legal</h3>
            <ul role="list" class="mt-6 space-y-4">
              <li>
                <a
                  href="/terms-of-service"
                  class="text-sm/6 text-gray-400 hover:text-white"
                >
                  Terms of Service
                </a>
              </li>
              <li>
                <a
                  href="/acceptable-use-policy"
                  class="text-sm/6 text-gray-400 hover:text-white"
                >
                  Acceptable Use Policy
                </a>
              </li>
            </ul>
          </div>
          <div class="mt-10 md:mt-0">
            <h3 class="text-sm/6 font-semibold text-white">Privacy</h3>
            <ul role="list" class="mt-6 space-y-4">
              <li>
                <a
                  href="/privacy-policy"
                  class="text-sm/6 text-gray-400 hover:text-white"
                >
                  Privacy Policy
                </a>
              </li>
              <li>
                <a
                  href="/cookie-policy"
                  class="text-sm/6 text-gray-400 hover:text-white"
                >
                  Cookie Policy
                </a>
              </li>
            </ul>
          </div>
        </div>
      </div>
    </div>
    <div class="mt-12 border-t border-white/10 pt-8 md:flex md:items-center md:justify-between">
      <div class="flex gap-x-6 md:order-2">
        <a
          href="https://gitlab.com/brusecke/epic-fantasy-forge"
          target="_blank"
          rel="noopener noreferrer"
          class="text-gray-400 hover:text-gray-300"
        >
          <span class="sr-only">GitLab</span>
          <svg
            class="w-[18px] h-[18px] fill-[#9ca3af] hover:fill-[#d1d5db]"
            viewBox="0 0 512 512"
            xmlns="http://www.w3.org/2000/svg"
          >
            <!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
            <path d="M503.5 204.6L502.8 202.8L433.1 21.02C431.7 17.45 429.2 14.43 425.9 12.38C423.5 10.83 420.8 9.865 417.9 9.57C415 9.275 412.2 9.653 409.5 10.68C406.8 11.7 404.4 13.34 402.4 15.46C400.5 17.58 399.1 20.13 398.3 22.9L351.3 166.9H160.8L113.7 22.9C112.9 20.13 111.5 17.59 109.6 15.47C107.6 13.35 105.2 11.72 102.5 10.7C99.86 9.675 96.98 9.295 94.12 9.587C91.26 9.878 88.51 10.83 86.08 12.38C82.84 14.43 80.33 17.45 78.92 21.02L9.267 202.8L8.543 204.6C-1.484 230.8-2.72 259.6 5.023 286.6C12.77 313.5 29.07 337.3 51.47 354.2L51.74 354.4L52.33 354.8L158.3 434.3L210.9 474L242.9 498.2C246.6 500.1 251.2 502.5 255.9 502.5C260.6 502.5 265.2 500.1 268.9 498.2L300.9 474L353.5 434.3L460.2 354.4L460.5 354.1C482.9 337.2 499.2 313.5 506.1 286.6C514.7 259.6 513.5 230.8 503.5 204.6z">
            </path>
          </svg>
        </a>
        <a
          href="https://www.linkedin.com/in/henrik-bruesecke-07961791/"
          target="_blank"
          rel="noopener noreferrer"
          class="text-gray-400 hover:text-gray-300"
        >
          <span class="sr-only">LinkedIn</span>
          <svg
            class="w-[18px] h-[18px] fill-[#9ca3af] hover:fill-[#d1d5db]"
            viewBox="0 0 448 512"
            xmlns="http://www.w3.org/2000/svg"
          >
            <!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
            <path d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z">
            </path>
          </svg>
        </a>
      </div>
      <p class="mt-8 text-sm/6 text-gray-400 md:order-1 md:mt-0">
        Copyright &copy; 2025 Henrik Brüsecke
      </p>
    </div>
  </div>
</footer>

We can now take this new footer component into use in our website.html.heex layout. Add the below at the end of the file:

website.html.heex
<EpicFantasyForgeWeb.WebComponents.footer />

Now when you run your Phoenix project you should have a footer:

Desktop Footer

On mobile sized screens the footer should look like this:

Mobile Footer

Since our pages don't have any content yet the footer appears directly underneath the navigation bar. Once we add content to the currently empty pages in a later section of this guide the footer will naturally appear underneath the page content.