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":
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:
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:
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 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 © 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:
<EpicFantasyForgeWeb.WebComponents.footer />
Now when you run your Phoenix project you should have a footer:
On mobile sized screens the footer should look like this:
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.