<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Colin Oakley</title>
    <description>The latest articles on DEV Community by Colin Oakley (@htmlandbacon).</description>
    <link>https://dev.to/htmlandbacon</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F13520%2F060d5bbb-0a99-46c7-a223-d0495a993b0c.jpeg</url>
      <title>DEV Community: Colin Oakley</title>
      <link>https://dev.to/htmlandbacon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/htmlandbacon"/>
    <language>en</language>
    <item>
      <title>Evaluating accessibility</title>
      <dc:creator>Colin Oakley</dc:creator>
      <pubDate>Thu, 27 May 2021 08:12:52 +0000</pubDate>
      <link>https://dev.to/htmlandbacon/evaluating-accessibility-al1</link>
      <guid>https://dev.to/htmlandbacon/evaluating-accessibility-al1</guid>
      <description>&lt;p&gt;One thing that is often asked when I am talking about accessibility is how you evaluate it on a website or service.&lt;/p&gt;

&lt;p&gt;There isn't an easy answer to this question as it is a complex mix of technical implementation, design, and tooling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;The most recent evaluation I did was with an interaction designer, the first thing I did was use a Miro board to document the high-level flow of the service.&lt;/p&gt;

&lt;p&gt;This helps me understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what the service is doing&lt;/li&gt;
&lt;li&gt;what sort of patterns are included&lt;/li&gt;
&lt;li&gt;any sticky points&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives us a visual representation to document issues against.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automated checks
&lt;/h2&gt;

&lt;p&gt;The first thing I always do is get a feel for the page&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does it have landmarks?&lt;/li&gt;
&lt;li&gt;Does it have form elements?&lt;/li&gt;
&lt;li&gt;Does it have any interactive elements?&lt;/li&gt;
&lt;li&gt;Does the header document outline follow a standard order?&lt;/li&gt;
&lt;li&gt;Does it respond when you change browser width?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Usually, this will help narrow down what sort of issues might happen on a page.&lt;/p&gt;

&lt;p&gt;From here I'll run some browser plugins to see if anything obvious is flagged&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://wave.webaim.org/"&gt;WAVE Evaluation Tool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.deque.com/axe/browser-extensions/"&gt;axe DevTools Browser Extensions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.deque.com/axe/browser-extensions/"&gt;Accessibility Insights&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These are by no means the only automated checks, and we need to appreciate that these sort of plugins, will only flag a limited selection of issues.&lt;/p&gt;

&lt;p&gt;"Our research backs this up. While the tools picked up the majority of the accessibility barriers we created – 71% – there was a large minority that would only have been picked up by manual checking." from &lt;a href="https://accessibility.blog.gov.uk/2017/02/24/what-we-found-when-we-tested-tools-on-the-worlds-least-accessible-webpage/"&gt;What we found when we tested tools on the world’s least-accessible webpage&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manual checks
&lt;/h2&gt;

&lt;p&gt;Often there is a lot of subtlety to accessibility issues semantically an image may have an alternative text tag, but that doesn't mean it actively describes the image.&lt;/p&gt;

&lt;p&gt;The manual check falls into two parts largely, understanding and interaction.&lt;/p&gt;

&lt;p&gt;For interaction I'll generally go through this list:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check tab order&lt;/li&gt;
&lt;li&gt;Check focus style on interaction elements&lt;/li&gt;
&lt;li&gt;Check page can be used by only a keyboard (this related to two)&lt;/li&gt;
&lt;li&gt;Check interaction with the page&lt;/li&gt;
&lt;li&gt;Check error states&lt;/li&gt;
&lt;li&gt;Check common input issues (i.e trimming spaces)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://htmlpreview.github.io/?https://github.com/dwp/assistive-technology-templates/blob/master/html/os-x-voiceover.html"&gt;Check using a screen reader&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Check &lt;a href="https://marcysutton.com/links-vs-buttons-in-modern-web-applications"&gt;buttons and links are used in the right context&lt;/a&gt; and Voice Control&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Checking the page conveys understanding ends up being more of a content check&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check page titles follow best practice&lt;/li&gt;
&lt;li&gt;Check form fields are descriptive&lt;/li&gt;
&lt;li&gt;Check errors are descriptive&lt;/li&gt;
&lt;li&gt;Check link text is descriptive, this may need a screen reader as sometimes context is hidden.&lt;/li&gt;
&lt;li&gt;Check any aria/hidden content is read out as intended&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Service level checks
&lt;/h2&gt;

&lt;p&gt;There is a couple of functions we need to check at a service level&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Service has a skip link&lt;/li&gt;
&lt;li&gt;Landmarks and navigation is consistent&lt;/li&gt;
&lt;li&gt;&lt;a href="https://accessibility-manual.dwp.gov.uk/best-practice/service-features#2-2-1-timing-adjustable-a-"&gt;Session timeout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://accessibility-manual.dwp.gov.uk/best-practice/service-features#3-3-4-error-prevention-legal-financial-data-"&gt;Check your answers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Alignment
&lt;/h2&gt;

&lt;p&gt;The final part of the evaluation is to check if the service is consistent with other GOV.UK services and documented &lt;a href="https://design-system.service.gov.uk/patterns/"&gt;patterns&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dealing with issues
&lt;/h2&gt;

&lt;p&gt;The first step is to validate is if the issue is a &lt;a href="https://accessibility-manual.dwp.gov.uk/tools-and-resources/known-accessibility-issues"&gt;false positive&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From here we need to decide if it is an issue of implementation or something we are consuming.&lt;/p&gt;

&lt;p&gt;If for example we are using an external package, we will need to work out if the issue is already documented, or if it is something new. With the &lt;a href="https://github.com/alphagov/govuk-frontend/"&gt;GOV.UK frontend&lt;/a&gt; we would raise this on GitHub.&lt;/p&gt;

&lt;p&gt;It won't always be a technical fix either, a lot of complicated accessibility issues will need to be designed out of a service.&lt;/p&gt;

&lt;p&gt;A recent example of this is the conversation around the use of an &lt;a href="https://github.com/alphagov/govuk-design-system-backlog/issues/1"&gt;accordion&lt;/a&gt; where we should a step back, and change how we present the information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outputs
&lt;/h2&gt;

&lt;p&gt;The first time I did this I gave people an Excel list, this lacked the context needed to where it was happening in the service.&lt;/p&gt;

&lt;p&gt;I've now started to use that Miro as a visual representation of issues grouped into different types and attached related -&lt;a href="https://www.gov.uk/service-manual/helping-people-to-use-your-service/understanding-wcag"&gt;Web Content Accessibility Guidelines (known as WCAG 2.1)&lt;/a&gt; which I walk through with the team to set context and talk about the barriers it will create.&lt;/p&gt;

&lt;p&gt;Miro is really nice for giving context but bad as a document store. The next step is to raise issues as output to a project board (like Jira or GitHub Projects), this will allow better tracking of issues, tagging, and give a consolidated view.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://accessibility-manual.dwp.gov.uk/"&gt;DWP Accessibility Manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gov.uk/service-manual/helping-people-to-use-your-service/making-your-service-accessible-an-introduction"&gt;Service Manual - Making your service accessible: an introduction&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>a11y</category>
      <category>process</category>
      <category>government</category>
      <category>webdev</category>
    </item>
    <item>
      <title>On a team who is responsible for accessibility?</title>
      <dc:creator>Colin Oakley</dc:creator>
      <pubDate>Tue, 18 Jun 2019 10:31:16 +0000</pubDate>
      <link>https://dev.to/htmlandbacon/on-a-team-who-is-responsible-for-accessibility-58mj</link>
      <guid>https://dev.to/htmlandbacon/on-a-team-who-is-responsible-for-accessibility-58mj</guid>
      <description>&lt;p&gt;There is always a slightly weird moment on most teams I've worked on where a conversation happens about who is responsible for accessibility.&lt;/p&gt;

&lt;p&gt;The truth is no one person is responsible for accessibility, we as a team are responsible. It should be a principle of the services we deliver that they are by default accessible. This will become part of &lt;a href="https://gds.blog.gov.uk/2018/09/24/how-were-helping-public-sector-websites-meet-accessibility-requirements/"&gt;UK law&lt;/a&gt; later in the year for Government services.&lt;/p&gt;

&lt;p&gt;For me as a front-end developer, I can build something that is semantically accessible, this doesn't make it useable.&lt;/p&gt;

&lt;p&gt;Everyone on the team needs to advocate for accessibility, we need to understand what our roles are responsible for, and how they fit together to create accessible services.&lt;/p&gt;

&lt;p&gt;It is worth having this conversation as a team, so you can get a better understanding of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  User Researchers
&lt;/h2&gt;

&lt;p&gt;We should be doing research with a wide range of people who use our service. I'm never overly keen on persona but it is a great way to raise awareness on a team of the different types of challenges a user will face.&lt;/p&gt;

&lt;p&gt;Another important thing is making sure we regularly test with people who will use our service, who use assistive technology. This sometimes can be quite difficult to find, so we can do usability testing with people who use the tools.&lt;/p&gt;

&lt;p&gt;This will give us some context that our service is usable, but might not help us understand if the person's user need is met by the service.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.gov.uk/government/publications/understanding-disabilities-and-impairments-user-profiles"&gt;Understanding disabilities and impairments: user profiles&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Content and Interaction Designers
&lt;/h2&gt;

&lt;p&gt;There are lots of things a designer (both content and interaction) needs to take into account when designing a service, such as making sure we have thought about focus state, colour contrasts and clear language.&lt;br&gt;
As designers we need to understand WCAG 2.1 and the core parts of it, so we can influence how we design.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://accessibility.blog.gov.uk/2016/09/02/dos-and-donts-on-designing-for-accessibility/"&gt;Dos and don'ts on designing for accessibility&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gov.uk/service-manual/helping-people-to-use-your-service/understanding-wcag"&gt;Understanding WCAG 2.1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/TR/WCAG21/"&gt;Web Content Accessibility Guidelines (WCAG) 2.1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gov.uk/guidance/content-design/writing-for-gov-uk"&gt;Content design: planning, writing and managing content&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Developers and Testers
&lt;/h2&gt;

&lt;p&gt;For me, as a developer, it is a given that I use the right mark-up for a website, regardless of the technology used.&lt;/p&gt;

&lt;p&gt;We also need to build testing tools into our process, I know they won't catch all the things (see link below), but building them into pipelines is a way to catch big problems early.&lt;/p&gt;

&lt;p&gt;We can also sanity check things like is it keyboard accessible? and we can build these into our definition of done.&lt;/p&gt;

&lt;p&gt;We can also sanity check our services with tools, we need to appreciate that we will not use the tools in the same way as an actual user.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://alphagov.github.io/accessibility-tool-audit/"&gt;How do automated accessibility checkers compare?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://insidegovuk.blog.gov.uk/2018/01/24/improving-accessibility-with-accessibility-acceptance-criteria/"&gt;Improving accessibility with accessibility acceptance criteria&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Product Owners
&lt;/h2&gt;

&lt;p&gt;Like everyone product owners need to understand the types of users that might be affected by issues. They also need to make sure the team has the time and space to do the testing and deal with the outcome.&lt;/p&gt;

&lt;p&gt;They need to be an advocate of the work that is going on and make sure stakeholders understand what work is going on, and why it is important.&lt;br&gt;
Building a digital product doesn't make the other support channels accessible, but we can use this to highlight issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if this isn't happening?
&lt;/h2&gt;

&lt;p&gt;Most of the time, I've found starting to have the conversation about what accessibility needs we have for our users is enough to kick start better conversations around it, if it still doesn't happen, here are some things you can try to get it going.&lt;/p&gt;

&lt;p&gt;A lot of these activities will hopefully help to get people to understand more about accessibility and start to build empathy with people who have disabilities that we need to think about when designing and building services.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Make it visible&lt;/strong&gt; - I linked to the excellent &lt;a href="https://accessibility.blog.gov.uk/2016/09/02/dos-and-donts-on-designing-for-accessibility/"&gt;home office accessibility posters earlier&lt;/a&gt;, the more you can do in your team space to make the problem visible the better. Start putting accessibility design challenges on the wall, calling out accessibility issues (be it bugs or usability) as bugs, tech debt, or features all the starts to put it at the front of people's mind.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tell the story&lt;/strong&gt; - taking the team out on user research with people with access needs is a good way to raise awareness, get buy-in and highlight issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Run a workshop&lt;/strong&gt; - workshops are another great way to build empathy, either using assistive technology (like a screen reader) to navigate your service or you could get a set of &lt;a href="https://vinesimspecs.com/"&gt;vine sim specs&lt;/a&gt; to help simulate issues&lt;br&gt;
Make it part of the process - as developers, we already have parts of our process like unit testing, there is no reason we can't include accessible acceptance criteria.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Get audits&lt;/strong&gt; - reaching out to other teams in your company or even outside to review your service is another way to get great feedback&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Make it open&lt;/strong&gt; - sharing the issues you are having and how you've fixed them is another great way to make it more visible as a team and company and to help other people learn - &lt;a href="https://bulbenergy.github.io/bulb-audit/"&gt;Bulb did a great open accessibility audit&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>a11y</category>
      <category>teamwork</category>
      <category>frontend</category>
    </item>
    <item>
      <title>working with templates</title>
      <dc:creator>Colin Oakley</dc:creator>
      <pubDate>Tue, 21 May 2019 08:08:58 +0000</pubDate>
      <link>https://dev.to/htmlandbacon/working-with-templates-2n32</link>
      <guid>https://dev.to/htmlandbacon/working-with-templates-2n32</guid>
      <description>&lt;p&gt;I've worked with a number of templating engine across different systems which vary quite a lot.&lt;/p&gt;

&lt;p&gt;A lot of the approach you take to building something will depend on the features the engine has.&lt;/p&gt;

&lt;p&gt;Rather than give an overview of the language, I thought I'd talk a little about how to apply some of it.&lt;/p&gt;

&lt;p&gt;I'm going to talk a little about &lt;a href="https://mozilla.github.io/nunjucks/"&gt;nunjucks&lt;/a&gt; - it is feature rich, well supported and has &lt;a href="https://mozilla.github.io/nunjucks/templating.html"&gt;extensive docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For this, I've mashed together some &lt;a href="https://getbootstrap.com/"&gt;bootstrap templates&lt;/a&gt; to make a pretty generic looking website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3nUiKCLB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/oovv8t851zs9jw6iklwl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3nUiKCLB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/oovv8t851zs9jw6iklwl.png" alt="example web page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the &lt;a href="https://github.com/htmlandbacon/nunjucks-example/blob/master/views/pages/full-version.nunjucks"&gt;code on github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With nunjucks there are three features we need to talk about before we start deciding how to start to split up the page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extend&lt;/strong&gt; - this allows us to define a base template, and then override parts of it within the child template. This is known as &lt;a href="https://mozilla.github.io/nunjucks/templating.html#template-inheritance"&gt;template inheritance&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Includes&lt;/strong&gt; - this allows us to pull another template into our current template&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Macro&lt;/strong&gt; - these are functions, you can define a reusable chunk of code. &lt;/p&gt;

&lt;h2&gt;
  
  
  Base template
&lt;/h2&gt;

&lt;p&gt;You would normally hope for more than one page, then you can make a better judgement about what you should turn the elements of the page into, but given the page above, the first part we will work out is a base template&lt;/p&gt;

&lt;p&gt;We will be having one base template that all other pages will extend out of this, in the case above we'd have one with the header and the footer in it.&lt;/p&gt;

&lt;p&gt;This template will have a series of &lt;a href="https://mozilla.github.io/nunjucks/templating.html#block"&gt;blocks&lt;/a&gt; that we can override in a child page - so we will have a &lt;strong&gt;home page&lt;/strong&gt; that &lt;strong&gt;extends&lt;/strong&gt; the &lt;strong&gt;base template&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A block is a named space that can be replaced by the child template.&lt;/p&gt;

&lt;p&gt;If we assume that the header and footer won't need to be replaced then our base template will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
// stuff for header
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
// navigation html

// block: content

//footer html
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Even within this, we have some options, we could already extract the navigation and footer to their own either macros or includes.&lt;/p&gt;

&lt;p&gt;When I look at templating I am looking at how we compose different elements, once we start splitting it down into smaller chunks we start to think about how they are used.&lt;/p&gt;

&lt;p&gt;The aim is to make it more maintainable, though if we over extract then we can be in danger of making it too complex.&lt;/p&gt;

&lt;p&gt;Check out the &lt;a href="https://github.com/htmlandbacon/nunjucks-example/blob/master/views/templates/base-includes.nunjucks"&gt;full base template&lt;/a&gt;, you can see I've moved navigation and footer into includes, this is to isolate them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The home page
&lt;/h2&gt;

&lt;p&gt;We can now create a page by making a file like the one below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight twig"&gt;&lt;code&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="s1"&gt;'templates/base-includes.nunjucks'&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;

&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;pageTitle&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;

&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;


&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;content&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
// home page content lives here
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can now start working out what to do with our home page content, this can be broken down into three parts.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;jumbotron&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;subscription information&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;three column content&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We will assume that all three of these are &lt;a href="https://github.com/htmlandbacon/nunjucks-example/blob/master/views/pages/home-page-includes.nunjucks"&gt;includes for the moment&lt;/a&gt;, these can now be included in new pages, so if we want to make an alternative version change what we include, or if we want to update a section, we are now changing a smaller file.&lt;/p&gt;

&lt;h2&gt;
  
  
  What can we make a macro
&lt;/h2&gt;

&lt;p&gt;The thing that stands out that will work as a macro is the subscription information.&lt;/p&gt;

&lt;p&gt;We have three repeating blocks, if we look at all three we work out what is common so we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight twig"&gt;&lt;code&gt;// classes

// header

// price

// features

// button
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can start by building a macro that takes one parameter - the title, then build up the rest.&lt;/p&gt;

&lt;p&gt;The macro is called priceBox and takes a parameter title, this is then printed in place of the original header.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="nv"&gt;priceBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card mb-3 shadow-sm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h4&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"my-0 font-weight-normal"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endmacro&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To use this we first import it to our other template, and then call it, below is the wrap around include we are using.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="s1"&gt;'../../components/price-box.nunjucks'&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nv"&gt;priceBox&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-deck mb-3 text-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;priceBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Free'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;

    &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;priceBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Pro'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;

    &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;priceBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Enterprise'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There are two ways to import a macro, you can &lt;a href="https://mozilla.github.io/nunjucks/templating.html#import"&gt;read more about import&lt;/a&gt; over at the docs.&lt;/p&gt;

&lt;p&gt;We can now expand our macro to take price, features and buttons.&lt;/p&gt;

&lt;p&gt;Below is an example of an extended version, I've named the variables we are passing in so it makes it a little clearer.&lt;/p&gt;

&lt;p&gt;We can give these defaults in the macro if needed, for this it doesn't really need it.&lt;/p&gt;

&lt;p&gt;Features takes an array of items that we loop over in the macro and button takes an object so we can supply multiple values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight twig"&gt;&lt;code&gt;    &lt;span class="cp"&gt;{{&lt;/span&gt; 
        &lt;span class="nv"&gt;priceBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Free'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'0.00'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;features&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="s1"&gt;'10 users included'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s1"&gt;'2 GB of storage'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="s1"&gt;'Email support'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="s1"&gt;'Help center access'&lt;/span&gt;
                &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="nv"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'Sign up for free'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nv"&gt;classes&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'btn-outline-primary'&lt;/span&gt;
                &lt;span class="err"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Our macro now looks like the below, if no futures are provided then we default the text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="nv"&gt;priceBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;features&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;button&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card mb-3 shadow-sm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h4&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"my-0 font-weight-normal"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-title pricing-card-title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;$&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;price&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;small&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-muted"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;/ mo&lt;span class="nt"&gt;&amp;lt;/small&amp;gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"list-unstyled mt-3 mb-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;feature&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;features&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;feature&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;No features&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-lg btn-block &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;button.classes&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;button.text&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endmacro&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We now have the same page as we started with, but broken down into re-usable chunk, we can now build additional pages.&lt;/p&gt;

&lt;p&gt;Nunjucks also has a number of &lt;a href="https://mozilla.github.io/nunjucks/templating.html#builtin-filters"&gt;built-in filters&lt;/a&gt; you can also extend it to &lt;a href="https://mozilla.github.io/nunjucks/templating.html#filter"&gt;add your own&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>templating</category>
      <category>nunjucks</category>
    </item>
    <item>
      <title>templating - from html to macros</title>
      <dc:creator>Colin Oakley</dc:creator>
      <pubDate>Tue, 02 Jan 2018 21:15:24 +0000</pubDate>
      <link>https://dev.to/htmlandbacon/templating---from-html-to-macros-20co</link>
      <guid>https://dev.to/htmlandbacon/templating---from-html-to-macros-20co</guid>
      <description>&lt;p&gt;Whenever I am pairing with other developers we always seem to hit a similar topic; abstraction.&lt;/p&gt;

&lt;p&gt;There is ever a clear-cut answer to that question, as it requires the context of the code and the state of the application.&lt;/p&gt;

&lt;p&gt;Overly abstracted code can make changing it difficult and hard to comprehend whereas no abstraction can lead to bloat and repetition.&lt;/p&gt;

&lt;p&gt;Below is an example of a &lt;a href="https://govuk-elements.herokuapp.com/form-elements/#ni-number"&gt;text input&lt;/a&gt; form GOV.UK Elements.&lt;/p&gt;

&lt;p&gt;The examples below use &lt;a href="https://mozilla.github.io/nunjucks/templating.html"&gt;nunjucks&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-group"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-label"&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"ni-number"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        National Insurance number
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-hint"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            It's on your National Insurance card, benefit letter, payslip or P60.
      &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"ni-number"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"ni-number"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Form elements always seem a very clear example of where we should do an abstraction - they have set structure and usually are used multiple times on a site.&lt;/p&gt;

&lt;p&gt;When we look at making a reusable form element, we do it with the composition of the makeup of our HTML in mind.&lt;/p&gt;

&lt;p&gt;There are a couple ways we could break this out, the first would be so that each of the parts of the code would have its own macro - this would mean each part would be usable within other form elements.&lt;/p&gt;

&lt;p&gt;This would look like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;form-group wrapper&lt;/li&gt;
&lt;li&gt;label&lt;/li&gt;
&lt;li&gt;input&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using nunjucks we'd end up with something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="nv"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt; 
        &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; 
        &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
        &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endmacro&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;

&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-label"&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;for&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-hint"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;hint&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endmacro&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would allow us to compose our UI like this,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;"forms.html"&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nv"&gt;field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-group"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ni-number'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="s1"&gt;'National Insurance number'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'It\'s on your National Insurance card, bene...'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;

    &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ni-number'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="s1"&gt;'ni-number'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nv"&gt;niNumberValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows label and field to be composed to produce other form elements, they could also be wrapped in another function to produce a form element, I'll come to this later. We could also look at moving the form-group div to a macro.&lt;/p&gt;

&lt;p&gt;This could also be done as a single macro.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="nv"&gt;textInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-group"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-label"&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-hint"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;hint&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt; 
        &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; 
        &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
        &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endmacro&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This encapsulates both the previous macros in one call, this makes it less composable but also has the full element. &lt;/p&gt;

&lt;p&gt;The second method will quickly become bloated if we need to add on additional options for example styling, input type or additional HTML properties.&lt;/p&gt;

&lt;p&gt;We could also make a hybrid of the two methods, though as we start to do multiple layers we start to make our code less readable and we need to be more mindful when we make changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="nv"&gt;textInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-group"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt; 
        &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; 
        &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
        &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endmacro&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This in hindsight feels like the right balance, textInput is encapsulated but the label can be re-used across different macros.&lt;/p&gt;

&lt;p&gt;My final macro has the following inputs&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;name&lt;/td&gt;
&lt;td&gt;sets the name of the input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;id&lt;/td&gt;
&lt;td&gt;sets the id of the input, and the for of the label&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;label&lt;/td&gt;
&lt;td&gt;sets the text of the label&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hint&lt;/td&gt;
&lt;td&gt;sets hint text within the label&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;value&lt;/td&gt;
&lt;td&gt;sets the value of the input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;error&lt;/td&gt;
&lt;td&gt;sets the error message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;maxlength&lt;/td&gt;
&lt;td&gt;sets the max length of the input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;classes&lt;/td&gt;
&lt;td&gt;object used for styling elements&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This has various states, including optional fields and error states. This after a couple of iterations seemed like the right level of abstraction in the application context, though I think there is more to do with moving the label to its own macro and being called within the element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;macro&lt;/span&gt; &lt;span class="nv"&gt;textInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;maxlength&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
        &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"input-"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;-form"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-group&lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;error&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="s"&gt; form-group-error&lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;classes.label&lt;/span&gt; &lt;span class="cp"&gt;%}{{&lt;/span&gt; &lt;span class="nv"&gt;classes.label&lt;/span&gt; &lt;span class="cp"&gt;}}{%&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="s"&gt;form-label-bold&lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
            &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;hint&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-hint"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;hint&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
            &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;error&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"error-message"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;error&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt; &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
            &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control&lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;classes.input&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;classes.input&lt;/span&gt; &lt;span class="cp"&gt;}}{%&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
            &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
            &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;maxlength&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt; &lt;span class="na"&gt;maxlength=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;maxlength&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
            &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
            &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
            &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whenever you make a deliberate decision to try and make re-useable code there is always going to be a trade-off in functionality, readability, and maintenance.&lt;/p&gt;

&lt;p&gt;Keeping things self-contained gives the ability to refactor it later with minimal change.&lt;/p&gt;

&lt;p&gt;Feel free to add how you'd do this, or message me on &lt;a href="http://twitter.com/htmlandbacon"&gt;twitter&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://codepen.io/htmlandbacon/full/jmoPyP/"&gt;live template render&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://govuk-elements.herokuapp.com/"&gt;GOV.UK Elements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/govuk-elements-nunjucks"&gt;nunjucks elements&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nunjucks</category>
      <category>abstraction</category>
      <category>javascript</category>
      <category>templating</category>
    </item>
  </channel>
</rss>
