<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ eleventy - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ eleventy - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 15 May 2026 09:49:03 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/eleventy/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Learn the Eleventy Static Site Generator by Building and Deploying a Portfolio Website ]]>
                </title>
                <description>
                    <![CDATA[ What is Eleventy? Eleventy (also called 11ty) is a simple yet powerful static site generator. It uses JavaScript to transform data and templates into HTML pages. It’s beginner-friendly, has fast build times, and generates fast sites by default. It al... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-eleventy/</link>
                <guid isPermaLink="false">66d45ee1787a2a3b05af43aa</guid>
                
                    <category>
                        <![CDATA[ eleventy ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Static Site Generators ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gerard Hynes ]]>
                </dc:creator>
                <pubDate>Tue, 06 Sep 2022 16:26:13 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/09/learn-eleventy.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <h2 id="heading-what-is-eleventy">What is Eleventy?</h2>
<p>Eleventy (also called 11ty) is a simple yet powerful static site generator. It uses JavaScript to transform data and templates into HTML pages.</p>
<p>It’s beginner-friendly, has fast build times, and generates fast sites by default. It also has a very active and friendly community.</p>
<p>Eleventy excels at content-driven sites and is used by <a target="_blank" href="https://web.dev/">Google</a>, <a target="_blank" href="https://www.netlify.com/">Netlify</a>, <a target="_blank" href="https://digitalhumanities.mit.edu/">MIT</a>, <a target="_blank" href="https://worldwideweb.cern.ch/">CERN</a>, <a target="_blank" href="https://www.a11yproject.com/">the A11y Project</a>, <a target="_blank" href="https://eslint.org/">ESLint,</a> and more.</p>
<p>Since pages are generated ahead of time, they can be served as fast as possible from a Content Delivery Network (CDN). Eleventy also generates no client-side JavaScript, which helps your site to load faster.</p>
<p>In this tutorial, we're going to build a simple developer portfolio site to demonstrate some of the main features of Eleventy.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-29-at-17-46-26-Eleventy-Portfolio.png" alt="Eleventy portfolio homepage" width="600" height="400" loading="lazy"></p>
<p><em>Eleventy portfolio homepage</em></p>
<p>We’ll learn about:</p>
<ol>
<li><p>Setting up and configuring an Eleventy project</p>
</li>
<li><p>Templating and layouts</p>
</li>
<li><p>Handling CSS and images</p>
</li>
<li><p>Working with collections and data files</p>
</li>
<li><p>Shortcodes and Eleventy plugins</p>
</li>
<li><p>Deploying the site to Netlify</p>
</li>
</ol>
<p>The portfolio site will have:</p>
<ul>
<li><p>A Homepage</p>
</li>
<li><p>An About page</p>
</li>
<li><p>A Contact page (with contact form)</p>
</li>
<li><p>A Projects page</p>
</li>
<li><p>A page for each project (with case study)</p>
</li>
</ul>
<p>Eleventy can pull in data from APIs, a Content Management System (CMS), or from local files. To keep things simple, we’ll store our project data in Markdown files.</p>
<p>The full code for the finished portfolio is <a target="_blank" href="https://github.com/gerhynes/eleventy-portfolio">available on GitHub</a>. If you get stuck at any stage, please check your code against the finished site.</p>
<h2 id="heading-table-of-contents">Table of Contents:</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-prerequisite-install-nodejs">Prerequisite - Install Node.js</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-initial-project-setup">Initial Project Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-configure-the-project">How to Configure the Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-add-a-template">How to Add a Template</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-templates-in-eleventy">How to Use Templates in Eleventy</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-layouts-in-eleventy">How to Use Layouts in Eleventy</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-configure-the-css-and-images">How to Configure the CSS and Images</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-partials-in-eleventy">How to Use Partials in Eleventy</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-collections-in-eleventy">How to Use Collections in Eleventy</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-directory-data-files">How to Use Directory Data Files</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-collections-in-templates">How to Use Collections in Templates</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-shortcodes">How to Use Shortcodes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-the-eleventy-image-plugin">How to Use the Eleventy Image Plugin</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-a-build-contact-form-with-netlify-forms">How to Build a Contact Form with Netlify Forms</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-deploy-to-netlify">How to Deploy to Netlify</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-where-to-take-it-from-here">Where to Take it from Here</a></p>
</li>
</ol>
<h3 id="heading-prerequisite-install-nodejs">Prerequisite - Install Node.js</h3>
<p>If you don’t already have Node.js installed, go to <a target="_blank" href="https://nodejs.org/en/">nodejs.org</a> and follow the instructions for your operating system.</p>
<p>Open a terminal and use <code>node --version</code> to make sure it’s installed. As long as it’s version 12 or newer, you’re good to go.</p>
<h2 id="heading-initial-project-setup">Initial Project Setup</h2>
<p>First, create a directory for your portfolio. You can call it <code>eleventy-portfolio</code> or whatever you want.</p>
<p>Open this directory in a terminal and run <code>npm init -y</code> to create a <code>package.json</code> file with the default settings.</p>
<p>Next, install Eleventy using <code>npm install --save-dev @11ty/eleventy</code>.</p>
<p>In the root directory of the project, create a <code>.gitignore</code> file with the following contents so that Git doesn’t track any unwanted files:</p>
<pre><code class="lang-python">node_modules
/public
</code></pre>
<h2 id="heading-how-to-configure-the-project">How to Configure the Project</h2>
<p>Eleventy is “zero-config” by default. If you don’t change anything, Eleventy will take all the files in your root directory, run a build process, and output the resulting files to a <code>_site</code> directory.</p>
<p>But Eleventy also has flexible configuration options that let you customize your build process, watch for changes in certain file types, and manipulate content with filters and shortcodes.</p>
<p>Your Eleventy configuration goes in a <code>.eleventy.js</code> file in the root of your project.</p>
<p>For example, the default input directory is the root directory of your project, while the default output directory is <code>_site</code>. Some people prefer to change this, with <code>src</code> and <code>public</code> being common choices.</p>
<p>If you’d like this structure, create <code>src</code> and <code>public</code> directories in the root of your project and then set them as the input and output directories in <code>.eleventy.js</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">eleventyConfig</span>) </span>{
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">dir</span>: {
      <span class="hljs-attr">input</span>: <span class="hljs-string">"src"</span>,
      <span class="hljs-attr">output</span>: <span class="hljs-string">"public"</span>
    }
  };
};
</code></pre>
<p>In case you’re wondering, the <code>eleventyConfig</code> argument that is passed to the function is the default configuration object that Eleventy provides. Soon we’ll use this object to customize our Eleventy build process.</p>
<h2 id="heading-how-to-add-a-template">How to Add a Template</h2>
<p>Let’s add our first template. We’ll keep things as simple as possible by using a Markdown file.</p>
<p>In the <code>src</code> directory, create an <code>index.md</code> with <code># Hello World from Eleventy</code> as its contents. This is your first Eleventy template.</p>
<p>To build and view the site we can use the development server that comes with Eleventy.</p>
<p>In your terminal, make sure you’re in the root directory of your project and run <code>eleventy --serve</code>. This starts the development server, which will watch your <code>src</code> directory and automatically reload your site whenever you change your code.</p>
<p>After a moment you’ll see:</p>
<pre><code class="lang-python">[Browsersync] Access URLs:
 ----------------------------------
    Local: http://localhost:<span class="hljs-number">8080</span>
 External: http://your_ip_address:<span class="hljs-number">8080</span>
 ----------------------------------
[Browsersync] Serving files <span class="hljs-keyword">from</span>: public
</code></pre>
<p>Open a web browser and go to <a target="_blank" href="http://localhost:8080"><code>http://localhost:8080</code></a>. Congratulations, you’ve made a (very simple) Eleventy site! 🥳🎉</p>
<p>At this stage, your project will have the following structure:</p>
<pre><code class="lang-python">node_modules/
public/
src/
.eleventy.js
.gitignore
package.lock.json
package.json
</code></pre>
<p>Most sites need more than one page, so we’re going to need to learn more about <strong>templates</strong>.</p>
<p>Before we do that, we can customize our build commands if we want to. This step is entirely optional.</p>
<h3 id="heading-optional-step-how-to-create-custom-build-commands">Optional Step – How to Create Custom Build Commands</h3>
<p>The default command to run the development server is <code>eleventy --serve</code>, while the default command to build the site is <code>eleventy</code>.</p>
<p>If you’d like to replace these with different commands, such as <code>start</code> and <code>build</code>, open <code>package.json</code> and under <code>scripts</code> replace the “test” command with your preferred commands:</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"eleventy --serve"</span>,
    <span class="hljs-attr">"build"</span>: <span class="hljs-string">"eleventy"</span>
  },
</code></pre>
<p>Now we can use <code>npm start</code> in the terminal to start the development server and <code>npm run build</code> to generate a build of our site.</p>
<p>You can use <code>ctrl/cmd</code> + <code>c</code> to stop the development server whenever you need to.</p>
<h2 id="heading-how-to-use-templates-in-eleventy">How to Use Templates in Eleventy</h2>
<p>Turning Markdown files into HTML is neat, but so far you aren’t really getting much benefit over just writing your site in plain HTML. This is where <strong>templates</strong> come in.</p>
<p>First, we need to clarify some terms:</p>
<ul>
<li><p><strong>Template –</strong> A content file that Eleventy will transform into a page, or pages, in the built site</p>
</li>
<li><p><strong>Layout –</strong> A template that wraps around another template, usually to provide a structure to present content in</p>
</li>
<li><p><strong>Partial –</strong> A template that makes up part of another template</p>
</li>
</ul>
<p>Templates let you combine content and data to generate whatever HTML your site needs.</p>
<p>Layouts let you give multiple templates the same basic structure.</p>
<p>Partials let you build small reusable components that you can use in larger templates.</p>
<p>Eleventy supports ten different languages for templating, including: HTML, Markdown, JavaScript, Liquid, Nunjucks, Handlebars, Mustache, EJS, Haml, and Pug. (In version 1.0 Eleventy added support for custom templates using any arbitrary file extension, but this is probably better reserved for more custom/advanced use cases).</p>
<p>You can even mix different templating languages in the same file, such as Markdown and Nunjucks, if you want to.</p>
<p>In this project, we’ll use <a target="_blank" href="https://mozilla.github.io/nunjucks/">Nunjucks</a>. It’s a templating language for JavaScript created by Mozilla, and is pretty popular in the Eleventy community.</p>
<p>In the <code>src</code> directory, delete <code>index.md</code> and create an <code>index.njk</code> file. If you’re using VS Code, type <code>!</code> + <code>tab</code> to generate the basic HTML structure for the page. Change the title to "Eleventy Portfolio" and in the <code>&lt;body&gt;</code> element, add <code>&lt;h1&gt;Home Page&lt;/h1&gt;</code>.</p>
<p>Your page should look like this:</p>
<pre><code class="lang-python">&lt;!DOCTYPE html&gt;
&lt;html lang=<span class="hljs-string">"en"</span>&gt;
&lt;head&gt;
  &lt;meta charset=<span class="hljs-string">"UTF-8"</span>&gt;
  &lt;meta http-equiv=<span class="hljs-string">"X-UA-Compatible"</span> content=<span class="hljs-string">"IE=edge"</span>&gt;
  &lt;meta name=<span class="hljs-string">"viewport"</span> content=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;
  &lt;title&gt;Eleventy Portfolio&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;Home Page&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>Next, still in <code>src</code>, create <code>about.njk</code> and <code>contact.njk</code> files. You can copy the contents of <code>index.njk</code> into them and replace the <code>&lt;h1&gt;</code> with <code>&lt;h1&gt;About Page&lt;/h1&gt;</code> and <code>&lt;h1&gt;Contact Page&lt;/h1&gt;</code> respectively.</p>
<p>Start your dev server. if it isn’t already running. Go to <a target="_blank" href="http://localhost:8080"><code>http://localhost:8080</code></a> to see the homepage, <code>http://localhost:8080/about</code> for the About page, and <code>http://localhost:8080/contact</code> for the Contact page.</p>
<p>In our portfolio site, each of these pages is going to have the same basic layout. So instead of writing the same code in each page template, we’re going to use Eleventy <strong>layouts</strong>.</p>
<h2 id="heading-how-to-use-layouts-in-eleventy">How to Use Layouts in Eleventy</h2>
<p>Layouts are templates that wrap around other templates, presenting the content in a consistent way.</p>
<p>Inside the <code>src</code> directory, create a <code>_includes</code> directory. This is going to contain all our layouts and partials.</p>
<p>Inside <code>_includes</code>, create a <code>base.njk</code> file. This will provide a standard layout for every page of our site.</p>
<p>Copy the following code into <code>base.njk</code>:</p>
<pre><code class="lang-python">&lt;!DOCTYPE html&gt;
&lt;html lang=<span class="hljs-string">"en"</span>&gt;
&lt;head&gt;
  &lt;meta charset=<span class="hljs-string">"UTF-8"</span>&gt;
  &lt;meta http-equiv=<span class="hljs-string">"X-UA-Compatible"</span> content=<span class="hljs-string">"IE=edge"</span>&gt;
  &lt;meta name=<span class="hljs-string">"viewport"</span> content=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;
  &lt;meta name=<span class="hljs-string">"description"</span> content=<span class="hljs-string">"I'm a Frontend software developer who builds sites and apps that help people reach their personal and professional goals."</span>/&gt;
  &lt;title&gt;{{ title }}&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">content</span>"&gt;
    &lt;<span class="hljs-title">header</span> <span class="hljs-title">class</span>="<span class="hljs-title">header</span> <span class="hljs-title">container</span>"&gt;
    &lt;<span class="hljs-title">h1</span> <span class="hljs-title">class</span>="<span class="hljs-title">header__title</span>"&gt;
      &lt;<span class="hljs-title">a</span> <span class="hljs-title">href</span>="/"&gt;<span class="hljs-title">Marie</span> <span class="hljs-title">Jackson</span>&lt;/<span class="hljs-title">a</span>&gt;
    &lt;/<span class="hljs-title">h1</span>&gt;
    &lt;<span class="hljs-title">ul</span> <span class="hljs-title">class</span>="<span class="hljs-title">header__links</span>"&gt;
      &lt;<span class="hljs-title">li</span>&gt;
        &lt;<span class="hljs-title">a</span> <span class="hljs-title">class</span>="<span class="hljs-title">header__link</span>" <span class="hljs-title">href</span>="/<span class="hljs-title">about</span>"&gt;<span class="hljs-title">About</span>&lt;/<span class="hljs-title">a</span>&gt;
      &lt;/<span class="hljs-title">li</span>&gt;
      &lt;<span class="hljs-title">li</span>&gt;
        &lt;<span class="hljs-title">a</span> <span class="hljs-title">class</span>="<span class="hljs-title">header__link</span>" <span class="hljs-title">href</span>="/<span class="hljs-title">projects</span>"&gt;<span class="hljs-title">Projects</span>&lt;/<span class="hljs-title">a</span>&gt;
      &lt;/<span class="hljs-title">li</span>&gt;
      &lt;<span class="hljs-title">li</span>&gt;
        &lt;<span class="hljs-title">a</span> <span class="hljs-title">class</span>="<span class="hljs-title">header__link</span>" <span class="hljs-title">href</span>="/<span class="hljs-title">contact</span>"&gt;<span class="hljs-title">Contact</span>&lt;/<span class="hljs-title">a</span>&gt;
      &lt;/<span class="hljs-title">li</span>&gt;
    &lt;/<span class="hljs-title">ul</span>&gt;
    &lt;/<span class="hljs-title">header</span>&gt;
    &lt;<span class="hljs-title">main</span> <span class="hljs-title">class</span>="<span class="hljs-title">main</span> <span class="hljs-title">container</span>"&gt;
      {{ <span class="hljs-title">content</span> | <span class="hljs-title">safe</span> }}
    &lt;/<span class="hljs-title">main</span>&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
  &lt;<span class="hljs-title">footer</span> <span class="hljs-title">class</span>="<span class="hljs-title">footer</span>"&gt;
      &lt;<span class="hljs-title">p</span>&gt;&amp;<span class="hljs-title">copy</span>; <span class="hljs-title">Marie</span> <span class="hljs-title">Jackson</span> 2022&lt;/<span class="hljs-title">p</span>&gt;
  &lt;/<span class="hljs-title">footer</span>&gt;
&lt;/<span class="hljs-title">body</span>&gt;
&lt;/<span class="hljs-title">html</span>&gt;</span>
</code></pre>
<p>The <code>content</code> value will be the main content of whichever template we use with <code>base.njk</code> as its layout. <code>safe</code> is a filter that prevents this content from being escaped (having potentially unsafe characters replaced).</p>
<p>Now, change <code>index.njk</code> to be:</p>
<pre><code class="lang-python">---
title: <span class="hljs-string">"Eleventy Portfolio"</span>
layout: <span class="hljs-string">"base.njk"</span>
---

&lt;h1&gt;{{ title }} Home Page&lt;/h1&gt;
</code></pre>
<p>Notice how the template has frontmatter data at the top of the file. By default this is written in YAML, but you can use other languages too.</p>
<p>This frontmatter lets you set values for your templates. In this case, the <code>layout</code> value tells the template to use the <code>base.njk</code> layout and the <code>title</code> value provides a title that we are using in our template's <code>&lt;h1&gt;</code> tag.</p>
<p>Next, delete everything from <code>about.njk</code> and paste in the following content:</p>
<pre><code class="lang-python">---
title: <span class="hljs-string">"Eleventy Portfolio"</span>
layout: <span class="hljs-string">"base.njk"</span>
---

&lt;section <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">bio</span> <span class="hljs-title">prose</span>"&gt;
  &lt;<span class="hljs-title">h2</span> <span class="hljs-title">class</span>="<span class="hljs-title">heading</span>--<span class="hljs-title">main</span>"&gt;<span class="hljs-title">My</span> <span class="hljs-title">story</span>&lt;/<span class="hljs-title">h2</span>&gt;
  &lt;<span class="hljs-title">p</span>&gt;<span class="hljs-title">Lorem</span> <span class="hljs-title">ipsum</span> <span class="hljs-title">dolor</span> <span class="hljs-title">sit</span> <span class="hljs-title">amet</span>, <span class="hljs-title">consectetur</span> <span class="hljs-title">adipiscing</span> <span class="hljs-title">elit</span>, <span class="hljs-title">sed</span> <span class="hljs-title">do</span> <span class="hljs-title">eiusmod</span> <span class="hljs-title">tempor</span> <span class="hljs-title">incididunt</span> <span class="hljs-title">ut</span> <span class="hljs-title">labore</span> <span class="hljs-title">et</span> <span class="hljs-title">dolore</span> <span class="hljs-title">magna</span> <span class="hljs-title">aliqua</span>. <span class="hljs-title">Aliquet</span> <span class="hljs-title">risus</span> <span class="hljs-title">feugiat</span> <span class="hljs-title">in</span> <span class="hljs-title">ante</span> <span class="hljs-title">metus</span> <span class="hljs-title">dictum</span>.&lt;/<span class="hljs-title">p</span>&gt;

  &lt;<span class="hljs-title">p</span>&gt;<span class="hljs-title">Tellus</span> <span class="hljs-title">pellentesque</span> <span class="hljs-title">eu</span> <span class="hljs-title">tincidunt</span> <span class="hljs-title">tortor</span> <span class="hljs-title">aliquam</span> <span class="hljs-title">nulla</span> <span class="hljs-title">facilisi</span> <span class="hljs-title">cras</span> <span class="hljs-title">fermentum</span>. <span class="hljs-title">Turpis</span> <span class="hljs-title">egestas</span> <span class="hljs-title">integer</span> <span class="hljs-title">eget</span> <span class="hljs-title">aliquet</span>. <span class="hljs-title">Vestibulum</span> <span class="hljs-title">morbi</span> <span class="hljs-title">blandit</span> <span class="hljs-title">cursus</span> <span class="hljs-title">risus</span> <span class="hljs-title">at</span> <span class="hljs-title">ultrices</span> <span class="hljs-title">mi</span> <span class="hljs-title">tempus</span>. <span class="hljs-title">Ut</span> <span class="hljs-title">lectus</span> <span class="hljs-title">arcu</span> <span class="hljs-title">bibendum</span> <span class="hljs-title">at</span>. <span class="hljs-title">Integer</span> <span class="hljs-title">enim</span> <span class="hljs-title">neque</span> <span class="hljs-title">volutpat</span> <span class="hljs-title">ac</span> <span class="hljs-title">tincidunt</span>.&lt;/<span class="hljs-title">p</span>&gt;

  &lt;<span class="hljs-title">p</span>&gt;<span class="hljs-title">Commodo</span> <span class="hljs-title">ullamcorper</span> <span class="hljs-title">a</span> <span class="hljs-title">lacus</span> <span class="hljs-title">vestibulum</span> <span class="hljs-title">sed</span> <span class="hljs-title">arcu</span>. <span class="hljs-title">Et</span> <span class="hljs-title">tortor</span> <span class="hljs-title">consequat</span> <span class="hljs-title">id</span> <span class="hljs-title">porta</span> <span class="hljs-title">nibh</span> <span class="hljs-title">venenatis</span> <span class="hljs-title">cras</span> <span class="hljs-title">sed</span>. <span class="hljs-title">Nulla</span> <span class="hljs-title">pharetra</span> <span class="hljs-title">diam</span> <span class="hljs-title">sit</span> <span class="hljs-title">amet</span> <span class="hljs-title">nisl</span>. <span class="hljs-title">Ipsum</span> <span class="hljs-title">nunc</span> <span class="hljs-title">aliquet</span> <span class="hljs-title">bibendum</span> <span class="hljs-title">enim</span> <span class="hljs-title">facilisis</span> <span class="hljs-title">gravida</span> <span class="hljs-title">neque</span> <span class="hljs-title">convallis</span> <span class="hljs-title">a</span>. <span class="hljs-title">Nec</span> <span class="hljs-title">sagittis</span> <span class="hljs-title">aliquam</span> <span class="hljs-title">malesuada</span> <span class="hljs-title">bibendum</span>.&lt;/<span class="hljs-title">p</span>&gt;

  &lt;<span class="hljs-title">p</span>&gt;<span class="hljs-title">Tellus</span> <span class="hljs-title">pellentesque</span> <span class="hljs-title">eu</span> <span class="hljs-title">tincidunt</span> <span class="hljs-title">tortor</span> <span class="hljs-title">aliquam</span> <span class="hljs-title">nulla</span> <span class="hljs-title">facilisi</span> <span class="hljs-title">cras</span> <span class="hljs-title">fermentum</span>. <span class="hljs-title">Turpis</span> <span class="hljs-title">egestas</span> <span class="hljs-title">integer</span> <span class="hljs-title">eget</span> <span class="hljs-title">aliquet</span>. <span class="hljs-title">Vestibulum</span> <span class="hljs-title">morbi</span> <span class="hljs-title">blandit</span> <span class="hljs-title">cursus</span> <span class="hljs-title">risus</span> <span class="hljs-title">at</span> <span class="hljs-title">ultrices</span> <span class="hljs-title">mi</span> <span class="hljs-title">tempus</span>. <span class="hljs-title">Ut</span> <span class="hljs-title">lectus</span> <span class="hljs-title">arcu</span> <span class="hljs-title">bibendum</span> <span class="hljs-title">at</span>. <span class="hljs-title">Integer</span> <span class="hljs-title">enim</span> <span class="hljs-title">neque</span> <span class="hljs-title">volutpat</span> <span class="hljs-title">ac</span> <span class="hljs-title">tincidunt</span>.&lt;/<span class="hljs-title">p</span>&gt;

  &lt;<span class="hljs-title">p</span>&gt;<span class="hljs-title">Commodo</span> <span class="hljs-title">ullamcorper</span> <span class="hljs-title">a</span> <span class="hljs-title">lacus</span> <span class="hljs-title">vestibulum</span> <span class="hljs-title">sed</span> <span class="hljs-title">arcu</span>. <span class="hljs-title">Et</span> <span class="hljs-title">tortor</span> <span class="hljs-title">consequat</span> <span class="hljs-title">id</span> <span class="hljs-title">porta</span> <span class="hljs-title">nibh</span> <span class="hljs-title">venenatis</span> <span class="hljs-title">cras</span> <span class="hljs-title">sed</span>. <span class="hljs-title">Nulla</span> <span class="hljs-title">pharetra</span> <span class="hljs-title">diam</span> <span class="hljs-title">sit</span> <span class="hljs-title">amet</span> <span class="hljs-title">nisl</span>. <span class="hljs-title">Ipsum</span> <span class="hljs-title">nunc</span> <span class="hljs-title">aliquet</span> <span class="hljs-title">bibendum</span> <span class="hljs-title">enim</span> <span class="hljs-title">facilisis</span> <span class="hljs-title">gravida</span> <span class="hljs-title">neque</span> <span class="hljs-title">convallis</span> <span class="hljs-title">a</span>. <span class="hljs-title">Nec</span> <span class="hljs-title">sagittis</span> <span class="hljs-title">aliquam</span> <span class="hljs-title">malesuada</span> <span class="hljs-title">bibendum</span>.&lt;/<span class="hljs-title">p</span>&gt;
&lt;/<span class="hljs-title">section</span>&gt;</span>
</code></pre>
<p>Now delete everything from <code>contact.njk</code> and paste in this content:</p>
<pre><code class="lang-python">---
title: <span class="hljs-string">"Eleventy Portfolio"</span>
layout: <span class="hljs-string">"base.njk"</span>
---

&lt;h2 <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">heading</span>--<span class="hljs-title">main</span> <span class="hljs-title">text</span>-<span class="hljs-title">center</span>"&gt;<span class="hljs-title">Want</span> <span class="hljs-title">to</span> <span class="hljs-title">get</span> <span class="hljs-title">in</span> <span class="hljs-title">touch</span>?&lt;/<span class="hljs-title">h2</span>&gt;
&lt;<span class="hljs-title">p</span> <span class="hljs-title">class</span>="<span class="hljs-title">contact__sub</span>-<span class="hljs-title">heading</span> <span class="hljs-title">text</span>-<span class="hljs-title">center</span>"&gt;<span class="hljs-title">I</span>'<span class="hljs-title">m</span> <span class="hljs-title">always</span> <span class="hljs-title">open</span> <span class="hljs-title">to</span> <span class="hljs-title">new</span> <span class="hljs-title">opportunities</span> <span class="hljs-title">and</span> <span class="hljs-title">projects</span>. &lt;/<span class="hljs-title">p</span>&gt;

&lt;<span class="hljs-title">form</span> <span class="hljs-title">class</span>="<span class="hljs-title">form</span>" <span class="hljs-title">name</span>="<span class="hljs-title">contact</span>" <span class="hljs-title">action</span>="/<span class="hljs-title">success</span>" <span class="hljs-title">method</span>="<span class="hljs-title">POST</span>" <span class="hljs-title">data</span>-<span class="hljs-title">netlify</span>="<span class="hljs-title">true</span>"&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__section</span>"&gt;
    &lt;<span class="hljs-title">label</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__label</span>" <span class="hljs-title">for</span>="<span class="hljs-title">yourName</span>"&gt;<span class="hljs-title">Name</span>&lt;/<span class="hljs-title">label</span>&gt;
    &lt;<span class="hljs-title">input</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__input</span>" <span class="hljs-title">name</span>="<span class="hljs-title">name</span>" <span class="hljs-title">type</span>="<span class="hljs-title">text</span>" <span class="hljs-title">id</span>="<span class="hljs-title">yourName</span>" <span class="hljs-title">required</span>="<span class="hljs-title">true</span>"&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__section</span>"&gt;
    &lt;<span class="hljs-title">label</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__label</span>" <span class="hljs-title">for</span>="<span class="hljs-title">yourEmail</span>"&gt;<span class="hljs-title">Email</span>&lt;/<span class="hljs-title">label</span>&gt;
    &lt;<span class="hljs-title">input</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__input</span>" <span class="hljs-title">name</span>="<span class="hljs-title">email</span>" <span class="hljs-title">type</span>="<span class="hljs-title">email</span>"  <span class="hljs-title">id</span>="<span class="hljs-title">yourEmail</span>" <span class="hljs-title">required</span>="<span class="hljs-title">true</span>"&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__section</span>"&gt;
    &lt;<span class="hljs-title">label</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__label</span>" <span class="hljs-title">for</span>="<span class="hljs-title">message</span>"&gt;<span class="hljs-title">Message</span>&lt;/<span class="hljs-title">label</span>&gt;
    &lt;<span class="hljs-title">textarea</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__input</span>" <span class="hljs-title">name</span>="<span class="hljs-title">message</span>" <span class="hljs-title">id</span>="<span class="hljs-title">message</span>" <span class="hljs-title">rows</span>="4" <span class="hljs-title">required</span>="<span class="hljs-title">true</span>"&gt;&lt;/<span class="hljs-title">textarea</span>&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
    &lt;<span class="hljs-title">button</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__button</span>" <span class="hljs-title">type</span>="<span class="hljs-title">submit</span>"&gt;<span class="hljs-title">Let</span>'<span class="hljs-title">s</span> <span class="hljs-title">talk</span>&lt;/<span class="hljs-title">button</span>&gt;
&lt;/<span class="hljs-title">form</span>&gt;</span>
</code></pre>
<p>We’re going to learn about how this contact form will work later in the tutorial.</p>
<p>Our portfolio is starting to take shape, even though things still look really bare. Let's get our CSS and images working next.</p>
<h2 id="heading-how-to-configure-the-css-and-images">How to Configure the CSS and Images</h2>
<p>While Eleventy can understand supported templating languages out of the box, it needs to be configured to process CSS and image files. Fortunately, this doesn’t require much configuration. While we’re at it, we’re also going to add a favicon to the site.</p>
<p>Inside the <code>src</code> directory, create three folders: <code>css</code>, <code>images</code>, and <code>favicons</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/src.PNG" alt="src directory structure" width="600" height="400" loading="lazy"></p>
<p><em>src directory structure</em></p>
<p>Inside the <code>css</code> directory, make a <code>style.css</code> file. Since this isn’t a CSS tutorial, I’m going to provide the CSS in <a target="_blank" href="https://github.com/gerhynes/eleventy-portfolio/tree/main/src">the GitHub repo for the project</a>. You can copy and paste it from there, but I’m not going to cover the CSS in any depth.</p>
<p>The images for this portfolio are also available in the <code>images</code> directory in the GitHub repo. Copy these images into the <code>images</code> directory of your project.</p>
<p>Finally, copy the files from the <code>favicons</code> directory in the GitHub repo into the <code>favicons</code> directory of your project.</p>
<p>In <code>base.njk</code> add these lines to the <code>&lt;head&gt;</code> element:</p>
<pre><code class="lang-python">&lt;link rel=<span class="hljs-string">"icon"</span> href=<span class="hljs-string">"/favicon.ico"</span> sizes=<span class="hljs-string">"any"</span>&gt;
&lt;link rel=<span class="hljs-string">"apple-touch-icon"</span> href=<span class="hljs-string">"/apple-touch-icon.png"</span>&gt;
&lt;link rel=<span class="hljs-string">"preconnect"</span> href=<span class="hljs-string">"https://fonts.googleapis.com"</span>&gt;
&lt;link rel=<span class="hljs-string">"preconnect"</span> href=<span class="hljs-string">"https://fonts.gstatic.com"</span> crossorigin&gt;
&lt;link href=<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&amp;display=swap"</span> rel=<span class="hljs-string">"stylesheet"</span>&gt;
&lt;link rel=<span class="hljs-string">"stylesheet"</span> href=<span class="hljs-string">"{{'/css/style.css' | url | safe}}"</span>&gt;
</code></pre>
<p>The first two links include the favicon, the next three will fetch the Inter font from Google fonts, and the last one will connect <code>style.css</code> to <code>base.njk</code>.</p>
<p>Now, if we reload our homepage we’ll see that… absolutely nothing has changed.</p>
<p>By default, Eleventy will only process template files. To tell it to include CSS files and images, we need to add a few lines of configuration.</p>
<p>Add these lines to the configuration function in <code>.eleventy.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">eleventyConfig</span>) </span>{
  eleventyConfig.addPassthroughCopy(<span class="hljs-string">"./src/css/"</span>);
  eleventyConfig.addWatchTarget(<span class="hljs-string">"./src/css/"</span>);
  eleventyConfig.addPassthroughCopy(<span class="hljs-string">"./src/images/"</span>);
  eleventyConfig.addPassthroughCopy({ <span class="hljs-string">"./src/favicons"</span>: <span class="hljs-string">"/"</span> });

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">dir</span>: {
      <span class="hljs-attr">input</span>: <span class="hljs-string">"src"</span>,
      <span class="hljs-attr">output</span>: <span class="hljs-string">"public"</span>
    }
  };
};
</code></pre>
<p><code>addPassthroughCopy</code> tells Eleventy to pass the CSS, favicons, and image files through to the final build.</p>
<p><code>addWatchTarget</code> tells the Eleventy dev server to watch the <code>css</code> directory and reload the site if the files in this directory change.</p>
<p>With the favicons, we’re also telling Eleventy to output these files to the root of the generated content so that the links in <code>base.njk</code> will work.</p>
<p>Restart the server and you’ll see that the CSS is finally being applied and the favicon is showing up. We'll include the images shortly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-17-19-57-Eleventy-Portfolio.png" alt="Homepage with styles applied" width="600" height="400" loading="lazy"></p>
<p><em>Homepage with styles applied</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-18-16-28-Eleventy-Portfolio.png" alt="About page with styles applied." width="600" height="400" loading="lazy"></p>
<p><em>About page with styles applied</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-18-17-08-Eleventy-Portfolio.png" alt="Contact page with styles applied." width="600" height="400" loading="lazy"></p>
<p><em>Contact page with styles applied</em></p>
<p>The About page and Contact page are fairly self-contained. But the homepage for our site is going to have a couple of parts to it. It will consist of a header and footer, as well as a profile section, technologies section, and projects section. Each of these parts is going to use a <strong>partial</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/layout.png" alt="Layout of portfolio homepage." width="600" height="400" loading="lazy"></p>
<p><em>Layout of portfolio homepage</em></p>
<h2 id="heading-how-to-use-partials-in-eleventy">How to Use Partials in Eleventy</h2>
<p>Partials are templates that make up part of another template. Partials help us to think about our site in terms of reusable components that we can include whenever we need them.</p>
<p>In the <code>_includes</code> directory, create a <code>header.njk</code> and <code>footer.njk</code> file.</p>
<p>Cut the header element out of <code>base.njk</code> and paste it into <code>header.njk</code>.</p>
<p>Cut the footer element out of <code>base.njk</code> and paste it into <code>footer.njk</code>.</p>
<p>Back in <code>base.njk</code> add <code>{% include "header.njk" %}</code> where the header element used to be and <code>{% include "footer.njk" %}</code> where the footer element used to be.</p>
<p><code>base.njk</code> should now have this content inside its <code>&lt;body&gt;</code> tag:</p>
<pre><code class="lang-python">&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">content</span>"&gt;
    {% <span class="hljs-title">include</span> "<span class="hljs-title">header</span>.<span class="hljs-title">njk</span>" %}
    &lt;<span class="hljs-title">main</span> <span class="hljs-title">class</span>="<span class="hljs-title">main</span> <span class="hljs-title">container</span>"&gt;
      {{ <span class="hljs-title">content</span> | <span class="hljs-title">safe</span> }}
    &lt;/<span class="hljs-title">main</span>&gt;
&lt;/<span class="hljs-title">div</span>&gt;
{% <span class="hljs-title">include</span> "<span class="hljs-title">footer</span>.<span class="hljs-title">njk</span>" %}</span>
</code></pre>
<p>The site won’t look any different but our base layout is already becoming more modular.</p>
<p>Next, still in the <code>_includes</code> directory, create a <code>profile.njk</code> file with the following content:</p>
<pre><code class="lang-python">&lt;section <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">profile</span>"&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__image</span>-<span class="hljs-title">wrapper</span>"&gt;
    &lt;<span class="hljs-title">img</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__image</span>" <span class="hljs-title">src</span>="/<span class="hljs-title">images</span>/<span class="hljs-title">profile</span>.<span class="hljs-title">jpg</span>" <span class="hljs-title">alt</span>="<span class="hljs-title">Marie</span> <span class="hljs-title">Jackson</span>, <span class="hljs-title">Software</span> <span class="hljs-title">Developer</span>"&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__card</span>"&gt;
    &lt;<span class="hljs-title">p</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__text</span>"&gt;<span class="hljs-title">Hi</span>! <span class="hljs-title">I</span>'<span class="hljs-title">m</span> &lt;<span class="hljs-title">span</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__text</span>--<span class="hljs-title">highlight</span>"&gt;<span class="hljs-title">Marie</span>&lt;/<span class="hljs-title">span</span>&gt;, <span class="hljs-title">a</span> <span class="hljs-title">mathematician</span> <span class="hljs-title">turned</span> <span class="hljs-title">software</span> <span class="hljs-title">developer</span> <span class="hljs-title">from</span> <span class="hljs-title">Hampton</span>, <span class="hljs-title">Virginia</span>.&lt;/<span class="hljs-title">p</span>&gt;
    &lt;<span class="hljs-title">p</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__text</span>"&gt;<span class="hljs-title">As</span> <span class="hljs-title">a</span> &lt;<span class="hljs-title">span</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__text</span>--<span class="hljs-title">highlight</span>"&gt;<span class="hljs-title">Frontend</span> <span class="hljs-title">Developer</span>&lt;/<span class="hljs-title">span</span>&gt;, <span class="hljs-title">I</span> <span class="hljs-title">love</span> <span class="hljs-title">building</span> <span class="hljs-title">sites</span> <span class="hljs-title">and</span> <span class="hljs-title">apps</span> <span class="hljs-title">that</span> <span class="hljs-title">help</span> <span class="hljs-title">people</span> <span class="hljs-title">reach</span> <span class="hljs-title">their</span> <span class="hljs-title">personal</span> <span class="hljs-title">and</span> <span class="hljs-title">professional</span> <span class="hljs-title">goals</span>.&lt;/<span class="hljs-title">p</span>&gt;
    &lt;<span class="hljs-title">p</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__text</span>"&gt;<span class="hljs-title">I</span> <span class="hljs-title">focus</span> <span class="hljs-title">on</span> <span class="hljs-title">speed</span>, <span class="hljs-title">security</span> <span class="hljs-title">and</span> <span class="hljs-title">scalability</span>, <span class="hljs-title">using</span> <span class="hljs-title">React</span>.<span class="hljs-title">js</span> <span class="hljs-title">and</span> <span class="hljs-title">Firebase</span> <span class="hljs-title">to</span> <span class="hljs-title">create</span> <span class="hljs-title">rich</span>, <span class="hljs-title">dynamic</span> <span class="hljs-title">experiences</span>.&lt;/<span class="hljs-title">p</span>&gt;
    &lt;<span class="hljs-title">p</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__text</span>"&gt;<span class="hljs-title">I</span>'<span class="hljs-title">m</span> <span class="hljs-title">always</span> <span class="hljs-title">open</span> <span class="hljs-title">to</span> <span class="hljs-title">new</span> <span class="hljs-title">opportunities</span> <span class="hljs-title">and</span> <span class="hljs-title">projects</span>. <span class="hljs-title">So</span> <span class="hljs-title">don</span>'<span class="hljs-title">t</span> <span class="hljs-title">hesitate</span> <span class="hljs-title">to</span> &lt;<span class="hljs-title">a</span> <span class="hljs-title">class</span>="<span class="hljs-title">profile__link</span>" <span class="hljs-title">href</span>="/<span class="hljs-title">contact</span>"&gt;<span class="hljs-title">get</span> <span class="hljs-title">in</span> <span class="hljs-title">touch</span>&lt;/<span class="hljs-title">a</span>&gt;.&lt;<span class="hljs-title">p</span>&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
&lt;/<span class="hljs-title">section</span>&gt;</span>
</code></pre>
<p>Next, create a <code>technologies.njk</code> file with this content:</p>
<pre><code class="lang-python">&lt;section <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">technologies</span>"&gt;
  &lt;<span class="hljs-title">h2</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__heading</span>"&gt;<span class="hljs-title">Technologies</span> <span class="hljs-title">I</span> <span class="hljs-title">love</span> <span class="hljs-title">to</span> <span class="hljs-title">work</span> <span class="hljs-title">with</span>&lt;/<span class="hljs-title">h2</span>&gt;
  &lt;<span class="hljs-title">ul</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__list</span>"&gt;
    &lt;<span class="hljs-title">li</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__item</span>"&gt;
      &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__logo</span>"&gt;
      &lt;<span class="hljs-title">img</span> <span class="hljs-title">src</span>="/<span class="hljs-title">images</span>/<span class="hljs-title">javascript</span>.<span class="hljs-title">svg</span>" <span class="hljs-title">alt</span>="<span class="hljs-title">JavaScript</span> <span class="hljs-title">logo</span>"&gt;
      &lt;/<span class="hljs-title">div</span>&gt;
      &lt;<span class="hljs-title">h3</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__title</span>"&gt;<span class="hljs-title">JavaScript</span>&lt;/<span class="hljs-title">h3</span>&gt;
    &lt;/<span class="hljs-title">li</span>&gt;
    &lt;<span class="hljs-title">li</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__item</span>"&gt;
      &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__logo</span>"&gt;
      &lt;<span class="hljs-title">img</span> <span class="hljs-title">src</span>="/<span class="hljs-title">images</span>/<span class="hljs-title">react</span>.<span class="hljs-title">svg</span>" <span class="hljs-title">alt</span>="<span class="hljs-title">React</span>.<span class="hljs-title">js</span> <span class="hljs-title">logo</span>"&gt;
      &lt;/<span class="hljs-title">div</span>&gt;
      &lt;<span class="hljs-title">h3</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__title</span>"&gt;<span class="hljs-title">React</span>.<span class="hljs-title">js</span>&lt;/<span class="hljs-title">h3</span>&gt;
    &lt;/<span class="hljs-title">li</span>&gt;
    &lt;<span class="hljs-title">li</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__item</span>"&gt;
      &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__logo</span>"&gt;
        &lt;<span class="hljs-title">img</span> <span class="hljs-title">src</span>="/<span class="hljs-title">images</span>/<span class="hljs-title">tailwindcss</span>.<span class="hljs-title">svg</span>" <span class="hljs-title">alt</span>="<span class="hljs-title">Tailwind</span> <span class="hljs-title">CSS</span> <span class="hljs-title">logo</span>"&gt;
      &lt;/<span class="hljs-title">div</span>&gt;
      &lt;<span class="hljs-title">h3</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__title</span>"&gt;<span class="hljs-title">Tailwind</span> <span class="hljs-title">CSS</span>&lt;/<span class="hljs-title">h3</span>&gt;
    &lt;/<span class="hljs-title">li</span>&gt;
    &lt;<span class="hljs-title">li</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__item</span>"&gt;
      &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__logo</span>"&gt;
        &lt;<span class="hljs-title">img</span> <span class="hljs-title">src</span>="/<span class="hljs-title">images</span>/<span class="hljs-title">firebase</span>.<span class="hljs-title">svg</span>" <span class="hljs-title">alt</span>="<span class="hljs-title">Firebase</span> <span class="hljs-title">logo</span>"&gt;
      &lt;/<span class="hljs-title">div</span>&gt;
      &lt;<span class="hljs-title">h3</span> <span class="hljs-title">class</span>="<span class="hljs-title">technologies__title</span>"&gt;<span class="hljs-title">Firebase</span>&lt;/<span class="hljs-title">h3</span>&gt;
    &lt;/<span class="hljs-title">li</span>&gt;
  &lt;/<span class="hljs-title">ul</span>&gt;
&lt;/<span class="hljs-title">section</span>&gt;</span>
</code></pre>
<p>In <code>index.njk</code> replace the <code>&lt;h1&gt;</code> tag with:</p>
<pre><code class="lang-python">{% include <span class="hljs-string">"profile.njk"</span> %}
{% include <span class="hljs-string">"technologies.njk"</span> %}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-18-15-11-Eleventy-Portfolio.png" alt="Portfolio homepage with profile and technologies sections." width="600" height="400" loading="lazy"></p>
<p><em>Portfolio homepage with profile and technologies sections</em></p>
<p>Our homepage is starting to take shape but the site still needs the most important part of any portfolio: projects.</p>
<p>To keep the project data organized, we’re going to use <strong>collections</strong>.</p>
<h2 id="heading-how-to-use-collections-in-eleventy">How to Use Collections in Eleventy</h2>
<p>Collections let you group related content together. In our portfolio we’re going to create a <code>projects</code> collection using Markdown files to store information about each individual project.</p>
<p>Inside the <code>src</code> directory, create a <code>projects</code> directory. We’re going to need a Markdown file for each project. As placeholders, we’ll use three projects that I’ve been meaning to build.</p>
<p>Josh W Comeau has some great advice on <a target="_blank" href="https://www.joshwcomeau.com/effective-portfolio/">building an effective developer portfolio</a> and he strongly recommends describing your personal projects with detailed case studies. So for each of our projects we’re going to have a case study laying out:</p>
<ul>
<li><p>What problem we solved</p>
</li>
<li><p>Why we chose these specific technologies</p>
</li>
<li><p>What challenges we faced</p>
</li>
<li><p>What lessons we learned</p>
</li>
</ul>
<p>Copy the following three sample projects into the <code>projects</code> directory:</p>
<p><code>catch-up.md</code></p>
<pre><code class="lang-markdown">---
title: "Catch Up"
summary: "Sometimes it's hard to keep in touch with friends and family. I made this app to remind me to schedule a call if we haven't talked in a while."
image: /images/catch-up.jpg
imageAlt: "Screenshots of catch up app"
tech:
<span class="hljs-bullet">  -</span> "Next.js"
<span class="hljs-bullet">  -</span> "Firebase"
<span class="hljs-bullet">  -</span> "Tailwind CSS"
siteUrl: "#"
<span class="hljs-section">repoUrl: "#"
---</span>

<span class="hljs-section">### Problem Solved</span>

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Tincidunt tortor aliquam nulla facilisi. Feugiat scelerisque varius morbi enim nunc faucibus a pellentesque sit. Condimentum lacinia quis vel eros donec ac odio tempor orci.

<span class="hljs-section">### Technologies Used</span>

Scelerisque eleifend donec pretium vulputate sapien nec sagittis aliquam. Diam sit amet nisl suscipit adipiscing bibendum est ultricies. Consequat ac felis donec et odio pellentesque diam volutpat commodo.

<span class="hljs-section">### Challenges Faced</span>

Eget mauris pharetra et ultrices. Molestie nunc non blandit massa enim nec. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae. Nulla at volutpat diam ut venenatis. Volutpat ac tincidunt vitae semper quis lectus nulla at.

<span class="hljs-section">### Lessons Learned</span>

Non blandit massa enim nec. Tempor commodo ullamcorper a lacus vestibulum sed. Et netus et malesuada fames ac turpis egestas integer eget. In ante metus dictum at tempor commodo. Eu scelerisque felis imperdiet proin fermentum leo.
</code></pre>
<p><code>sourdough-sensei.md</code></p>
<pre><code class="lang-markdown">---
title: "Sourdough Sensei"
summary: "Like a lot of people, I got really into sourdough in 2020. I made this app to help me bake delicious bread by putting all my recipes and schedules in one place."
image: /images/sourdough-sensei.jpg
imageAlt: "Screenshots of sourdough bread app"
tech:
<span class="hljs-bullet">  -</span> "React.js"
<span class="hljs-bullet">  -</span> "Firebase"
<span class="hljs-bullet">  -</span> "Tailwind CSS"
siteUrl: "#"
<span class="hljs-section">repoUrl: "#"
---</span>

<span class="hljs-section">### Problem Solved</span>

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Tincidunt tortor aliquam nulla facilisi. Feugiat scelerisque varius morbi enim nunc faucibus a pellentesque sit. Condimentum lacinia quis vel eros donec ac odio tempor orci.

<span class="hljs-section">### Technologies Used</span>

Scelerisque eleifend donec pretium vulputate sapien nec sagittis aliquam. Diam sit amet nisl suscipit adipiscing bibendum est ultricies. Consequat ac felis donec et odio pellentesque diam volutpat commodo.

<span class="hljs-section">### Challenges Faced</span>

Eget mauris pharetra et ultrices. Molestie nunc non blandit massa enim nec. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae. Nulla at volutpat diam ut venenatis. Volutpat ac tincidunt vitae semper quis lectus nulla at.

<span class="hljs-section">### Lessons Learned</span>

Non blandit massa enim nec. Tempor commodo ullamcorper a lacus vestibulum sed. Et netus et malesuada fames ac turpis egestas integer eget. In ante metus dictum at tempor commodo. Eu scelerisque felis imperdiet proin fermentum leo.
</code></pre>
<p><code>spellbook.md</code></p>
<pre><code class="lang-markdown">---
title: "Spellbook"
summary: "I'm a huge Dungeons and Dragons fan, but keeping my spells straight has always been a challenge. I built this app to put all the information I need at my fingertips."
image: /images/spellbook.jpg
imageAlt: "Screenshots of DnD project"
tech:
<span class="hljs-bullet">  -</span> "Next.js"
<span class="hljs-bullet">  -</span> "Firebase"
<span class="hljs-bullet">  -</span> "Tailwind CSS"
siteUrl: "#"
<span class="hljs-section">repoUrl: "#"
---</span>

<span class="hljs-section">### Problem Solved</span>

Yes, I could have just used DnD Beyond. But where's the fun in that? Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Tincidunt tortor aliquam nulla facilisi. Feugiat scelerisque varius morbi enim nunc faucibus a pellentesque sit. Condimentum lacinia quis vel eros donec ac odio tempor orci.

<span class="hljs-section">### Technologies Used</span>

Scelerisque eleifend donec pretium vulputate sapien nec sagittis aliquam. Diam sit amet nisl suscipit adipiscing bibendum est ultricies. Consequat ac felis donec et odio pellentesque diam volutpat commodo.

<span class="hljs-section">### Challenges Faced</span>

Eget mauris pharetra et ultrices. Molestie nunc non blandit massa enim nec. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae. Nulla at volutpat diam ut venenatis. Volutpat ac tincidunt vitae semper quis lectus nulla at.

<span class="hljs-section">### Lessons Learned</span>

Non blandit massa enim nec. Tempor commodo ullamcorper a lacus vestibulum sed. Et netus et malesuada fames ac turpis egestas integer eget. In ante metus dictum at tempor commodo. Eu scelerisque felis imperdiet proin fermentum leo.
</code></pre>
<p>Just like with templates, the frontmatter at the top of these files makes values available that you can inject into your templates.</p>
<p>Since these Markdown files are ultimately inside the <code>src</code> directory, Eleventy will treat them as templates and create a HTML page from each file. Their URL will be in the format <code>/subdirectory_name/filename</code>, for example <code>/projects/sourdough-sensei</code>.</p>
<p>But Eleventy won't know what layout to use for these pages since they don't yet have a <code>layout</code> value in their frontmatter.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-19-08-18-Screenshot.png" alt="sourdough-sensei page without layout or frontmatter data" width="600" height="400" loading="lazy"></p>
<p><em>sourdough-sensei page without layout or frontmatter data</em></p>
<p>Right now these files aren’t a collection. Collections are defined by sharing a <code>tags</code> value, such as <code>“tags”: “projects”</code>.</p>
<p>Every file with the <code>projects</code> tag will be included in the <code>projects</code> collection.</p>
<p>Since we only have three projects, we could include a <code>tags</code> value in the frontmatter of our three Markdown files.</p>
<p>But if we had a site with a lot of content – for example dozens of blog posts, recorded talks, and tutorials that all shared dozens of tags between them – this could become difficult to manage. This is where <strong>directory data files</strong> are useful.</p>
<h3 id="heading-how-to-use-directory-data-files">How to Use Directory Data Files</h3>
<p>If you have certain values that are shared by every file in a folder, you can put these values in a directory data file.</p>
<p>Inside the <code>projects</code> directory, create a <code>projects.json</code> file. A directory data file should have the same name as the collection it’s attached to.</p>
<p>Any frontmatter fields that are shared by all the projects files should go in the <code>projects.json</code> directory data file:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"layout"</span>: <span class="hljs-string">"project.njk"</span>,
  <span class="hljs-attr">"tags"</span>: <span class="hljs-string">"projects"</span>
}
</code></pre>
<p>The <code>layout</code> value means that every project will use the same layout (we’re going to create this <code>project.njk</code> file in a moment). The <code>tags</code> value is what turns them into the <code>projects</code> collection that we can use in our templates.</p>
<h2 id="heading-how-to-use-collections-in-templates">How to Use Collections in Templates</h2>
<p>We’re now going to use the <code>projects</code> collection to:</p>
<ul>
<li><p>Add a projects section to our homepage</p>
</li>
<li><p>Create a Projects page</p>
</li>
<li><p>Create a case study page for each project</p>
</li>
</ul>
<p>To include data from a collection on a page of your site, you need to reference the <code>collections</code> object in a template.</p>
<p>We can use Nunjucks to loop over the collection and output its contents. To access a frontmatter value from a <code>project</code> in the <code>projects</code> collection, we use <code>project.data</code>.</p>
<p>For example:</p>
<pre><code class="lang-python">{% <span class="hljs-keyword">for</span> project <span class="hljs-keyword">in</span> collections.projects %}
{{ project.data.title }}
{% endfor %}
</code></pre>
<p>In the <code>_includes</code> directory, create <code>project.njk</code>, <code>project-card.njk</code> and <code>project-grid.njk</code> files.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/includes.PNG" alt="_includes directory structure." width="600" height="400" loading="lazy"></p>
<p>_<em>includes directory structure</em></p>
<p>We’ll use <code>project.njk</code> to create a page for each of our projects.</p>
<p>Since these pages are generated from templates, we can access their frontmatter values directly, such as <code>title</code>, <code>image</code>, <code>imageAlt</code>, and <code>content</code> for the main content of the Markdown file.</p>
<pre><code class="lang-python">---
layout: <span class="hljs-string">"base.njk"</span>
---

&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">project</span>"&gt;
  &lt;<span class="hljs-title">h2</span> <span class="hljs-title">class</span>="<span class="hljs-title">project__heading</span>"&gt;{{ <span class="hljs-title">title</span> }}&lt;/<span class="hljs-title">h2</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">project__image</span>-<span class="hljs-title">wrapper</span>"&gt;
      &lt;<span class="hljs-title">img</span> <span class="hljs-title">class</span>="<span class="hljs-title">project__image</span>" <span class="hljs-title">src</span>="{{ <span class="hljs-title">image</span> }}" <span class="hljs-title">alt</span>="{{ <span class="hljs-title">imageAlt</span> }}"&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">project__content</span> <span class="hljs-title">prose</span>"&gt;
    {{ <span class="hljs-title">content</span> | <span class="hljs-title">safe</span> }}
  &lt;/<span class="hljs-title">div</span>&gt;
&lt;/<span class="hljs-title">div</span>&gt;</span>
</code></pre>
<p><code>project-grid.njk</code> and <code>project-card.njk</code> will form the list of projects on our portfolio homepage and Projects page.</p>
<p><code>project-grid.njk</code> will loop over the <code>projects</code> collection and insert a <code>project-card</code> partial for each project in the collection.</p>
<p>Add the following content to <code>project-grid.njk</code>:</p>
<pre><code class="lang-python">&lt;section <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">projects</span>"&gt;
  &lt;<span class="hljs-title">h2</span> <span class="hljs-title">class</span>="<span class="hljs-title">project__heading</span>"&gt;<span class="hljs-title">Recent</span> <span class="hljs-title">projects</span>&lt;/<span class="hljs-title">h2</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">grid</span>"&gt;
    {% <span class="hljs-title">for</span> <span class="hljs-title">project</span> <span class="hljs-title">in</span> <span class="hljs-title">collections</span>.<span class="hljs-title">projects</span> %}
      {% <span class="hljs-title">include</span> "<span class="hljs-title">project</span>-<span class="hljs-title">card</span>.<span class="hljs-title">njk</span>" %}
    {% <span class="hljs-title">endfor</span> %}
  &lt;/<span class="hljs-title">div</span>&gt;
&lt;/<span class="hljs-title">section</span>&gt;</span>
</code></pre>
<p>Add the following content to <code>project-card.njk</code>:</p>
<pre><code class="lang-python">&lt;article <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card</span>"&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card__image</span>-<span class="hljs-title">wrapper</span>"&gt;
    &lt;<span class="hljs-title">img</span> <span class="hljs-title">class</span>="<span class="hljs-title">project__image</span>" <span class="hljs-title">src</span>="{{ <span class="hljs-title">project</span>.<span class="hljs-title">data</span>.<span class="hljs-title">image</span> }}" <span class="hljs-title">alt</span>="{{ <span class="hljs-title">project</span>.<span class="hljs-title">data</span>.<span class="hljs-title">imageAlt</span> }}"&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card__body</span>"&gt;
    &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card__tags</span>"&gt;
      {% <span class="hljs-title">for</span> <span class="hljs-title">tag</span> <span class="hljs-title">in</span> <span class="hljs-title">project</span>.<span class="hljs-title">data</span>.<span class="hljs-title">tech</span> %}
        &lt;<span class="hljs-title">span</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card__tag</span>"&gt;{{ <span class="hljs-title">tag</span> }}&lt;/<span class="hljs-title">span</span>&gt;
      {% <span class="hljs-title">endfor</span> %}
    &lt;/<span class="hljs-title">div</span>&gt;
    &lt;<span class="hljs-title">h3</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card__title</span>"&gt;
      &lt;<span class="hljs-title">a</span> <span class="hljs-title">href</span>="{{ <span class="hljs-title">project</span>.<span class="hljs-title">url</span> }}"&gt;{{ <span class="hljs-title">project</span>.<span class="hljs-title">data</span>.<span class="hljs-title">title</span> }}&lt;/<span class="hljs-title">a</span>&gt;
    &lt;/<span class="hljs-title">h3</span>&gt;
    &lt;<span class="hljs-title">p</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card__summary</span>"&gt;{{ <span class="hljs-title">project</span>.<span class="hljs-title">data</span>.<span class="hljs-title">summary</span> }}&lt;/<span class="hljs-title">p</span>&gt;
    &lt;<span class="hljs-title">a</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card__link</span>" <span class="hljs-title">href</span>="{{ <span class="hljs-title">project</span>.<span class="hljs-title">url</span> }}"&gt;<span class="hljs-title">Read</span> <span class="hljs-title">project</span> <span class="hljs-title">case</span> <span class="hljs-title">study</span> 
      &lt;<span class="hljs-title">svg</span> <span class="hljs-title">xmlns</span>="<span class="hljs-title">http</span>:</span>//www.w3.org/<span class="hljs-number">2000</span>/svg<span class="hljs-string">" class="</span>project-card__link-icon<span class="hljs-string">" viewBox="</span><span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">20</span> <span class="hljs-number">20</span><span class="hljs-string">" fill="</span>currentColo<span class="hljs-string">r"&gt;
        &lt;path fill-rule="</span>evenodd<span class="hljs-string">" d="</span>M7<span class="hljs-number">.293</span> <span class="hljs-number">14.707</span>a1 <span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">010</span><span class="hljs-number">-1.414L</span>10<span class="hljs-number">.586</span> <span class="hljs-number">10</span> <span class="hljs-number">7.293</span> <span class="hljs-number">6.707</span>a1 <span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">011.414</span><span class="hljs-number">-1.414l</span>4 <span class="hljs-number">4</span>a1 <span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">010</span> <span class="hljs-number">1.414l</span><span class="hljs-number">-4</span> <span class="hljs-number">4</span>a1 <span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">01</span><span class="hljs-number">-1.414</span> <span class="hljs-number">0</span>z<span class="hljs-string">" clip-rule="</span>evenodd<span class="hljs-string">" /&gt;
      &lt;/svg&gt;
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/article&gt;</span>
</code></pre>
<p>Since <code>project-card.njk</code> is accessing frontmatter values from a member of a collection, we need to use <code>project.data</code> to access these values in the template. Eleventy also generates a <code>project.url</code> value that we can use to link to the project's generated page.</p>
<p>In <code>index.njk</code>, add <code>{% include "project-grid.njk" %}</code> underneath the profile and technologies partials.</p>
<pre><code class="lang-python">---
title: <span class="hljs-string">"Eleventy Portfolio"</span>
layout: <span class="hljs-string">"base.njk"</span>
---

{% include <span class="hljs-string">"profile.njk"</span> %}
{% include <span class="hljs-string">"technologies.njk"</span> %}
{% include <span class="hljs-string">"project-grid.njk"</span> %}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-19-41-45-Eleventy-Portfolio.png" alt="Grid of project cards on homepage." width="600" height="400" loading="lazy"></p>
<p><em>Grid of project cards on homepage</em></p>
<p>Next we're going to create a Projects page. In the <code>src</code> directory, create a <code>projects.njk</code> file with the following contents:</p>
<pre><code class="lang-python">---
title: <span class="hljs-string">"Eleventy Portfolio"</span>
layout: <span class="hljs-string">"base.njk"</span>
---

&lt;h2 <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">projects__heading</span>"&gt;<span class="hljs-title">Recent</span> <span class="hljs-title">projects</span>&lt;/<span class="hljs-title">h2</span>&gt;
&lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">list</span>"&gt;
  {% <span class="hljs-title">for</span> <span class="hljs-title">project</span> <span class="hljs-title">in</span> <span class="hljs-title">collections</span>.<span class="hljs-title">projects</span> %}
    {% <span class="hljs-title">include</span> "<span class="hljs-title">project</span>-<span class="hljs-title">card</span>.<span class="hljs-title">njk</span>" %}
  {% <span class="hljs-title">endfor</span> %}
&lt;/<span class="hljs-title">div</span>&gt;</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-19-25-32-Eleventy-Portfolio.png" alt="Projects page." width="600" height="400" loading="lazy"></p>
<p><em>Projects page</em></p>
<p>The projects are now being displayed on our homepage as well as the projects page, and each project now has its own page with its case study.</p>
<p>We could stop here, but there are a few more Eleventy features that will make our portfolio site even better, namely <strong>shortcodes</strong> and <strong>plugins</strong>.</p>
<h3 id="heading-how-to-use-shortcodes">How to Use Shortcodes</h3>
<p>A shortcode is a way to inject reusable content (often a JavaScript string template literal) into your templates.</p>
<p>We’re going to create a simple <code>year</code> shortcode that outputs the current year so that the footer in our portfolio site is always up to date.</p>
<p>Add the following line to the configuration function in <code>.eleventy.js</code>.</p>
<pre><code class="lang-javascript">eleventyConfig.addShortcode(<span class="hljs-string">"year"</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getFullYear()}</span>`</span>);
</code></pre>
<p>When you use the shortcode in a template the function will be run and the <code>year</code> value will be injected into the template.</p>
<p>In <code>footer.njk</code> use <code>{% year %}</code> to access the <code>year</code> shortcode.</p>
<pre><code class="lang-python">&lt;footer <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">footer</span>"&gt;
  &lt;<span class="hljs-title">p</span>&gt;&amp;<span class="hljs-title">copy</span>; <span class="hljs-title">Marie</span> <span class="hljs-title">Jackson</span> {% <span class="hljs-title">year</span> %}&lt;/<span class="hljs-title">p</span>&gt;
&lt;/<span class="hljs-title">footer</span>&gt;</span>
</code></pre>
<p>You might need to restart your development server for it to recognize the shortcode.</p>
<p>Now whenever you trigger a build of your site in the future, your footer will always show the correct year.</p>
<p>Shortcodes can do a lot more than this. Next, we’re going to use the Eleventy Image plugin, which uses shortcodes, to optimize our site’s images and improve our page load speed.</p>
<h3 id="heading-how-to-use-the-eleventy-image-plugin">How to Use the Eleventy Image Plugin</h3>
<p>Eleventy has a number of official plugins, from ones to check your writing for inclusive language to others that let you leverage Serverless functions.</p>
<p>The Image plugin is particularly useful since images are often the largest resource your site loads. It optimizes your images so your site uses the appropriate size and format for the user's browser, saving bandwidth for your user and making your site load faster.</p>
<p>First we need to install the Image plugin from npm. In the root of your project, run:</p>
<pre><code class="lang-python">npm install @<span class="hljs-number">11</span>ty/eleventy-img
</code></pre>
<p>At the top of <code>.eleventy.js</code>, we’re going to import the Image plugin and configure the shortcode that the plugin will use to optimize our images.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Image = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@11ty/eleventy-img"</span>);

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">imageShortcode</span>(<span class="hljs-params">src, alt, sizes</span>) </span>{
  <span class="hljs-keyword">let</span> metadata = <span class="hljs-keyword">await</span> Image(<span class="hljs-string">`./src<span class="hljs-subst">${src}</span>`</span>, {
    <span class="hljs-attr">widths</span>: [<span class="hljs-number">300</span>, <span class="hljs-number">800</span>, <span class="hljs-literal">null</span>],
    <span class="hljs-attr">formats</span>: [<span class="hljs-string">"avif"</span>, <span class="hljs-string">"jpeg"</span>],
    <span class="hljs-attr">urlPath</span>: <span class="hljs-string">"/images/"</span>,
    <span class="hljs-attr">outputDir</span>: <span class="hljs-string">"./public/images/"</span>
  });

  <span class="hljs-keyword">let</span> imageAttributes = {
    alt,
    sizes,
    <span class="hljs-attr">loading</span>: <span class="hljs-string">"lazy"</span>,
    <span class="hljs-attr">decoding</span>: <span class="hljs-string">"async"</span>
  };

  <span class="hljs-keyword">return</span> Image.generateHTML(metadata, imageAttributes);
}
</code></pre>
<p>The image shortcode takes in arguments for <code>src</code>, <code>alt</code> and <code>sizes</code>. These will be the URL for the image, the text for the image’s alt tag, and the sizes that are used to display different sized images at different screen sizes.</p>
<p>The <code>widths</code> property specifies what size images the plugin will generate. In this case, 300px, 800px, and the image's original size.</p>
<p>The <code>formats</code> property specifies which image formats to generate. Here we're using avif (which produces high quality images at low file sizes) with jpeg as a fallback for browsers that don't support avif.</p>
<p><code>urlPath</code> and <code>outputDir</code> tell the plugin where to get the images from and where to output the optimized images to.</p>
<p>The plugin adds <code>loading</code> and <code>decoding</code> attributes to the generated HTML to lazy-load the images and decode them asynchronously, both of which will help with page load times.</p>
<p>Next, we’re going to include the shortcode in our configuration function. We'll call it <code>EleventyImage</code> for the sake of clarity.</p>
<pre><code class="lang-javascript">eleventyConfig.addNunjucksAsyncShortcode(<span class="hljs-string">"EleventyImage"</span>, imageShortcode);
</code></pre>
<p>Notice that we’re using <code>addNunjucksAsyncShortcode</code> rather than <code>addShortcode</code>. This is because the image generation process is asynchronous. It will take some amount of time to generate different image sizes and formats and we want our shortcode to wait until these have all been generated before it injects the finished HTML into our templates.</p>
<p>Since our shortcode is asynchronous, we’re going to run into an issue with using this shortcode inside a Nunjucks for loop. We need to use <code>asyncEach</code>, the asynchronous version of Nunjuck’s <code>for</code>.</p>
<p>In <code>projects.njk</code> and <code>project-grid.njk</code>, replace this:</p>
<pre><code class="lang-python">{% <span class="hljs-keyword">for</span> project <span class="hljs-keyword">in</span> collections.projects %}
{% include <span class="hljs-string">"project-card.njk"</span> %}
{% endfor %}
</code></pre>
<p>with this:</p>
<pre><code class="lang-python">{% asyncEach project <span class="hljs-keyword">in</span> collections.projects %}
{% include <span class="hljs-string">"project-card.njk"</span> %}
{% endeach %}
</code></pre>
<p>Now, in <code>project.njk</code> we can replace this:</p>
<pre><code class="lang-python">&lt;img <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">project__image</span>" <span class="hljs-title">src</span>="{{ <span class="hljs-title">image</span> }}" <span class="hljs-title">alt</span>="{{ <span class="hljs-title">imageAlt</span> }}"&gt;</span>
</code></pre>
<p>with this:</p>
<pre><code class="lang-python">{% EleventyImage image, imageAlt, <span class="hljs-string">"(min-width: 30em) 50vw, 100vw"</span> %}
</code></pre>
<p>The <code>image</code>, <code>imageAlt</code> and <code>"(min-width: 30em) 50vw, 100vw"</code> values are the <code>src</code>, <code>alt</code> and <code>sizes</code> parameters for the Image shortcode.</p>
<p>Next, in <code>project-card.njk</code>, we can replace this:</p>
<pre><code class="lang-python">&lt;img <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">project</span>-<span class="hljs-title">card__image</span>" <span class="hljs-title">src</span>="{{ <span class="hljs-title">project</span>.<span class="hljs-title">data</span>.<span class="hljs-title">image</span> }}" <span class="hljs-title">alt</span>="{{ <span class="hljs-title">project</span>.<span class="hljs-title">data</span>.<span class="hljs-title">imageAlt</span> }}"&gt;</span>
</code></pre>
<p>with this:</p>
<pre><code class="lang-python">{% EleventyImage project.data.image, project.data.imageAlt, <span class="hljs-string">"(min-width: 30em) 50vw, 100vw"</span> %}
</code></pre>
<p>Finally, in <code>profile.njk</code> we can replace this:</p>
<pre><code class="lang-python">&lt;img <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">profile__image</span>" <span class="hljs-title">src</span>="/<span class="hljs-title">images</span>/<span class="hljs-title">profile</span>.<span class="hljs-title">jpg</span>" <span class="hljs-title">alt</span>="<span class="hljs-title">Marie</span> <span class="hljs-title">Jackson</span>, <span class="hljs-title">Software</span> <span class="hljs-title">Developer</span>"&gt;</span>
</code></pre>
<p>with this:</p>
<pre><code class="lang-python">{% EleventyImage <span class="hljs-string">"/images/profile.jpg"</span>, <span class="hljs-string">"Marie Jackson, Software Developer"</span>, <span class="hljs-string">"(min-width: 16em) 50vw, 100vw"</span> %}
</code></pre>
<p>When our site builds, the Eleventy Image plugin will do a couple of things:</p>
<ul>
<li><p>there will be multiple formats and sizes for every image in <code>public/images</code></p>
</li>
<li><p>our generated HTML will now use the <code>&lt;picture&gt;</code> element</p>
</li>
<li><p>the <code>&lt;img&gt;</code> tags will have <code>loading="lazy"</code> and <code>decode="async"</code> attributes</p>
</li>
</ul>
<p>Now our site will serve the optimal image format and size depending on the browser and screen size of the site visitor. And images will be lazy loaded as they are about to enter the viewport.</p>
<p>If we use the network tab in a browser's developer tools, we can test the difference. On an iPhone 12, the unoptimized image on one of our project pages would be 30.37KB, while the image optimized by the Image plugin is just 6.01KB, an 80% saving!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/unoptimized.PNG" alt="Unoptimized image on mobile - 30.37KB." width="600" height="400" loading="lazy"></p>
<p><em>Unoptimized image on mobile - 30.37KB</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/optimized.PNG" alt="Optimized image on mobile 6.01KB." width="600" height="400" loading="lazy"></p>
<p><em>Optimized image on mobile 6.01KB</em></p>
<p>We’re almost ready to deploy our site. But before we do that, we need to complete our contact form.</p>
<h2 id="heading-how-to-a-build-contact-form-with-netlify-forms">How to a Build Contact Form with Netlify Forms</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-18-17-08-Eleventy-Portfolio-1.png" alt="Contact page" width="600" height="400" loading="lazy"></p>
<p><em>Contact page</em></p>
<p>Eleventy is a <strong>static</strong> site generator. But Eleventy works really well with the Jamstack architecture, where you statically generate as much of a site as possible in advance and use APIs and third-party services to add dynamic content and functionality.</p>
<p>In the past, if you wanted to have a contact form on your website, you would need some sort of server, such as a PHP app, to process the form submission.</p>
<p>We’re going to use Netlify Forms to add a contact form to our portfolio without needing to manage a server to handle the submitted forms.</p>
<p>To make this work, we need to make sure our form has two attributes. The most important one is <code>data-netlify="true"</code>. The other is <code>action="/success"</code>.</p>
<pre><code class="lang-python">&lt;form <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">form</span>" <span class="hljs-title">name</span>="<span class="hljs-title">contact</span>" <span class="hljs-title">action</span>="/<span class="hljs-title">success</span>" <span class="hljs-title">method</span>="<span class="hljs-title">POST</span>" <span class="hljs-title">data</span>-<span class="hljs-title">netlify</span>="<span class="hljs-title">true</span>"&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__section</span>"&gt;
    &lt;<span class="hljs-title">label</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__label</span>" <span class="hljs-title">for</span>="<span class="hljs-title">yourName</span>"&gt;<span class="hljs-title">Name</span>&lt;/<span class="hljs-title">label</span>&gt;
    &lt;<span class="hljs-title">input</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__input</span>" <span class="hljs-title">name</span>="<span class="hljs-title">name</span>" <span class="hljs-title">type</span>="<span class="hljs-title">text</span>" <span class="hljs-title">id</span>="<span class="hljs-title">yourName</span>" <span class="hljs-title">required</span>="<span class="hljs-title">true</span>"&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__section</span>"&gt;
    &lt;<span class="hljs-title">label</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__label</span>" <span class="hljs-title">for</span>="<span class="hljs-title">yourEmail</span>"&gt;<span class="hljs-title">Email</span>&lt;/<span class="hljs-title">label</span>&gt;
    &lt;<span class="hljs-title">input</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__input</span>" <span class="hljs-title">name</span>="<span class="hljs-title">email</span>" <span class="hljs-title">type</span>="<span class="hljs-title">email</span>"  <span class="hljs-title">id</span>="<span class="hljs-title">yourEmail</span>" <span class="hljs-title">required</span>="<span class="hljs-title">true</span>"&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
  &lt;<span class="hljs-title">div</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__section</span>"&gt;
    &lt;<span class="hljs-title">label</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__label</span>" <span class="hljs-title">for</span>="<span class="hljs-title">message</span>"&gt;<span class="hljs-title">Message</span>&lt;/<span class="hljs-title">label</span>&gt;
    &lt;<span class="hljs-title">textarea</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__input</span>" <span class="hljs-title">name</span>="<span class="hljs-title">message</span>" <span class="hljs-title">id</span>="<span class="hljs-title">message</span>" <span class="hljs-title">rows</span>="4" <span class="hljs-title">required</span>="<span class="hljs-title">true</span>"&gt;&lt;/<span class="hljs-title">textarea</span>&gt;
  &lt;/<span class="hljs-title">div</span>&gt;
    &lt;<span class="hljs-title">button</span> <span class="hljs-title">class</span>="<span class="hljs-title">form__button</span>" <span class="hljs-title">type</span>="<span class="hljs-title">submit</span>"&gt;<span class="hljs-title">Let</span>'<span class="hljs-title">s</span> <span class="hljs-title">talk</span>&lt;/<span class="hljs-title">button</span>&gt;
&lt;/<span class="hljs-title">form</span>&gt;</span>
</code></pre>
<p>By having a <code>data-netlify="true"</code> attribute on our contact form, when the site is deployed to Netlify, Netlify will recognize this and take over handling the form submission.</p>
<p>By default, when someone completes a Netlify form, they will get a generically styled success message with a link back to the form page. But we can direct them to a custom page by including an <code>action</code> attribute on our form.</p>
<p>The <code>action="/success"</code> attribute means that when the form submits, the user will be redirected to a "success" page on your site (you can give this page a different name if you like). So we had better build that page now.</p>
<p>In the <code>src</code> directory, create a <code>success.njk</code> file with the following content:</p>
<pre><code class="lang-python">---
title: <span class="hljs-string">"Eleventy Portfolio"</span>
layout: <span class="hljs-string">"base.njk"</span>
---

&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">container</span> <span class="hljs-title">text</span>-<span class="hljs-title">center</span>"&gt;
  &lt;<span class="hljs-title">h2</span> <span class="hljs-title">class</span>="<span class="hljs-title">heading</span>--<span class="hljs-title">main</span>"&gt;<span class="hljs-title">Thanks</span> <span class="hljs-title">for</span> <span class="hljs-title">getting</span> <span class="hljs-title">in</span> <span class="hljs-title">touch</span>!&lt;/<span class="hljs-title">h2</span>&gt;
  &lt;<span class="hljs-title">p</span>&gt;<span class="hljs-title">I</span>'<span class="hljs-title">ll</span> <span class="hljs-title">respond</span> <span class="hljs-title">as</span> <span class="hljs-title">soon</span> <span class="hljs-title">as</span> <span class="hljs-title">I</span> <span class="hljs-title">can</span>.&lt;<span class="hljs-title">p</span>&gt;
&lt;/<span class="hljs-title">div</span>&gt;</span>
</code></pre>
<p>Once we deploy the site to Netlify, any submitted forms will show up in the Netlify interface. So let’s finally deploy our portfolio site.</p>
<h2 id="heading-how-to-deploy-to-netlify">How to Deploy to Netlify</h2>
<p>You can deploy an Eleventy site on any static hosting platform: Netlify, Vercel, GitHub Pages, even an AWS S3 bucket.</p>
<p>I'll show you how to deploy to Netlify since we're using Netlify Forms for our contact form. On another hosting platform, you could use a Serverless function to handle submitting the form and sending an email.</p>
<p>If you don't already have a Netlify account, go to <a target="_blank" href="https://www.netlify.com/">netlify.com</a> and create a free one.</p>
<p>Netlify will give you the option to:</p>
<ol>
<li><p>Import an existing project</p>
</li>
<li><p>Start from a template</p>
</li>
<li><p>Deploy manually</p>
</li>
</ol>
<p>We already have our portfolio site, so we don't need a template.</p>
<p>I'll walk you through the two other options.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-21-25-15-Deploy-your-first-project-Netlify.png" alt="Netlify project start screen." width="600" height="400" loading="lazy"></p>
<p><em>Netlify project start screen</em></p>
<h3 id="heading-option-1-how-to-deploy-manually">Option 1 – How to Deploy Manually</h3>
<p>If you're not comfortable with Git and GitHub, Netlify lets you drag and drop to upload a project into their interface.</p>
<p>On your command line, run <code>npm run build</code> or <code>eleventy</code> to build your site.</p>
<p>Now upload the site's <code>public</code> directory to Netlify's file upload interface. In a few moments Netlify will have the site live on a URL that you can visit.</p>
<p>If you want to make future changes to your deployed site, click on "Deploys" and scroll down to find the file uploader.</p>
<p>You can rebuild your site locally and upload the new version of your <code>public</code> folder to Netlify whenever you want.</p>
<h3 id="heading-option-2-how-to-import-a-project-from-git">Option 2 – How to Import a Project from Git</h3>
<p>If you are familiar with Git and GitHub, commit your code and push it to GitHub. Then click on the "Import from Git" button.</p>
<p>Netlify will ask you to connect a Git provider. Choose GitHub and authorize Netlify to access your GitHub repositories.</p>
<p>Choose the repository that holds your portfolio site. You can search for "eleventy", or whatever name you gave it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-21-44-56-Import-an-existing-project-from-a-Git-repository-Netlify.png" alt="Netlify import project interface." width="600" height="400" loading="lazy"></p>
<p><em>Netlify import project interface</em></p>
<p>Netlify will detect that this is an Eleventy project and will ask you to confirm the basic build settings.</p>
<p>Make sure the build command is either <code>npm run build</code> or <code>eleventy</code>.</p>
<p>Under "Publish directory", enter <code>public</code> instead of <code>_site</code>.</p>
<p>Now click the "Deploy site" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-21-46-55-Import-an-existing-project-from-a-Git-repository-Netlify.png" alt="Netlify build settings page." width="600" height="400" loading="lazy"></p>
<p><em>Netlify build settings page</em></p>
<p>In a few moments Netlify will tell you that your site is live and give you a URL for it.</p>
<p>Once your site is live, if go to the Contact page, fill out the form, and submit it. You'll be redirected to the custom success page that you made.</p>
<p>If you click on "Forms" in the Netlify interface, you'll be brought to the Netlify Forms dashboard.</p>
<p>The form will have whatever name you used in the <code>name</code> attribute on your contact form, in this case "contact".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-at-21-55-09-Forms-remarkable-blini-2319ee.png" alt="Netlify forms dashboard." width="600" height="400" loading="lazy"></p>
<p><em>Netlify forms dashboard</em></p>
<p>Congratulations, you've built and deployed an Eleventy portfolio site. 🥳🎉🎉🎉</p>
<p>Feel free to use this project as a template for your own portfolio and customize it any way you'd like. So many portfolios look similar, so it's always good when a portfolio shows off your personality and passions.</p>
<h2 id="heading-where-to-take-it-from-here">Where to Take it from Here</h2>
<p>This tutorial has hopefully taught you the basics of Eleventy, and how to combine data and templates to make fast sites without a whole lot of tooling or configuration.</p>
<p>If you'd like to take your Eleventy journey further, the <a target="_blank" href="https://www.11ty.dev/docs/">Eleventy docs</a> are very good. There's lots more to learn about manipulating data, not to mention adding personalized content and dynamic interactivity with Serverless and Edge Functions.</p>
<p><a target="_blank" href="https://11ty.rocks/">11ty.rocks</a> by Stephanie Eckles is also a great resource, with practical tips and helpful tutorials on all sorts of Eleventy features.</p>
<p>I hope this guide has been helpful and made you excited to learn more about Eleventy, static site generators, and the Jamstack.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
