# VuePress Tutorial 8 - Custom Footer
# What is a Footer?
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.
# Homepage Layout Footer
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
If you do decide to add a footer using the frontmatter in the homepage, then the HTML will look like this:
# Rich-text Footer
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.
# VuePress Blog Theme Footer
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.
# Custom Footer
Before designing the custom footer component, we need to have an understanding of the following topics:
- Writing a Theme (opens new window)
- Plugins (opens new window)
- vuepress-plugin-svg-icons (opens new window)
- Theme Inheritance (opens new window)
- globalLayout (opens new window)
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:
.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:
.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:
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
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
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
# 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 @email@example.com.
After installing the plugin, the
package.json file should look something like this:
Next we need to configure the plugin by editing the
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│ └── 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:
- GitHub (opens new window)
- YouTube (opens new window)
- Discord (opens new window)
- Telegram (opens new window)
- Twitter (opens new window)
- LinkedIn (opens new window)
- Patreon (opens new window)
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.
# 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
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
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.
a tag will have the following attributes:
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
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
As mentioned in the previous post these values for the
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.
name attribute has a value of the name of the related SVG file with the
.svg extension omitted.
script tag and give the component a name. Here's what the
Footer.vue file looks like after updating the
Finally, we'll style the component by adding the following CSS classes:
"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:
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).
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
"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).
"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
If you're unfamiliar with CSS selectors, then check out the CSS Selector Reference (opens new window).
"made-by" class is given
margin: 0 which removes the margin from the
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
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
First, we need to create the
index.js file in the
theme directory which should now look like this:
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│ │ └── GlobalLayout.vue │ └── index.js
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
$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
# Next Steps
In the next tutorial we'll discuss how to override the
palette.styl files to add our own global styling to the site. The global styling will include background color, accent color, text color, etc.