# VuePress Tutorial 8 - Custom Footer

By: Jay the Code Monkey
Posted: Apr 6, 2022 Updated: Apr 18, 2023

Now it's time to start building the custom footer component for the site. Before creating the footer component, we're going to first describe what a footer is then we'll mention some other options for footers provided by VuePress (opens new window) and the @vuepress/theme-blog (opens new window).

A footer is located at the bottom of a page, and it typically contains:

  • Authorship Information
  • Copyright Information
  • Contact Information
  • Sitemap (Important Links Regardless of Current Page - Similar to Global Navbar)

For the Code Monkeys Blog we'll be building a footer that consists of links to various social media platforms. This gives the user an easy way to interact with various content and the community.

Take a look at the footer on this page to see what we'll be designing for the blog. To see another example you can check out the VuePress (opens new window) site footer as well.

Make sure you start the local development server which should be running at http://localhost:8080/ (opens new window) to see the changes we'll be making to the site. If the changes aren't appearing after you save them, then try restarting your local development server.

If you remember from the previous post VuePress Tutorial 6 - Homepage Layout, VuePress (opens new window) provides a way to add a footer to the homepage by adding the following to the homepage layout which is located in docs/README.md:

If you do decide to add a footer using the frontmatter in the homepage, then the HTML will look like this:

VuePress (opens new window) also provides a rich-text footer (opens new window) which gives you the ability to easily add more functionality to your footer like links. To set this type of footer you need to use markdown slot syntax (opens new window) which we won't discuss in detail here.

Since the rich-text footer (opens new window) uses markdown slot syntax (opens new window), you can only add it to markdown files, and it needs to be manaully added to each markdown file to be displayed.

These limitations are why we'll be creating a custom footer component. If you only want to show the footer on one or a few markdown pages, then this option should work fine for you.

The Code Monkeys Blog uses the default theme (opens new window), but if you're interested in using @vuepress/theme-blog (opens new window) be sure to take a look at the footer option (opens new window).

Here are some examples of sites that use the @vuepress/theme-blog (opens new window) footer:

Since we'll be using social media sites that are not currently supported by the footer.contact (opens new window) option, we won't be using this footer. You can contribute social media contact types by making a pull request to the vuepress-theme-blog (opens new window) repository though if you're interested.

Before designing the custom footer component, we need to have an understanding of the following topics:

We won't be describing every detail about each topic above since we only need to understand how to create our custom footer component. If you're interested in learning more now, then check out the links above.

# Writing a Theme

In VuePress (opens new window) you have the ability to make your site into a theme. This gives you the option to publish your site as an npm (opens new window) package which allows other developers to easily install and use your theme.

To write your own theme you need to create a theme directory in the .vuepress directory. The docs directory for your site should now look something like this:

. ├── docs │ ├── .vuepress │ │ ├── public │ │ ├── theme │ │ └── config.js │ └── README.md

After creating the theme directory, all you need to do is create a Layout.vue file inside of it like this:

. ├── docs │ ├── .vuepress │ │ ├── public │ │ ├── theme │ │ │ └── Layout.vue │ │ └── config.js │ └── README.md

From here you can develop your site like any other Vue (opens new window) application by organizing your theme however you want. Being able to organize your theme however you want provides a lot of flexibility when creating your site, but it's recommended to use the directory structure below when designing your theme:

theme ├── components │ └── xxx.vue ├── global-components │ └── xxx.vue ├── layouts │ ├── Layout.vue (Mandatory) │ └── xxx.vue ├── styles │ ├── index.styl │ └── palette.styl ├── templates │ ├── dev.html │ └── ssr.html ├── enhanceApp.js └── index.js

Here's a description for each directory and file in the theme directory:

  • components: Local components used in your theme.
  • global-components: Components in this directory automatically get registered as global, so you don't need to explicitly import them in a file when using them.
  • layouts: Layout components used in your theme.
    • Layout.vue: A mandatory layout file for every theme.
  • styles: Stores files related to styling your theme.
    • index.styl: Overrides any default styling and allows you to globally style your site.
    • palette.styl: Overrides any default styling variables and allows you to add any global styling variables.
  • templates: Stores HTML template files.
    • dev.html: HTML template file for development environment.
    • ssr.html: HTML template file used in the build time.
  • enhanceApp.js: Enhances the theme of your site by giving you the ability to install Vue plugins, add router hooks, etc.
  • index.js: Entry file for for theme configuration.

Reviewing the Recommended Directory Structure for Themes

You may have recognized this directory structure from the VuePress Tutorial 4 - Directory Structure post.

When creating the custom footer component we'll use the global-components directory, the index.js file, and the layouts directory. The global-components directory will be where we add the custom footer component since we want the footer to be available globally. The index.js file will be used to inherit the default theme (opens new window) using theme inheritance (opens new window). Finally, the layouts directory will be where we add the GlobalLayout.vue file which allows us to add our custom footer component to the global layout of the site.

Since we'll be using the vuepress-plugin-svg-icons (opens new window) to add social media icons to our footer, let's go over what plugins (opens new window) are, how to install them, and how to configure them.

# Basics of Plugins

Plugins (opens new window) allow you to add global-level functionality to VuePress (opens new window). You can configure them by passing in options. It's also possible to write your own and publish them as npm (opens new window) packages.

To use a plugin you need to first install it by using either yarn or npm. We'll be using yarn to install all of the plugins for the blog, but the commands for installing the plugins with npm will also be provided. After installing a plugin, you can configure it by adding it to the config.js file.

# VuePress Plugin - SVG Icons

Now that we know the basics, we're ready to install and configure vuepress-plugin-svg-icons (opens new window).

# Using the Tutorials Repo

If you're following along with the tutorials, then when you switch to the tutorial-8 branch you can run the following command to install the package instead of running the installation command:

This will ensure you have the same version used in the blog since the command uses the version specified in the yarn.lock file during the installation.

# Using the Installation Command

To install the plugin in your own project you can run the following command:

Installing the Same Plugin Version

If you want to ensure you're installing the same version being used in the tutorials and blog, then run yarn upgrade @goy/vuepress-plugin-svg-icons@4.2.3.

After installing the plugin, the package.json file should look something like this:

Next we need to configure the plugin by editing the config.js file:

To add the social media icons to the site we need to create an icons directory in the docs directory. Here's what the docs directory should look like after adding the icons directory:

. ├── docs │ ├── .vuepress │ ├── icons │ └── README.md

The plugin recommends using iconfont (opens new window) to find Scalable Vector Graphics (SVGs) (opens new window) for your site. After creating an account, you can search for icons and download them. When downloading the icons you have the option to specify a color and size for the icon. For the blog we'll be using a color of #e6e6e6 and a size of 200 which is the default size.

You can download the icons from the tutorial-8 branch of the code-monkeys-blog-tutorials (opens new window) repository.

Using SVG Export

To easily download the icons used in the footer you can also install the browser extension SVG Export (opens new window). After installing the extension, all you need to do is click the extension icon which will extract all of the SVGs including their inline styles from the current page. A new tab will open containing all of the extracted SVGs which you can then download.

We'll be using icons for these social media sites in the footer:

After downloading the icons the icons directory should look something like this:

├── icons │ ├── Discord.svg │ ├── GitHub.svg │ ├── LinkedIn.svg │ ├── Patreon.svg │ ├── Telegram.svg │ ├── Twitter.svg │ └── YouTube.svg

After adding the icons to icons directory, the plugin will automically load the icons and will provide a global component named vp-icon. To use the vp-icon component you need to pass a name attribute to it where the value is the name of the SVG file you want to use.

If you're interested in learning more about the plugin, then check out the vuepress-plugin-svg-icons (opens new window) documentation which contains more information about configuration options, component props, and command-line interface (CLI) commands.

We're now ready to create the custom footer component.

The custom footer component will be added to the global-components directory. Here's what the theme directory will look like after adding the Footer.vue file:

├── theme │ ├── global-components │ │ └── Footer.vue

Here we're creating a *.vue file which is known as a Single-File Component (SFC) (opens new window). This is a special file format that allows you to encapsulate the HTML in a template tag, the JavaScript in a script tag, and the CSS in a style tag for the component.

Here's what the Footer.vue file looks like after adding these three main sections:

To start we'll add the HTML to the template tag. The contents of the footer will be wrapped in a footer tag containing two child tags a div tag and a p tag. The div tag will contain seven child a tags one for each of the social media icons. The p tag will contain authorship information for the blog.

Each a tag will have the following attributes: href, target, and rel. The href specifies the URL of the page the link goes to, the target specifies where to open the link, and the rel specifies the relationship between the current page and the link. Each a tag will also have a child vp-icon tag which will have the name attribute discussed earlier.

Here's what the Footer.vue file looks like after adding the HTML to the template tag:

Each href has a value of the related URL for the social media site. Each target has a value of _blank, and each rel has a value of noopener noreferrer.

As mentioned in the previous post these values for the target and rel attributes are used to prevent a vulnerability known as reverse tabnabbing (opens new window) which can happen when a user clicks on an external link. All major browsers have fixed this vulnerability, but you can still include these attributes in case a user is using a browser without this security update.

Each name attribute has a value of the name of the related SVG file with the .svg extension omitted.

Next we'll export the JavaScript in the script tag and give the component a name. Here's what the Footer.vue file looks like after updating the script tag:

Finally, we'll style the component by adding the following CSS classes: "footer", "icons", and "made-by". We'll be adding the "footer" class to the footer tag, the "icons" class to the div tag, and the "made-by" class to the p tag. Then we'll add styling for each of the CSS classes in the style tag. Here's what the Footer.vue file looks like after styling:

The lang attribute used in the style tag is used to specify which pre-processor we want to use in the component. Here we're using Stylus (opens new window) which is the default pre-processor used by VuePress (opens new window). If you want to learn how to use a different pre-processor, then check out Using Pre-processors (opens new window).

A scoped attribute is also used in the style tag which means all of the styling only applies to the current component. Take a look at Scoped CSS (opens new window) to learn more about the scoped attribute.

The "footer" class is given display: flex which defines a flex container for all of the direct children of the tag where the "footer" class is used. In this case the "footer" class is used on the footer tag which means the div tag and p tag will be in a flex container. The "footer" class is also given flex-direction: column which means the flex items in the flex container, i.e., the div tag and the p tag will be stacked on top of each other in a column as opposed to the default row setting. The flex items are then given align-items: center which will horizontally center the flex items since the flex direction is set to column. The "footer" class is then given padding: 2.5rem 2.5rem 2rem which will set a padding of 2.5rem for the top, 2.5rem for the left and right, and 2rem for the bottom.

If you're unfamiliar with flexbox, then check out A Complete Guide to Flexbox (opens new window) and Basic Concepts of Flexbox (opens new window). Also, if you're unfamiliar with CSS units like rem, then check out CSS Units (opens new window).

The "icons" class is also given display: flex which means each a tag will be in a flex container since they're all direct children of the div tag which has the "icons" class. The "icons" class is also given margin-bottom: 1.75rem and font-size: 2rem which increases the size of the icons. The CSS selector .icons > a:not(:last-child) is then used which selects all a tags where the parent tag has a class of "icons" except for the last a tag. Each a tag that is selected is given margin-right: 4.6875rem.

If you're unfamiliar with CSS selectors, then check out the CSS Selector Reference (opens new window).

Finally, the "made-by" class is given margin: 0 which removes the margin from the p tag.

If you didn't feel comfortable with the CSS discussed above, then here's a good resource to go through CSS Tutorial (opens new window).

As we continue to develop the blog, we'll add more styling to the footer to make it look presentable in different scenarios like on smaller screen sizes, when a sidebar is present, etc.

Here's what the Footer.vue file should look like:

After adding the global-components directory to the theme directory, you may have noticed the site is rendering a blank page. This is because we created a directory in the theme directory, so VuePress (opens new window) is now looking for a Layout.vue file in the theme directory.

We have the option of creating a layouts directory and placing our own Layout.vue file inside of it, but as previously mentioned we're going to use theme inheritance (opens new window) to inherit the default theme (opens new window).

# Theme Inheritance

Theme inheritance (opens new window) allows you to pass all of the capabilities from a parent theme to a child theme. In our case the parent theme is the default theme (opens new window), and we'll be creating the child theme as we develop the blog.

To create the child theme from the default theme (opens new window), we need to configure the extend (opens new window) option in the index.js file.

First, we need to create the index.js file in the theme directory which should now look like this:

├── theme │ ├── global-components │ └── index.js

We can now configure the extend (opens new window) option:

The inherited default theme (opens new window) should now be rendering alongside the child theme instead of the blank page.

Missing Layout.vue File

You may have noticed that the Layout.vue file is listed as a mandatory file, but we didn't need to create one in the theme directory. This is because you don't need to explicitly create the Layout.vue file when you're inheriting it from the default theme (opens new window).

The child theme is also able to override files in the parent theme by creating a file with the same name in the same location. We'll go over how to override parent theme files in more detail in future tutorials. You can also override some parent theme files by just using the same name as the parent theme file in the child theme. For example, we're going to override the GlobalLayout.vue file by using the same name for the file in the child theme and the code provided by the documentation.

Now let's create the layouts directory in the theme directory. This is where we'll be adding the GlobalLayout.vue file which again allows us to add our custom footer component to the global layout of the site.

# Using the Global Layout

Here's what the theme directory will look like after creating the GlobalLayout.vue file in the layouts directory:

├── theme │ ├── global-components │ ├── layouts │ │ └── GlobalLayout.vue │ └── index.js

The GlobalLayout.vue file is responsible for handling the global layout of the site. Here's the path to the default GlobalLayout.vue file provided by VuePress (opens new window) node_modules/@vuepress/core/lib/client/components. You can also view the code for the default global layout here (opens new window).

The default global layout gives you the ability to render different layouts depending on if $page.path is defined, i.e., the URL of the page is valid and if $page.frontmatter.layout is defined. If only the $page.path is defined, then the default layout will be used which is Layout. If $page.frontmatter.layout is defined, then the specific layout for that page will be used. If $page.path is not defined, then the NotFound layout is used which is the layout for the 404 page provided by VuePress (opens new window). In most scenarios you don't need to edit the default global layout, but if you want to add a global header or a global footer to your site, then this is a good place to add it.

To override and edit the GlobalLayout.vue file we're going to use the code provided by the globalLayout (opens new window) section from the documentation. The code provided by the documentation basically uses a computed property (opens new window) to determine the layout for a page based on if the URL of the page is defined and if the page uses a specific layout provided by the frontmatter. This is similar to the logic previously described when discussing the default global layout.

Here's the code from the documentation:

We're going to remove the example header tag and replace the example footer tag with our previously created footer component.

Here's what the GlobalLayout.vue file should look like after the changes:

Importing the Footer Component

Notice that we don't need to explicitly import the footer component since we made it a global component by adding it to the global-components directory in the theme directory.

# Next Steps

In the next tutorial we'll discuss how to override the index.styl and palette.styl files to add our own global styling to the site. The global styling will include background color, accent color, text color, etc.

Made by & for Code Monkeys 🐵