Skip to main content

Summary

A summary presents a clear summarised output of values to the user.

<div class="summary">
  <div class="summary__group">
    <h2 class="summary__group-title">Turnover</h2>
    <table class="summary__items">
      <thead class="u-vh">
        <tr>
          <th>Question</th>
          <th>Answer given</th>
          <th>Change answer</th>
        </tr>
      </thead>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">What are the dates of the sales period you are reporting for? </div>
          </td>
          <td class="summary__values">
            1 January 2015 to 2 February 2017
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change answer">Change</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">For the period 1 January 2015 to 2 February 2017, what was the value of your total turnover, excluding VAT? </div>
          </td>
          <td class="summary__values">
            £180,440
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change answer">Change</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Please indicate the reasons for any changes in the total turnover </div>
          </td>
          <td class="summary__values">
            <ul class="u-mb-no">
              <li>
                Change in level of business activity
              </li>
              <li>
                Special/calendar events
                <ul class="u-mb-no">
                  <li>Some other value</li>
                </ul>
              </li>
            </ul>
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change answer">Change</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Please describe the changes in total turnover in more detail </div>
          </td>
          <td class="summary__values">
            Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change answer">Change</a>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
Nunjucks macro options
Name Type Required Description
summaries Array<Summaries> true An array of summaries
classes string false Classes to add to the summary component
hub boolean false Whether to render the summary in as a hub

Summaries

Name Type Required Description
groups Array<SummaryGroup> true An array of groups within a summary
summaryTitle string false The title for a group of summaries

SummaryGroup

Name Type Required Description
rows Array<SummaryRows> false An array of rows within a group
placeholderText string false A message to be shown as a placeholder if there are no rows in the summary
groupTitle string false The title for a summary within a group
headers Array<SummaryHeaders> false An array of headers to describe the data in the summary
summaryLink Array<SummaryLink> false Settings for the link to apear after the summary

SummaryRow

Name Type Required Description
rowItems Array<SummaryRowItem> true An array of items for this row
rowtitle string false The title for the row
rowTitleAttributes object false HTML attributes (for example data attributes) to add to the rowTitle
error boolean false Whether to render this item as an error
errorMessage string false Error message for the row
total boolean false Whether to render this item as a total

SummaryRowItem

Name Type Required Description
icon string false Name of the icon to be placed next to the title
title string false Label for the row item
valueList Array<SummaryValue> false The value(s) to the row item
actions Array<SummaryAction> false Configurations for action links. If not specified no links will render
attributes object false HTML attributes (for example data attributes) to add to the row item

SummaryValue

Name Type Required Description
text string true The display value
other string false The display value for the “other” input on a checkbox or radio

SummaryAction

Name Type Required Description
text string true Text for the action link
url string true URL to edit the answer
ariaLabel string false An aria-label to apply to the link if you need it to be more verbose for screen readers
attributes object false HTML attributes (for example data attributes) to add to the action link
Name Type Required Description
url string true The url for the link to follow the summary
text string true The text for the link to follow the summary
attributes object false HTML attributes (for example data attributes) to add to the summary link
{% from "components/summary/_macro.njk" import onsSummary %}
{{
  onsSummary({
    "summaries": [
            {
                "groups": [
                    {
                    "groupTitle": "Turnover",
                    "headers":["Question", "Answer given", "Change answer"],
                    "rows": [
                        {
                            "rowTitle": "What are the dates of the sales period you are reporting for?",
                            "rowItems": [
                                {
                                    "valueList": [
                                        {
                                            "text": "1 January 2015 to 2 February 2017"
                                        }
                                    ],
                                    "actions": [
                                        {
                                            "text": "Change",
                                            "ariaLabel": "Change answer",
                                            "url": "#"
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            "rowTitle": "For the period 1 January 2015 to 2 February 2017, what was the value of your total turnover, excluding VAT?",
                            "rowItems": [
                                {
                                    "valueList": [
                                        {
                                            "text": "£180,440"
                                        }
                                    ],
                                    "actions": [
                                        {
                                            "text": "Change",
                                            "ariaLabel": "Change answer",
                                            "url": "#"
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            "rowTitle": "Please indicate the reasons for any changes in the total turnover",
                            "rowItems": [
                                {
                                    "valueList": [
                                        {
                                            "text": "Change in level of business activity"
                                        },
                                        {
                                            "text": "Special/calendar events",
                                            "other": "Some other value"
                                        }
                                    ],
                                    "actions": [
                                        {
                                            "text": "Change",
                                            "ariaLabel": "Change answer",
                                            "url": "#"
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            "rowTitle": "Please describe the changes in total turnover in more detail",
                            "rowItems": [
                                {
                                    "valueList": [
                                        {
                                            "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
                                        }
                                    ],
                                    "actions": [
                                        {
                                            "text": "Change",
                                            "ariaLabel": "Change answer",
                                            "url": "#"
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ]
  })
}}

{% macro onsSummary(params) %}
    {% set className = "summary" %}
    {% set titleSize = "2" %}
    {% if params.classes is defined and params.classes %}
         {% set className = className + " " + params.classes %}
    {% endif %}
    {% if params.hub is defined and params.hub %}
        {% set className = className + " summary--hub" %}
    {% endif %}
    <div class="{{ className }}">
        {% for summary in params.summaries %}
            <div class="summary__group">
                {% if summary.summaryTitle is defined and summary.summaryTitle %}
                    <h2 class="summary__title u-mb-m">{{ summary.summaryTitle }}</h2>
                    {% set titleSize = "3" %}
                {% endif %}
                {% for group in summary.groups %}
                    {% if group.groupTitle is defined and group.groupTitle %}
                        <h{{ titleSize }} class="summary__group-title">{{ group.groupTitle }}</h{{ titleSize }}>
                    {% endif %}
                    {% if group.rows is defined and group.rows %}
                        <table class="summary__items">
                            {% if group.headers is defined and group.headers %}
                                <thead class="u-vh">
                                    <tr>
                                        {% for header in group.headers %}
                                            <th>{{ header }}</th>
                                        {% endfor %}
                                    </tr>
                                </thead>
                            {% endif %}
                            {% for row in (group.rows if group.rows is iterable else group.rows.items()) %}
                                {% set itemClass = "" %}
                                {% if row.error is defined and row.error %} {% set itemClass = " summary__item--error" %}{% endif %}
                                {% if row.total is defined and row.total %} {% set itemClass = itemClass + " summary__item--total" %}{% endif %}
                                <tbody class="summary__item{{ itemClass }}">
                                    {% if row.errorMessage is defined and row.errorMessage or (row.rowItems | length > 1 and row.rowTitle) %}
                                        <tr class="summary__row">
                                            <th colspan="3" class="summary__row-title u-fs-r">{{ row.errorMessage or row.rowTitle }}</th>
                                        </tr>
                                    {% endif %}
                                    {% for rowItem in row.rowItems %}
                                        <tr class="summary__row{{ " summary__row--has-values" if rowItem.valueList else "" }}">
                                            <td
                                                class="summary__item-title"
                                                {% if rowItem.rowTitleAttributes is defined and rowItem.rowTitleAttributes %}{% for attribute, value in (rowItem.rowTitleAttributes.items() if rowItem.rowTitleAttributes is mapping and rowItem.rowTitleAttributes.items else rowItem.rowTitleAttributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                            >
                                                {% if rowItem.icon is defined and rowItem.icon %}
                                                    {% from "components/icons/_macro.njk" import onsIcon %}
                                                    <span class= "summary__item-title-icon {% if rowItem.icon == 'check' %} summary__item-title-icon--check{% endif %}">
                                                        {{
                                                            onsIcon({
                                                                "icon": rowItem.icon
                                                            })
                                                        }}
                                                    </span>
                                                {% endif %}
                                                <div class="summary__item--text{{ ' summary__item-title--text' if rowItem.icon else "" }}">{{ rowItem.rowTitle | default(row.rowTitle) | safe }} {{ hasIcons }}</div>
                                                {# Render section status for mobile if is hub #}
                                                {% if params.hub is defined and params.hub and rowItem.valueList is defined and rowItem.valueList %}
                                                    <span class="u-d-no@s u-fs-r"> — {{ rowItem.valueList[0].text | safe }}</span>
                                                {% endif %}
                                            </td>
                                            {% if rowItem.valueList is defined and rowItem.valueList %}
                                                <td
                                                    class="summary__values"
                                                    {% if rowItem.actions == null %} colspan="2"{% endif %}
                                                    {% if rowItem.attributes is defined and rowItem.attributes %}{% for attribute, value in (rowItem.attributes.items() if rowItem.attributes is mapping and rowItem.attributes.items else rowItem.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                >
                                                    {% if rowItem.valueList | length == 1 %}
                                                        {{ rowItem.valueList[0].text | safe }}
                                                        {% if rowItem.valueList[0].other is defined and rowItem.valueList[0].other or rowItem.valueList[0].other == 0 %}
                                                            <ul class="u-mb-no">
                                                                <li>{{ rowItem.valueList[0].other | safe }}</li>
                                                            </ul>
                                                        {% endif %}
                                                    {% else %}
                                                        <ul class="u-mb-no">
                                                            {% for value in (rowItem.valueList if rowItem.valueList is iterable else rowItem.valueList.items()) %}
                                                                <li>
                                                                    {{ value.text | safe }}
                                                                    {% if value.other is defined and value.other or value.other == 0 %}
                                                                        <ul class="u-mb-no">
                                                                            <li>{{ value.other | safe }}</li>
                                                                        </ul>
                                                                    {% endif %}
                                                                </li>
                                                            {% endfor %}
                                                        </ul>
                                                    {% endif %}
                                                </td>
                                            {% endif %}
                                            {% if rowItem.actions is defined and rowItem.actions %}
                                                <td class="summary__actions">
                                                    {% for action in (rowItem.actions if rowItem.actions is iterable else rowItem.actions.items()) %}
                                                        {% if loop.index > 1 %}<span class="summary__spacer"></span>{% endif %}
                                                        <a
                                                            href="{{ action.url }}"
                                                            class="summary__button"
                                                            {% if action.ariaLabel is defined and action.ariaLabel %} aria-label="{{ action.ariaLabel }}"{% endif %}
                                                            {% if action.attributes is defined and action.attributes %}{% for attribute, value in (action.attributes.items() if action.attributes is mapping and action.attributes.items else action.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                        >{{ action.text }}</a>
                                                    {% endfor %}
                                                </td>
                                            {% endif %}
                                        </tr>
                                    {% endfor %}
                                </tbody>
                            {% endfor %}
                        </table>
                    {% elif group.placeholderText is defined and group.placeholderText %}
                        {{ group.placeholderText }}
                    {% endif %}
                    {% if group.summaryLink is defined and group.summaryLink %}
                        <div class="{% if group.placeholderText is defined and group.placeholderText or group.rows is defined and group.rows %}u-pt-s{% endif %}{% if group.placeholderText is not defined and group.rows is defined and group.rows | length > 1 %} u-bt{% endif %}">
                            <a {% if group.summaryLink.attributes is defined and group.summaryLink.attributes %}{% for attribute, value in (group.summaryLink.attributes.items() if group.summaryLink.attributes is mapping and group.summaryLink.attributes.items else group.summaryLink.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %} href="{{ group.summaryLink.url }}">{{ group.summaryLink.text }}</a>
                        </div>
                    {% endif %}
                {% endfor %}
            </div>
        {% endfor %}
    </div>
{% endmacro %}

$summary-row-spacing: 1rem;
$summary-col-spacing: 1rem;
$hub-row-spacing: 1.3rem;
.summary {
  &__items {
    border-collapse: collapse;
    border-spacing: 0;
    width: 100%;
    + .summary__group-title {
      margin-top: 1.5rem;
    }
  }
  &__item {
    line-height: 1.4;
    &:not(:last-child),
    &:nth-of-type(1) {
      border-bottom: 1px solid $color-borders;
    }
    &--total {
      @extend .u-fs-m;
      border-width: 2px;
      font-weight: 700;
    }
    &--error {
      background: $color-errors-tint;
      border-left: 8px solid $color-errors;
    }
  }
  &__row-title {
    padding: $summary-row-spacing 0;
    text-align: left;
  }
  &__item-title,
  &__values,
  &__actions {
    hyphens: manual;
    overflow-wrap: break-word;
    padding: 0 0 $summary-row-spacing;
    vertical-align: top;
    word-wrap: break-word;
  }
  &__item-title {
    padding-top: $summary-row-spacing;
    position: relative;
    &--text {
      display: block;
      overflow: hidden;
      padding-left: 2rem;
    }
    &-icon {
      left: 0;
      position: absolute;
      text-align: center;
      &--check {
        fill: $color-leaf-green;
      }
    }
  }
  &__actions {
    white-space: nowrap;
  }
  &__spacer {
    background: $color-black;
    display: inline-block;
    height: 1rem;
    margin: 0 0.25rem;
    vertical-align: middle;
    width: 1px;
  }
  // Item Modifiers
  &__item--total & {
    &__values {
      @extend .u-fs-m;
    }
  }
  &__item--error & {
    &__row-title {
      color: $color-errors;
      font-weight: 700;
      padding: $summary-row-spacing $summary-col-spacing;
    }
    &__item-title,
    &__values,
    &__actions {
      padding-left: $summary-col-spacing;
      padding-right: $summary-col-spacing;
      @include mq('s') {
        padding-left: $summary-col-spacing / 2;
        padding-right: $summary-col-spacing / 2;
        &:first-child {
          padding-left: $summary-col-spacing;
        }
        &:last-child {
          padding-right: $summary-col-spacing;
        }
      }
    }
  }
  // Modifiers
  &--hub & {
    &__actions {
      padding: 0 0 $hub-row-spacing;
    }
    &__item-title {
      @extend .u-fs-r--b;
      padding-top: $hub-row-spacing;
    }
  }
  &:not(&--hub) & {
    &__values {
      @extend .u-fs-r--b;
    }
  }
  // Breakpoints
  @include mq(xxs, s, none, '<') {
    &__item-title,
    &__values,
    &__actions {
      display: block;
    }
    &--hub & {
      &__values {
        display: none;
      }
    }
  }
  @include mq(s) {
    &__item-title,
    &__values,
    &__actions {
      padding-top: $summary-row-spacing;
      vertical-align: top;
      &:not(:last-child) {
        padding-right: $summary-col-spacing;
      }
    }
    &__actions {
      text-align: right;
    }
    &__row--has-values & {
      &__item-title,
      &__values {
        width: 50%;
      }
    }
    &--hub & {
      &__item-title,
      &__values,
      &__actions {
        padding-top: $hub-row-spacing;
      }
    }
  }
}

When to use this component

Display a summary on a page after the user completes a section or full questionnaire, to let them check and confirm their answers.

How to use this component

The summary should provide users with a direct link back to the question(s) they have answered, allowing them to change their answer, then return to the summary to complete or continue their questionnaire.

The summary can contain multiple question and answer types, and will adapt it’s layout depending on the length of the strings.

The component contains a summaries key which can contain multiple summary groups. This allows for multipe summaries to be displayed. Each group in groups can have an optional groupTitle which provides a heading for the rows and renders a h2. This provides flexibility to allow for simple and complex summaries to be created within one instance of the onsSummary macro.

Accessibility

The summary component is made accessible by using the following aria attributes which are attached on domready via JavaScript:

Element ARIA attribute Description
summary__button aria-label="{ariaLabel}" Increases verbosity of the element's label

Variants

Summary without action

A summary of an answer the user cannot directly change, due to it being automatically calculated.

<div class="summary">
  <div class="summary__group">
    <h2 class="summary__group-title">Turnover</h2>
    <table class="summary__items">
      <thead class="u-vh">
        <tr>
          <th>Question</th>
          <th>Answer given</th>
        </tr>
      </thead>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">What are the dates of the sales period you are reporting for? </div>
          </td>
          <td class="summary__values" colspan="2">
            01 January 2015 to 02 February 2017
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Total turnover </div>
          </td>
          <td class="summary__values" colspan="2">
            £234,000.00
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
Nunjucks macro options
Name Type Required Description
summaries Array<Summaries> true An array of summaries
classes string false Classes to add to the summary component
hub boolean false Whether to render the summary in as a hub

Summaries

Name Type Required Description
groups Array<SummaryGroup> true An array of groups within a summary
summaryTitle string false The title for a group of summaries

SummaryGroup

Name Type Required Description
rows Array<SummaryRows> false An array of rows within a group
placeholderText string false A message to be shown as a placeholder if there are no rows in the summary
groupTitle string false The title for a summary within a group
headers Array<SummaryHeaders> false An array of headers to describe the data in the summary
summaryLink Array<SummaryLink> false Settings for the link to apear after the summary

SummaryRow

Name Type Required Description
rowItems Array<SummaryRowItem> true An array of items for this row
rowtitle string false The title for the row
rowTitleAttributes object false HTML attributes (for example data attributes) to add to the rowTitle
error boolean false Whether to render this item as an error
errorMessage string false Error message for the row
total boolean false Whether to render this item as a total

SummaryRowItem

Name Type Required Description
icon string false Name of the icon to be placed next to the title
title string false Label for the row item
valueList Array<SummaryValue> false The value(s) to the row item
actions Array<SummaryAction> false Configurations for action links. If not specified no links will render
attributes object false HTML attributes (for example data attributes) to add to the row item

SummaryValue

Name Type Required Description
text string true The display value
other string false The display value for the “other” input on a checkbox or radio

SummaryAction

Name Type Required Description
text string true Text for the action link
url string true URL to edit the answer
ariaLabel string false An aria-label to apply to the link if you need it to be more verbose for screen readers
attributes object false HTML attributes (for example data attributes) to add to the action link
Name Type Required Description
url string true The url for the link to follow the summary
text string true The text for the link to follow the summary
attributes object false HTML attributes (for example data attributes) to add to the summary link
{% from "components/summary/_macro.njk" import onsSummary %}
{{
    onsSummary({
        "summaries": [
            {
                "groups": [
                    {
                        "groupTitle": "Turnover",
                        "headers":["Question", "Answer given"],
                        "rows": [
                            {
                                "rowTitle": "What are the dates of the sales period you are reporting for?",
                                "rowItems": [
                                    {
                                        "valueList": [
                                            {
                                                "text": "01 January 2015 to 02 February 2017"
                                            }
                                        ]
                                    }
                                ]
                            },
                            {
                                "rowTitle": "Total turnover",
                                "rowItems": [
                                    {
                                        "valueList": [
                                            {
                                                "text": "£234,000.00"
                                            }
                                        ]
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        ]
    })
}}

{% macro onsSummary(params) %}
    {% set className = "summary" %}
    {% set titleSize = "2" %}
    {% if params.classes is defined and params.classes %}
         {% set className = className + " " + params.classes %}
    {% endif %}
    {% if params.hub is defined and params.hub %}
        {% set className = className + " summary--hub" %}
    {% endif %}
    <div class="{{ className }}">
        {% for summary in params.summaries %}
            <div class="summary__group">
                {% if summary.summaryTitle is defined and summary.summaryTitle %}
                    <h2 class="summary__title u-mb-m">{{ summary.summaryTitle }}</h2>
                    {% set titleSize = "3" %}
                {% endif %}
                {% for group in summary.groups %}
                    {% if group.groupTitle is defined and group.groupTitle %}
                        <h{{ titleSize }} class="summary__group-title">{{ group.groupTitle }}</h{{ titleSize }}>
                    {% endif %}
                    {% if group.rows is defined and group.rows %}
                        <table class="summary__items">
                            {% if group.headers is defined and group.headers %}
                                <thead class="u-vh">
                                    <tr>
                                        {% for header in group.headers %}
                                            <th>{{ header }}</th>
                                        {% endfor %}
                                    </tr>
                                </thead>
                            {% endif %}
                            {% for row in (group.rows if group.rows is iterable else group.rows.items()) %}
                                {% set itemClass = "" %}
                                {% if row.error is defined and row.error %} {% set itemClass = " summary__item--error" %}{% endif %}
                                {% if row.total is defined and row.total %} {% set itemClass = itemClass + " summary__item--total" %}{% endif %}
                                <tbody class="summary__item{{ itemClass }}">
                                    {% if row.errorMessage is defined and row.errorMessage or (row.rowItems | length > 1 and row.rowTitle) %}
                                        <tr class="summary__row">
                                            <th colspan="3" class="summary__row-title u-fs-r">{{ row.errorMessage or row.rowTitle }}</th>
                                        </tr>
                                    {% endif %}
                                    {% for rowItem in row.rowItems %}
                                        <tr class="summary__row{{ " summary__row--has-values" if rowItem.valueList else "" }}">
                                            <td
                                                class="summary__item-title"
                                                {% if rowItem.rowTitleAttributes is defined and rowItem.rowTitleAttributes %}{% for attribute, value in (rowItem.rowTitleAttributes.items() if rowItem.rowTitleAttributes is mapping and rowItem.rowTitleAttributes.items else rowItem.rowTitleAttributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                            >
                                                {% if rowItem.icon is defined and rowItem.icon %}
                                                    {% from "components/icons/_macro.njk" import onsIcon %}
                                                    <span class= "summary__item-title-icon {% if rowItem.icon == 'check' %} summary__item-title-icon--check{% endif %}">
                                                        {{
                                                            onsIcon({
                                                                "icon": rowItem.icon
                                                            })
                                                        }}
                                                    </span>
                                                {% endif %}
                                                <div class="summary__item--text{{ ' summary__item-title--text' if rowItem.icon else "" }}">{{ rowItem.rowTitle | default(row.rowTitle) | safe }} {{ hasIcons }}</div>
                                                {# Render section status for mobile if is hub #}
                                                {% if params.hub is defined and params.hub and rowItem.valueList is defined and rowItem.valueList %}
                                                    <span class="u-d-no@s u-fs-r"> — {{ rowItem.valueList[0].text | safe }}</span>
                                                {% endif %}
                                            </td>
                                            {% if rowItem.valueList is defined and rowItem.valueList %}
                                                <td
                                                    class="summary__values"
                                                    {% if rowItem.actions == null %} colspan="2"{% endif %}
                                                    {% if rowItem.attributes is defined and rowItem.attributes %}{% for attribute, value in (rowItem.attributes.items() if rowItem.attributes is mapping and rowItem.attributes.items else rowItem.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                >
                                                    {% if rowItem.valueList | length == 1 %}
                                                        {{ rowItem.valueList[0].text | safe }}
                                                        {% if rowItem.valueList[0].other is defined and rowItem.valueList[0].other or rowItem.valueList[0].other == 0 %}
                                                            <ul class="u-mb-no">
                                                                <li>{{ rowItem.valueList[0].other | safe }}</li>
                                                            </ul>
                                                        {% endif %}
                                                    {% else %}
                                                        <ul class="u-mb-no">
                                                            {% for value in (rowItem.valueList if rowItem.valueList is iterable else rowItem.valueList.items()) %}
                                                                <li>
                                                                    {{ value.text | safe }}
                                                                    {% if value.other is defined and value.other or value.other == 0 %}
                                                                        <ul class="u-mb-no">
                                                                            <li>{{ value.other | safe }}</li>
                                                                        </ul>
                                                                    {% endif %}
                                                                </li>
                                                            {% endfor %}
                                                        </ul>
                                                    {% endif %}
                                                </td>
                                            {% endif %}
                                            {% if rowItem.actions is defined and rowItem.actions %}
                                                <td class="summary__actions">
                                                    {% for action in (rowItem.actions if rowItem.actions is iterable else rowItem.actions.items()) %}
                                                        {% if loop.index > 1 %}<span class="summary__spacer"></span>{% endif %}
                                                        <a
                                                            href="{{ action.url }}"
                                                            class="summary__button"
                                                            {% if action.ariaLabel is defined and action.ariaLabel %} aria-label="{{ action.ariaLabel }}"{% endif %}
                                                            {% if action.attributes is defined and action.attributes %}{% for attribute, value in (action.attributes.items() if action.attributes is mapping and action.attributes.items else action.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                        >{{ action.text }}</a>
                                                    {% endfor %}
                                                </td>
                                            {% endif %}
                                        </tr>
                                    {% endfor %}
                                </tbody>
                            {% endfor %}
                        </table>
                    {% elif group.placeholderText is defined and group.placeholderText %}
                        {{ group.placeholderText }}
                    {% endif %}
                    {% if group.summaryLink is defined and group.summaryLink %}
                        <div class="{% if group.placeholderText is defined and group.placeholderText or group.rows is defined and group.rows %}u-pt-s{% endif %}{% if group.placeholderText is not defined and group.rows is defined and group.rows | length > 1 %} u-bt{% endif %}">
                            <a {% if group.summaryLink.attributes is defined and group.summaryLink.attributes %}{% for attribute, value in (group.summaryLink.attributes.items() if group.summaryLink.attributes is mapping and group.summaryLink.attributes.items else group.summaryLink.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %} href="{{ group.summaryLink.url }}">{{ group.summaryLink.text }}</a>
                        </div>
                    {% endif %}
                {% endfor %}
            </div>
        {% endfor %}
    </div>
{% endmacro %}

$summary-row-spacing: 1rem;
$summary-col-spacing: 1rem;
$hub-row-spacing: 1.3rem;
.summary {
  &__items {
    border-collapse: collapse;
    border-spacing: 0;
    width: 100%;
    + .summary__group-title {
      margin-top: 1.5rem;
    }
  }
  &__item {
    line-height: 1.4;
    &:not(:last-child),
    &:nth-of-type(1) {
      border-bottom: 1px solid $color-borders;
    }
    &--total {
      @extend .u-fs-m;
      border-width: 2px;
      font-weight: 700;
    }
    &--error {
      background: $color-errors-tint;
      border-left: 8px solid $color-errors;
    }
  }
  &__row-title {
    padding: $summary-row-spacing 0;
    text-align: left;
  }
  &__item-title,
  &__values,
  &__actions {
    hyphens: manual;
    overflow-wrap: break-word;
    padding: 0 0 $summary-row-spacing;
    vertical-align: top;
    word-wrap: break-word;
  }
  &__item-title {
    padding-top: $summary-row-spacing;
    position: relative;
    &--text {
      display: block;
      overflow: hidden;
      padding-left: 2rem;
    }
    &-icon {
      left: 0;
      position: absolute;
      text-align: center;
      &--check {
        fill: $color-leaf-green;
      }
    }
  }
  &__actions {
    white-space: nowrap;
  }
  &__spacer {
    background: $color-black;
    display: inline-block;
    height: 1rem;
    margin: 0 0.25rem;
    vertical-align: middle;
    width: 1px;
  }
  // Item Modifiers
  &__item--total & {
    &__values {
      @extend .u-fs-m;
    }
  }
  &__item--error & {
    &__row-title {
      color: $color-errors;
      font-weight: 700;
      padding: $summary-row-spacing $summary-col-spacing;
    }
    &__item-title,
    &__values,
    &__actions {
      padding-left: $summary-col-spacing;
      padding-right: $summary-col-spacing;
      @include mq('s') {
        padding-left: $summary-col-spacing / 2;
        padding-right: $summary-col-spacing / 2;
        &:first-child {
          padding-left: $summary-col-spacing;
        }
        &:last-child {
          padding-right: $summary-col-spacing;
        }
      }
    }
  }
  // Modifiers
  &--hub & {
    &__actions {
      padding: 0 0 $hub-row-spacing;
    }
    &__item-title {
      @extend .u-fs-r--b;
      padding-top: $hub-row-spacing;
    }
  }
  &:not(&--hub) & {
    &__values {
      @extend .u-fs-r--b;
    }
  }
  // Breakpoints
  @include mq(xxs, s, none, '<') {
    &__item-title,
    &__values,
    &__actions {
      display: block;
    }
    &--hub & {
      &__values {
        display: none;
      }
    }
  }
  @include mq(s) {
    &__item-title,
    &__values,
    &__actions {
      padding-top: $summary-row-spacing;
      vertical-align: top;
      &:not(:last-child) {
        padding-right: $summary-col-spacing;
      }
    }
    &__actions {
      text-align: right;
    }
    &__row--has-values & {
      &__item-title,
      &__values {
        width: 50%;
      }
    }
    &--hub & {
      &__item-title,
      &__values,
      &__actions {
        padding-top: $hub-row-spacing;
      }
    }
  }
}

Grouped

A summary of the answers to multiple questions in a section that are grouped. In this sceanrio we can create another heading level for groups using the summaryTitle key which renders a h2 and renders the groupTitle as a h3.

<h1>Your answers</h1>
<div class="summary">
  <div class="summary__group">
    <h2 class="summary__title u-mb-m">John Doe</h2>
    <h3 class="summary__group-title">Personal details</h3>
    <table class="summary__items">
      <thead class="u-vh">
        <tr>
          <th>Question</th>
          <th>Answer given</th>
        </tr>
      </thead>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Are you John Doe? </div>
          </td>
          <td class="summary__values" colspan="2">
            Yes I am
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">What's your date of birth? </div>
          </td>
          <td class="summary__values" colspan="2">
            1 January 1981
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">What is your sex? </div>
          </td>
          <td class="summary__values" colspan="2">
            Male
          </td>
        </tr>
      </tbody>
    </table>
    <h3 class="summary__group-title">Identity and health</h3>
    <table class="summary__items">
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">What is your country of birth? </div>
          </td>
          <td class="summary__values" colspan="2">
            England
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">What passports do you hold? </div>
          </td>
          <td class="summary__values" colspan="2">
            United Kingdom
          </td>
        </tr>
      </tbody>
    </table>
    <h3 class="summary__group-title">Qualifications</h3>
    <table class="summary__items">
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Have you completed an apprenticeship? </div>
          </td>
          <td class="summary__values" colspan="2">
            Yes
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Have you achieved a GCSE or equivalent qualification? </div>
          </td>
          <td class="summary__values" colspan="2">
            5 GCSEs grades A* to C or 9 to 4
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
Nunjucks macro options
Name Type Required Description
summaries Array<Summaries> true An array of summaries
classes string false Classes to add to the summary component
hub boolean false Whether to render the summary in as a hub

Summaries

Name Type Required Description
groups Array<SummaryGroup> true An array of groups within a summary
summaryTitle string false The title for a group of summaries

SummaryGroup

Name Type Required Description
rows Array<SummaryRows> false An array of rows within a group
placeholderText string false A message to be shown as a placeholder if there are no rows in the summary
groupTitle string false The title for a summary within a group
headers Array<SummaryHeaders> false An array of headers to describe the data in the summary
summaryLink Array<SummaryLink> false Settings for the link to apear after the summary

SummaryRow

Name Type Required Description
rowItems Array<SummaryRowItem> true An array of items for this row
rowtitle string false The title for the row
rowTitleAttributes object false HTML attributes (for example data attributes) to add to the rowTitle
error boolean false Whether to render this item as an error
errorMessage string false Error message for the row
total boolean false Whether to render this item as a total

SummaryRowItem

Name Type Required Description
icon string false Name of the icon to be placed next to the title
title string false Label for the row item
valueList Array<SummaryValue> false The value(s) to the row item
actions Array<SummaryAction> false Configurations for action links. If not specified no links will render
attributes object false HTML attributes (for example data attributes) to add to the row item

SummaryValue

Name Type Required Description
text string true The display value
other string false The display value for the “other” input on a checkbox or radio

SummaryAction

Name Type Required Description
text string true Text for the action link
url string true URL to edit the answer
ariaLabel string false An aria-label to apply to the link if you need it to be more verbose for screen readers
attributes object false HTML attributes (for example data attributes) to add to the action link
Name Type Required Description
url string true The url for the link to follow the summary
text string true The text for the link to follow the summary
attributes object false HTML attributes (for example data attributes) to add to the summary link
{% from "components/summary/_macro.njk" import onsSummary %}
<h1>Your answers</h1>
{{
    onsSummary({
        "summaries": [
            {
                "summaryTitle": "John Doe",
                "groups": [
                    {
                        "groupTitle": "Personal details",
                        "headers":["Question", "Answer given"],
                        "rows": [
                            {
                                "rowTitle": "Are you John Doe?",
                                "rowItems": [
                                    {
                                        "valueList": [
                                            {
                                                "text": "Yes I am"
                                            }
                                        ]
                                    }
                                ]
                            },
                            {
                                "rowTitle": "What's your date of birth?",
                                "rowItems": [
                                    {
                                        "valueList": [
                                            {
                                                "text": "1 January 1981"
                                            }
                                        ]
                                    }
                                ]
                            },
                            {
                                "rowTitle": "What is your sex?",
                                "rowItems": [
                                    {
                                        "valueList": [
                                            {
                                                "text": "Male"
                                            }
                                        ]
                                    }
                                ]
                            }
                        ]
                    },
                    {
                        "groupTitle": "Identity and health",
                        "rows": [
                            {
                                "rowTitle": "What is your country of birth?",
                                "rowItems": [
                                    {
                                        "valueList": [
                                            {
                                                "text": "England"
                                            }
                                        ]
                                    }
                                ]
                            },
                            {
                                "rowTitle": "What passports do you hold?",
                                "rowItems": [
                                    {
                                        "valueList": [
                                            {
                                                "text": "United Kingdom"
                                            }
                                        ]
                                    }
                                ]
                            }
                        ]
                    },
                    {
                        "groupTitle": "Qualifications",
                        "rows": [
                            {
                                "rowTitle": "Have you completed an apprenticeship?",
                                "rowItems": [
                                    {
                                        "valueList": [
                                            {
                                                "text": "Yes"
                                            }
                                        ]
                                    }
                                ]
                            },
                            {
                                "rowTitle": "Have you achieved a GCSE or equivalent qualification?",
                                "rowItems": [
                                    {
                                        "valueList": [
                                            {
                                                "text": "5 GCSEs grades A* to C or 9 to 4"
                                            }
                                        ]
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        ]
    })
}}

{% macro onsSummary(params) %}
    {% set className = "summary" %}
    {% set titleSize = "2" %}
    {% if params.classes is defined and params.classes %}
         {% set className = className + " " + params.classes %}
    {% endif %}
    {% if params.hub is defined and params.hub %}
        {% set className = className + " summary--hub" %}
    {% endif %}
    <div class="{{ className }}">
        {% for summary in params.summaries %}
            <div class="summary__group">
                {% if summary.summaryTitle is defined and summary.summaryTitle %}
                    <h2 class="summary__title u-mb-m">{{ summary.summaryTitle }}</h2>
                    {% set titleSize = "3" %}
                {% endif %}
                {% for group in summary.groups %}
                    {% if group.groupTitle is defined and group.groupTitle %}
                        <h{{ titleSize }} class="summary__group-title">{{ group.groupTitle }}</h{{ titleSize }}>
                    {% endif %}
                    {% if group.rows is defined and group.rows %}
                        <table class="summary__items">
                            {% if group.headers is defined and group.headers %}
                                <thead class="u-vh">
                                    <tr>
                                        {% for header in group.headers %}
                                            <th>{{ header }}</th>
                                        {% endfor %}
                                    </tr>
                                </thead>
                            {% endif %}
                            {% for row in (group.rows if group.rows is iterable else group.rows.items()) %}
                                {% set itemClass = "" %}
                                {% if row.error is defined and row.error %} {% set itemClass = " summary__item--error" %}{% endif %}
                                {% if row.total is defined and row.total %} {% set itemClass = itemClass + " summary__item--total" %}{% endif %}
                                <tbody class="summary__item{{ itemClass }}">
                                    {% if row.errorMessage is defined and row.errorMessage or (row.rowItems | length > 1 and row.rowTitle) %}
                                        <tr class="summary__row">
                                            <th colspan="3" class="summary__row-title u-fs-r">{{ row.errorMessage or row.rowTitle }}</th>
                                        </tr>
                                    {% endif %}
                                    {% for rowItem in row.rowItems %}
                                        <tr class="summary__row{{ " summary__row--has-values" if rowItem.valueList else "" }}">
                                            <td
                                                class="summary__item-title"
                                                {% if rowItem.rowTitleAttributes is defined and rowItem.rowTitleAttributes %}{% for attribute, value in (rowItem.rowTitleAttributes.items() if rowItem.rowTitleAttributes is mapping and rowItem.rowTitleAttributes.items else rowItem.rowTitleAttributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                            >
                                                {% if rowItem.icon is defined and rowItem.icon %}
                                                    {% from "components/icons/_macro.njk" import onsIcon %}
                                                    <span class= "summary__item-title-icon {% if rowItem.icon == 'check' %} summary__item-title-icon--check{% endif %}">
                                                        {{
                                                            onsIcon({
                                                                "icon": rowItem.icon
                                                            })
                                                        }}
                                                    </span>
                                                {% endif %}
                                                <div class="summary__item--text{{ ' summary__item-title--text' if rowItem.icon else "" }}">{{ rowItem.rowTitle | default(row.rowTitle) | safe }} {{ hasIcons }}</div>
                                                {# Render section status for mobile if is hub #}
                                                {% if params.hub is defined and params.hub and rowItem.valueList is defined and rowItem.valueList %}
                                                    <span class="u-d-no@s u-fs-r"> — {{ rowItem.valueList[0].text | safe }}</span>
                                                {% endif %}
                                            </td>
                                            {% if rowItem.valueList is defined and rowItem.valueList %}
                                                <td
                                                    class="summary__values"
                                                    {% if rowItem.actions == null %} colspan="2"{% endif %}
                                                    {% if rowItem.attributes is defined and rowItem.attributes %}{% for attribute, value in (rowItem.attributes.items() if rowItem.attributes is mapping and rowItem.attributes.items else rowItem.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                >
                                                    {% if rowItem.valueList | length == 1 %}
                                                        {{ rowItem.valueList[0].text | safe }}
                                                        {% if rowItem.valueList[0].other is defined and rowItem.valueList[0].other or rowItem.valueList[0].other == 0 %}
                                                            <ul class="u-mb-no">
                                                                <li>{{ rowItem.valueList[0].other | safe }}</li>
                                                            </ul>
                                                        {% endif %}
                                                    {% else %}
                                                        <ul class="u-mb-no">
                                                            {% for value in (rowItem.valueList if rowItem.valueList is iterable else rowItem.valueList.items()) %}
                                                                <li>
                                                                    {{ value.text | safe }}
                                                                    {% if value.other is defined and value.other or value.other == 0 %}
                                                                        <ul class="u-mb-no">
                                                                            <li>{{ value.other | safe }}</li>
                                                                        </ul>
                                                                    {% endif %}
                                                                </li>
                                                            {% endfor %}
                                                        </ul>
                                                    {% endif %}
                                                </td>
                                            {% endif %}
                                            {% if rowItem.actions is defined and rowItem.actions %}
                                                <td class="summary__actions">
                                                    {% for action in (rowItem.actions if rowItem.actions is iterable else rowItem.actions.items()) %}
                                                        {% if loop.index > 1 %}<span class="summary__spacer"></span>{% endif %}
                                                        <a
                                                            href="{{ action.url }}"
                                                            class="summary__button"
                                                            {% if action.ariaLabel is defined and action.ariaLabel %} aria-label="{{ action.ariaLabel }}"{% endif %}
                                                            {% if action.attributes is defined and action.attributes %}{% for attribute, value in (action.attributes.items() if action.attributes is mapping and action.attributes.items else action.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                        >{{ action.text }}</a>
                                                    {% endfor %}
                                                </td>
                                            {% endif %}
                                        </tr>
                                    {% endfor %}
                                </tbody>
                            {% endfor %}
                        </table>
                    {% elif group.placeholderText is defined and group.placeholderText %}
                        {{ group.placeholderText }}
                    {% endif %}
                    {% if group.summaryLink is defined and group.summaryLink %}
                        <div class="{% if group.placeholderText is defined and group.placeholderText or group.rows is defined and group.rows %}u-pt-s{% endif %}{% if group.placeholderText is not defined and group.rows is defined and group.rows | length > 1 %} u-bt{% endif %}">
                            <a {% if group.summaryLink.attributes is defined and group.summaryLink.attributes %}{% for attribute, value in (group.summaryLink.attributes.items() if group.summaryLink.attributes is mapping and group.summaryLink.attributes.items else group.summaryLink.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %} href="{{ group.summaryLink.url }}">{{ group.summaryLink.text }}</a>
                        </div>
                    {% endif %}
                {% endfor %}
            </div>
        {% endfor %}
    </div>
{% endmacro %}

$summary-row-spacing: 1rem;
$summary-col-spacing: 1rem;
$hub-row-spacing: 1.3rem;
.summary {
  &__items {
    border-collapse: collapse;
    border-spacing: 0;
    width: 100%;
    + .summary__group-title {
      margin-top: 1.5rem;
    }
  }
  &__item {
    line-height: 1.4;
    &:not(:last-child),
    &:nth-of-type(1) {
      border-bottom: 1px solid $color-borders;
    }
    &--total {
      @extend .u-fs-m;
      border-width: 2px;
      font-weight: 700;
    }
    &--error {
      background: $color-errors-tint;
      border-left: 8px solid $color-errors;
    }
  }
  &__row-title {
    padding: $summary-row-spacing 0;
    text-align: left;
  }
  &__item-title,
  &__values,
  &__actions {
    hyphens: manual;
    overflow-wrap: break-word;
    padding: 0 0 $summary-row-spacing;
    vertical-align: top;
    word-wrap: break-word;
  }
  &__item-title {
    padding-top: $summary-row-spacing;
    position: relative;
    &--text {
      display: block;
      overflow: hidden;
      padding-left: 2rem;
    }
    &-icon {
      left: 0;
      position: absolute;
      text-align: center;
      &--check {
        fill: $color-leaf-green;
      }
    }
  }
  &__actions {
    white-space: nowrap;
  }
  &__spacer {
    background: $color-black;
    display: inline-block;
    height: 1rem;
    margin: 0 0.25rem;
    vertical-align: middle;
    width: 1px;
  }
  // Item Modifiers
  &__item--total & {
    &__values {
      @extend .u-fs-m;
    }
  }
  &__item--error & {
    &__row-title {
      color: $color-errors;
      font-weight: 700;
      padding: $summary-row-spacing $summary-col-spacing;
    }
    &__item-title,
    &__values,
    &__actions {
      padding-left: $summary-col-spacing;
      padding-right: $summary-col-spacing;
      @include mq('s') {
        padding-left: $summary-col-spacing / 2;
        padding-right: $summary-col-spacing / 2;
        &:first-child {
          padding-left: $summary-col-spacing;
        }
        &:last-child {
          padding-right: $summary-col-spacing;
        }
      }
    }
  }
  // Modifiers
  &--hub & {
    &__actions {
      padding: 0 0 $hub-row-spacing;
    }
    &__item-title {
      @extend .u-fs-r--b;
      padding-top: $hub-row-spacing;
    }
  }
  &:not(&--hub) & {
    &__values {
      @extend .u-fs-r--b;
    }
  }
  // Breakpoints
  @include mq(xxs, s, none, '<') {
    &__item-title,
    &__values,
    &__actions {
      display: block;
    }
    &--hub & {
      &__values {
        display: none;
      }
    }
  }
  @include mq(s) {
    &__item-title,
    &__values,
    &__actions {
      padding-top: $summary-row-spacing;
      vertical-align: top;
      &:not(:last-child) {
        padding-right: $summary-col-spacing;
      }
    }
    &__actions {
      text-align: right;
    }
    &__row--has-values & {
      &__item-title,
      &__values {
        width: 50%;
      }
    }
    &--hub & {
      &__item-title,
      &__values,
      &__actions {
        padding-top: $hub-row-spacing;
      }
    }
  }
}

Multiple

A summary of multiple answers to a single question.

<div class="summary">
  <div class="summary__group">
    <h2 class="summary__title u-mb-m">Summary - Section Title</h2>
    <h3 class="summary__group-title">What are your monthly household expenses?</h3>
    <table class="summary__items">
      <thead class="u-vh">
        <tr>
          <th>Question</th>
          <th>Answer given</th>
          <th>Change answer</th>
        </tr>
      </thead>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Food </div>
          </td>
          <td class="summary__values">
            £50.00
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change answer">Change</a>
          </td>
        </tr>
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Utilities </div>
          </td>
          <td class="summary__values">
            £65.00
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change answer">Change</a>
          </td>
        </tr>
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Transport </div>
          </td>
          <td class="summary__values">
            £70.00
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change answer">Change</a>
          </td>
        </tr>
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Other </div>
          </td>
          <td class="summary__values">
            Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change answer">Change</a>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
Nunjucks macro options
Name Type Required Description
summaries Array<Summaries> true An array of summaries
classes string false Classes to add to the summary component
hub boolean false Whether to render the summary in as a hub

Summaries

Name Type Required Description
groups Array<SummaryGroup> true An array of groups within a summary
summaryTitle string false The title for a group of summaries

SummaryGroup

Name Type Required Description
rows Array<SummaryRows> false An array of rows within a group
placeholderText string false A message to be shown as a placeholder if there are no rows in the summary
groupTitle string false The title for a summary within a group
headers Array<SummaryHeaders> false An array of headers to describe the data in the summary
summaryLink Array<SummaryLink> false Settings for the link to apear after the summary

SummaryRow

Name Type Required Description
rowItems Array<SummaryRowItem> true An array of items for this row
rowtitle string false The title for the row
rowTitleAttributes object false HTML attributes (for example data attributes) to add to the rowTitle
error boolean false Whether to render this item as an error
errorMessage string false Error message for the row
total boolean false Whether to render this item as a total

SummaryRowItem

Name Type Required Description
icon string false Name of the icon to be placed next to the title
title string false Label for the row item
valueList Array<SummaryValue> false The value(s) to the row item
actions Array<SummaryAction> false Configurations for action links. If not specified no links will render
attributes object false HTML attributes (for example data attributes) to add to the row item

SummaryValue

Name Type Required Description
text string true The display value
other string false The display value for the “other” input on a checkbox or radio

SummaryAction

Name Type Required Description
text string true Text for the action link
url string true URL to edit the answer
ariaLabel string false An aria-label to apply to the link if you need it to be more verbose for screen readers
attributes object false HTML attributes (for example data attributes) to add to the action link
Name Type Required Description
url string true The url for the link to follow the summary
text string true The text for the link to follow the summary
attributes object false HTML attributes (for example data attributes) to add to the summary link
{% from "components/summary/_macro.njk" import onsSummary %}
{{
    onsSummary({
        "summaries": [
            {
                "summaryTitle": "Summary - Section Title",
                "groups": [
                    {
                        "groupTitle": "What are your monthly household expenses?",
                        "headers":["Question", "Answer given", "Change answer"],
                        "rows": [
                            {
                                "rowItems": [
                                    {
                                        "rowTitle": "Food",
                                        "valueList": [
                                            {
                                                "text": "£50.00"
                                            }
                                        ],
                                        "actions": [
                                            {
                                                "text": "Change",
                                                "ariaLabel": "Change answer",
                                                "url": "#"
                                            }
                                        ]
                                    },
                                    {
                                        "rowTitle": "Utilities",
                                        "valueList": [
                                            {
                                                "text": "£65.00"
                                            }
                                        ],
                                        "actions": [
                                            {
                                                "text": "Change",
                                                "ariaLabel": "Change answer",
                                                "url": "#"
                                            }
                                        ]
                                    },
                                    {
                                        "rowTitle": "Transport",
                                        "valueList": [
                                            {
                                                "text": "£70.00"
                                            }
                                        ],
                                        "actions": [
                                            {
                                                "text": "Change",
                                                "ariaLabel": "Change answer",
                                                "url": "#"
                                            }
                                        ]
                                    },
                                    {
                                        "rowTitle": "Other",
                                        "valueList": [
                                            {
                                                "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
                                            }
                                        ],
                                        "actions": [
                                            {
                                                "text": "Change",
                                                "ariaLabel": "Change answer",
                                                "url": "#"
                                            }
                                    ]
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        ]
    })
}}

{% macro onsSummary(params) %}
    {% set className = "summary" %}
    {% set titleSize = "2" %}
    {% if params.classes is defined and params.classes %}
         {% set className = className + " " + params.classes %}
    {% endif %}
    {% if params.hub is defined and params.hub %}
        {% set className = className + " summary--hub" %}
    {% endif %}
    <div class="{{ className }}">
        {% for summary in params.summaries %}
            <div class="summary__group">
                {% if summary.summaryTitle is defined and summary.summaryTitle %}
                    <h2 class="summary__title u-mb-m">{{ summary.summaryTitle }}</h2>
                    {% set titleSize = "3" %}
                {% endif %}
                {% for group in summary.groups %}
                    {% if group.groupTitle is defined and group.groupTitle %}
                        <h{{ titleSize }} class="summary__group-title">{{ group.groupTitle }}</h{{ titleSize }}>
                    {% endif %}
                    {% if group.rows is defined and group.rows %}
                        <table class="summary__items">
                            {% if group.headers is defined and group.headers %}
                                <thead class="u-vh">
                                    <tr>
                                        {% for header in group.headers %}
                                            <th>{{ header }}</th>
                                        {% endfor %}
                                    </tr>
                                </thead>
                            {% endif %}
                            {% for row in (group.rows if group.rows is iterable else group.rows.items()) %}
                                {% set itemClass = "" %}
                                {% if row.error is defined and row.error %} {% set itemClass = " summary__item--error" %}{% endif %}
                                {% if row.total is defined and row.total %} {% set itemClass = itemClass + " summary__item--total" %}{% endif %}
                                <tbody class="summary__item{{ itemClass }}">
                                    {% if row.errorMessage is defined and row.errorMessage or (row.rowItems | length > 1 and row.rowTitle) %}
                                        <tr class="summary__row">
                                            <th colspan="3" class="summary__row-title u-fs-r">{{ row.errorMessage or row.rowTitle }}</th>
                                        </tr>
                                    {% endif %}
                                    {% for rowItem in row.rowItems %}
                                        <tr class="summary__row{{ " summary__row--has-values" if rowItem.valueList else "" }}">
                                            <td
                                                class="summary__item-title"
                                                {% if rowItem.rowTitleAttributes is defined and rowItem.rowTitleAttributes %}{% for attribute, value in (rowItem.rowTitleAttributes.items() if rowItem.rowTitleAttributes is mapping and rowItem.rowTitleAttributes.items else rowItem.rowTitleAttributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                            >
                                                {% if rowItem.icon is defined and rowItem.icon %}
                                                    {% from "components/icons/_macro.njk" import onsIcon %}
                                                    <span class= "summary__item-title-icon {% if rowItem.icon == 'check' %} summary__item-title-icon--check{% endif %}">
                                                        {{
                                                            onsIcon({
                                                                "icon": rowItem.icon
                                                            })
                                                        }}
                                                    </span>
                                                {% endif %}
                                                <div class="summary__item--text{{ ' summary__item-title--text' if rowItem.icon else "" }}">{{ rowItem.rowTitle | default(row.rowTitle) | safe }} {{ hasIcons }}</div>
                                                {# Render section status for mobile if is hub #}
                                                {% if params.hub is defined and params.hub and rowItem.valueList is defined and rowItem.valueList %}
                                                    <span class="u-d-no@s u-fs-r"> — {{ rowItem.valueList[0].text | safe }}</span>
                                                {% endif %}
                                            </td>
                                            {% if rowItem.valueList is defined and rowItem.valueList %}
                                                <td
                                                    class="summary__values"
                                                    {% if rowItem.actions == null %} colspan="2"{% endif %}
                                                    {% if rowItem.attributes is defined and rowItem.attributes %}{% for attribute, value in (rowItem.attributes.items() if rowItem.attributes is mapping and rowItem.attributes.items else rowItem.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                >
                                                    {% if rowItem.valueList | length == 1 %}
                                                        {{ rowItem.valueList[0].text | safe }}
                                                        {% if rowItem.valueList[0].other is defined and rowItem.valueList[0].other or rowItem.valueList[0].other == 0 %}
                                                            <ul class="u-mb-no">
                                                                <li>{{ rowItem.valueList[0].other | safe }}</li>
                                                            </ul>
                                                        {% endif %}
                                                    {% else %}
                                                        <ul class="u-mb-no">
                                                            {% for value in (rowItem.valueList if rowItem.valueList is iterable else rowItem.valueList.items()) %}
                                                                <li>
                                                                    {{ value.text | safe }}
                                                                    {% if value.other is defined and value.other or value.other == 0 %}
                                                                        <ul class="u-mb-no">
                                                                            <li>{{ value.other | safe }}</li>
                                                                        </ul>
                                                                    {% endif %}
                                                                </li>
                                                            {% endfor %}
                                                        </ul>
                                                    {% endif %}
                                                </td>
                                            {% endif %}
                                            {% if rowItem.actions is defined and rowItem.actions %}
                                                <td class="summary__actions">
                                                    {% for action in (rowItem.actions if rowItem.actions is iterable else rowItem.actions.items()) %}
                                                        {% if loop.index > 1 %}<span class="summary__spacer"></span>{% endif %}
                                                        <a
                                                            href="{{ action.url }}"
                                                            class="summary__button"
                                                            {% if action.ariaLabel is defined and action.ariaLabel %} aria-label="{{ action.ariaLabel }}"{% endif %}
                                                            {% if action.attributes is defined and action.attributes %}{% for attribute, value in (action.attributes.items() if action.attributes is mapping and action.attributes.items else action.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                        >{{ action.text }}</a>
                                                    {% endfor %}
                                                </td>
                                            {% endif %}
                                        </tr>
                                    {% endfor %}
                                </tbody>
                            {% endfor %}
                        </table>
                    {% elif group.placeholderText is defined and group.placeholderText %}
                        {{ group.placeholderText }}
                    {% endif %}
                    {% if group.summaryLink is defined and group.summaryLink %}
                        <div class="{% if group.placeholderText is defined and group.placeholderText or group.rows is defined and group.rows %}u-pt-s{% endif %}{% if group.placeholderText is not defined and group.rows is defined and group.rows | length > 1 %} u-bt{% endif %}">
                            <a {% if group.summaryLink.attributes is defined and group.summaryLink.attributes %}{% for attribute, value in (group.summaryLink.attributes.items() if group.summaryLink.attributes is mapping and group.summaryLink.attributes.items else group.summaryLink.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %} href="{{ group.summaryLink.url }}">{{ group.summaryLink.text }}</a>
                        </div>
                    {% endif %}
                {% endfor %}
            </div>
        {% endfor %}
    </div>
{% endmacro %}

$summary-row-spacing: 1rem;
$summary-col-spacing: 1rem;
$hub-row-spacing: 1.3rem;
.summary {
  &__items {
    border-collapse: collapse;
    border-spacing: 0;
    width: 100%;
    + .summary__group-title {
      margin-top: 1.5rem;
    }
  }
  &__item {
    line-height: 1.4;
    &:not(:last-child),
    &:nth-of-type(1) {
      border-bottom: 1px solid $color-borders;
    }
    &--total {
      @extend .u-fs-m;
      border-width: 2px;
      font-weight: 700;
    }
    &--error {
      background: $color-errors-tint;
      border-left: 8px solid $color-errors;
    }
  }
  &__row-title {
    padding: $summary-row-spacing 0;
    text-align: left;
  }
  &__item-title,
  &__values,
  &__actions {
    hyphens: manual;
    overflow-wrap: break-word;
    padding: 0 0 $summary-row-spacing;
    vertical-align: top;
    word-wrap: break-word;
  }
  &__item-title {
    padding-top: $summary-row-spacing;
    position: relative;
    &--text {
      display: block;
      overflow: hidden;
      padding-left: 2rem;
    }
    &-icon {
      left: 0;
      position: absolute;
      text-align: center;
      &--check {
        fill: $color-leaf-green;
      }
    }
  }
  &__actions {
    white-space: nowrap;
  }
  &__spacer {
    background: $color-black;
    display: inline-block;
    height: 1rem;
    margin: 0 0.25rem;
    vertical-align: middle;
    width: 1px;
  }
  // Item Modifiers
  &__item--total & {
    &__values {
      @extend .u-fs-m;
    }
  }
  &__item--error & {
    &__row-title {
      color: $color-errors;
      font-weight: 700;
      padding: $summary-row-spacing $summary-col-spacing;
    }
    &__item-title,
    &__values,
    &__actions {
      padding-left: $summary-col-spacing;
      padding-right: $summary-col-spacing;
      @include mq('s') {
        padding-left: $summary-col-spacing / 2;
        padding-right: $summary-col-spacing / 2;
        &:first-child {
          padding-left: $summary-col-spacing;
        }
        &:last-child {
          padding-right: $summary-col-spacing;
        }
      }
    }
  }
  // Modifiers
  &--hub & {
    &__actions {
      padding: 0 0 $hub-row-spacing;
    }
    &__item-title {
      @extend .u-fs-r--b;
      padding-top: $hub-row-spacing;
    }
  }
  &:not(&--hub) & {
    &__values {
      @extend .u-fs-r--b;
    }
  }
  // Breakpoints
  @include mq(xxs, s, none, '<') {
    &__item-title,
    &__values,
    &__actions {
      display: block;
    }
    &--hub & {
      &__values {
        display: none;
      }
    }
  }
  @include mq(s) {
    &__item-title,
    &__values,
    &__actions {
      padding-top: $summary-row-spacing;
      vertical-align: top;
      &:not(:last-child) {
        padding-right: $summary-col-spacing;
      }
    }
    &__actions {
      text-align: right;
    }
    &__row--has-values & {
      &__item-title,
      &__values {
        width: 50%;
      }
    }
    &--hub & {
      &__item-title,
      &__values,
      &__actions {
        padding-top: $hub-row-spacing;
      }
    }
  }
}

Validation across multiple pages

<div class="summary">
  <div class="summary__group">
    <h2 class="summary__group-title">Summary - Section Title</h2>
    <table class="summary__items">
      <thead class="u-vh">
        <tr>
          <th>Question</th>
          <th>Answer given</th>
          <th>Change answer</th>
        </tr>
      </thead>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">For the period 1 May 2017 to 31 May 2017, what was the total turnover of Essential Enterprise Ltd.? </div>
          </td>
          <td class="summary__values">
            £600.00
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change answer">Change</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item summary__item--error">
        <tr class="summary__row">
          <th colspan="3" class="summary__row-title u-fs-r">Change one or more of the figures so they total the sum of £600</th>
        </tr>
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">What was the value of the business's total sales of food? </div>
          </td>
          <td class="summary__values">
            £123.00
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change answer">Change</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item summary__item--error">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">What was the value of the business's total sales of alcohol, confectionery and tobacco? </div>
          </td>
          <td class="summary__values">
            £200.00
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change answer">Change</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item summary__item--error">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">What was the value of the business's total sales of clothing and footwear? </div>
          </td>
          <td class="summary__values">
            £50.00
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change answer">Change</a>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
Nunjucks macro options
Name Type Required Description
summaries Array<Summaries> true An array of summaries
classes string false Classes to add to the summary component
hub boolean false Whether to render the summary in as a hub

Summaries

Name Type Required Description
groups Array<SummaryGroup> true An array of groups within a summary
summaryTitle string false The title for a group of summaries

SummaryGroup

Name Type Required Description
rows Array<SummaryRows> false An array of rows within a group
placeholderText string false A message to be shown as a placeholder if there are no rows in the summary
groupTitle string false The title for a summary within a group
headers Array<SummaryHeaders> false An array of headers to describe the data in the summary
summaryLink Array<SummaryLink> false Settings for the link to apear after the summary

SummaryRow

Name Type Required Description
rowItems Array<SummaryRowItem> true An array of items for this row
rowtitle string false The title for the row
rowTitleAttributes object false HTML attributes (for example data attributes) to add to the rowTitle
error boolean false Whether to render this item as an error
errorMessage string false Error message for the row
total boolean false Whether to render this item as a total

SummaryRowItem

Name Type Required Description
icon string false Name of the icon to be placed next to the title
title string false Label for the row item
valueList Array<SummaryValue> false The value(s) to the row item
actions Array<SummaryAction> false Configurations for action links. If not specified no links will render
attributes object false HTML attributes (for example data attributes) to add to the row item

SummaryValue

Name Type Required Description
text string true The display value
other string false The display value for the “other” input on a checkbox or radio

SummaryAction

Name Type Required Description
text string true Text for the action link
url string true URL to edit the answer
ariaLabel string false An aria-label to apply to the link if you need it to be more verbose for screen readers
attributes object false HTML attributes (for example data attributes) to add to the action link
Name Type Required Description
url string true The url for the link to follow the summary
text string true The text for the link to follow the summary
attributes object false HTML attributes (for example data attributes) to add to the summary link
{% from "components/summary/_macro.njk" import onsSummary %}
{{
    onsSummary({
        "summaries": [
            {
                "groups": [
                    {
                        "groupTitle": "Summary - Section Title",
                        "headers":["Question", "Answer given", "Change answer"],
                        "rows": [
                            {
                                "rowTitle": "For the period 1 May 2017 to 31 May 2017, what was the total turnover of Essential Enterprise Ltd.?",
                                "rowItems": [
                                    {
                                        "valueList": [
                                            {
                                                "text": "£600.00"
                                            }
                                        ],
                                        "actions": [
                                            {
                                                "text": "Change",
                                                "ariaLabel": "Change answer",
                                                "url": "#"
                                            }
                                        ]
                                    }
                                ]
                            },
                            {
                                "rowTitle": "What was the value of the business's total sales of food?",
                                "errorMessage": "Change one or more of the figures so they total the sum of £600",
                                "error": true,
                                "rowItems": [
                                    {
                                        "valueList": [
                                            {
                                                "text": "£123.00"
                                            }
                                        ],
                                        "actions": [
                                            {
                                                "text": "Change",
                                                "ariaLabel": "Change answer",
                                                "url": "#"
                                            }
                                        ]
                                    }
                                ]
                            },
                            {
                                "rowTitle": "What was the value of the business's total sales of alcohol, confectionery and tobacco?",
                                "error": true,
                                "rowItems": [
                                    {
                                        "valueList": [
                                            {
                                                "text": "£200.00"
                                            }
                                        ],
                                        "actions": [
                                            {
                                                "text": "Change",
                                                "ariaLabel": "Change answer",
                                                "url": "#"
                                            }
                                        ]
                                    }
                                ]
                            },
                            {
                                "rowTitle": "What was the value of the business's total sales of clothing and footwear?",
                                "error": true,
                                "rowItems": [
                                    {
                                        "valueList": [
                                            {
                                                "text": "£50.00"
                                            }
                                        ],
                                        "actions": [
                                            {
                                                "text": "Change",
                                                "ariaLabel": "Change answer",
                                                "url": "#"
                                            }
                                        ]
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        ]
    })
}}

{% macro onsSummary(params) %}
    {% set className = "summary" %}
    {% set titleSize = "2" %}
    {% if params.classes is defined and params.classes %}
         {% set className = className + " " + params.classes %}
    {% endif %}
    {% if params.hub is defined and params.hub %}
        {% set className = className + " summary--hub" %}
    {% endif %}
    <div class="{{ className }}">
        {% for summary in params.summaries %}
            <div class="summary__group">
                {% if summary.summaryTitle is defined and summary.summaryTitle %}
                    <h2 class="summary__title u-mb-m">{{ summary.summaryTitle }}</h2>
                    {% set titleSize = "3" %}
                {% endif %}
                {% for group in summary.groups %}
                    {% if group.groupTitle is defined and group.groupTitle %}
                        <h{{ titleSize }} class="summary__group-title">{{ group.groupTitle }}</h{{ titleSize }}>
                    {% endif %}
                    {% if group.rows is defined and group.rows %}
                        <table class="summary__items">
                            {% if group.headers is defined and group.headers %}
                                <thead class="u-vh">
                                    <tr>
                                        {% for header in group.headers %}
                                            <th>{{ header }}</th>
                                        {% endfor %}
                                    </tr>
                                </thead>
                            {% endif %}
                            {% for row in (group.rows if group.rows is iterable else group.rows.items()) %}
                                {% set itemClass = "" %}
                                {% if row.error is defined and row.error %} {% set itemClass = " summary__item--error" %}{% endif %}
                                {% if row.total is defined and row.total %} {% set itemClass = itemClass + " summary__item--total" %}{% endif %}
                                <tbody class="summary__item{{ itemClass }}">
                                    {% if row.errorMessage is defined and row.errorMessage or (row.rowItems | length > 1 and row.rowTitle) %}
                                        <tr class="summary__row">
                                            <th colspan="3" class="summary__row-title u-fs-r">{{ row.errorMessage or row.rowTitle }}</th>
                                        </tr>
                                    {% endif %}
                                    {% for rowItem in row.rowItems %}
                                        <tr class="summary__row{{ " summary__row--has-values" if rowItem.valueList else "" }}">
                                            <td
                                                class="summary__item-title"
                                                {% if rowItem.rowTitleAttributes is defined and rowItem.rowTitleAttributes %}{% for attribute, value in (rowItem.rowTitleAttributes.items() if rowItem.rowTitleAttributes is mapping and rowItem.rowTitleAttributes.items else rowItem.rowTitleAttributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                            >
                                                {% if rowItem.icon is defined and rowItem.icon %}
                                                    {% from "components/icons/_macro.njk" import onsIcon %}
                                                    <span class= "summary__item-title-icon {% if rowItem.icon == 'check' %} summary__item-title-icon--check{% endif %}">
                                                        {{
                                                            onsIcon({
                                                                "icon": rowItem.icon
                                                            })
                                                        }}
                                                    </span>
                                                {% endif %}
                                                <div class="summary__item--text{{ ' summary__item-title--text' if rowItem.icon else "" }}">{{ rowItem.rowTitle | default(row.rowTitle) | safe }} {{ hasIcons }}</div>
                                                {# Render section status for mobile if is hub #}
                                                {% if params.hub is defined and params.hub and rowItem.valueList is defined and rowItem.valueList %}
                                                    <span class="u-d-no@s u-fs-r"> — {{ rowItem.valueList[0].text | safe }}</span>
                                                {% endif %}
                                            </td>
                                            {% if rowItem.valueList is defined and rowItem.valueList %}
                                                <td
                                                    class="summary__values"
                                                    {% if rowItem.actions == null %} colspan="2"{% endif %}
                                                    {% if rowItem.attributes is defined and rowItem.attributes %}{% for attribute, value in (rowItem.attributes.items() if rowItem.attributes is mapping and rowItem.attributes.items else rowItem.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                >
                                                    {% if rowItem.valueList | length == 1 %}
                                                        {{ rowItem.valueList[0].text | safe }}
                                                        {% if rowItem.valueList[0].other is defined and rowItem.valueList[0].other or rowItem.valueList[0].other == 0 %}
                                                            <ul class="u-mb-no">
                                                                <li>{{ rowItem.valueList[0].other | safe }}</li>
                                                            </ul>
                                                        {% endif %}
                                                    {% else %}
                                                        <ul class="u-mb-no">
                                                            {% for value in (rowItem.valueList if rowItem.valueList is iterable else rowItem.valueList.items()) %}
                                                                <li>
                                                                    {{ value.text | safe }}
                                                                    {% if value.other is defined and value.other or value.other == 0 %}
                                                                        <ul class="u-mb-no">
                                                                            <li>{{ value.other | safe }}</li>
                                                                        </ul>
                                                                    {% endif %}
                                                                </li>
                                                            {% endfor %}
                                                        </ul>
                                                    {% endif %}
                                                </td>
                                            {% endif %}
                                            {% if rowItem.actions is defined and rowItem.actions %}
                                                <td class="summary__actions">
                                                    {% for action in (rowItem.actions if rowItem.actions is iterable else rowItem.actions.items()) %}
                                                        {% if loop.index > 1 %}<span class="summary__spacer"></span>{% endif %}
                                                        <a
                                                            href="{{ action.url }}"
                                                            class="summary__button"
                                                            {% if action.ariaLabel is defined and action.ariaLabel %} aria-label="{{ action.ariaLabel }}"{% endif %}
                                                            {% if action.attributes is defined and action.attributes %}{% for attribute, value in (action.attributes.items() if action.attributes is mapping and action.attributes.items else action.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                        >{{ action.text }}</a>
                                                    {% endfor %}
                                                </td>
                                            {% endif %}
                                        </tr>
                                    {% endfor %}
                                </tbody>
                            {% endfor %}
                        </table>
                    {% elif group.placeholderText is defined and group.placeholderText %}
                        {{ group.placeholderText }}
                    {% endif %}
                    {% if group.summaryLink is defined and group.summaryLink %}
                        <div class="{% if group.placeholderText is defined and group.placeholderText or group.rows is defined and group.rows %}u-pt-s{% endif %}{% if group.placeholderText is not defined and group.rows is defined and group.rows | length > 1 %} u-bt{% endif %}">
                            <a {% if group.summaryLink.attributes is defined and group.summaryLink.attributes %}{% for attribute, value in (group.summaryLink.attributes.items() if group.summaryLink.attributes is mapping and group.summaryLink.attributes.items else group.summaryLink.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %} href="{{ group.summaryLink.url }}">{{ group.summaryLink.text }}</a>
                        </div>
                    {% endif %}
                {% endfor %}
            </div>
        {% endfor %}
    </div>
{% endmacro %}

$summary-row-spacing: 1rem;
$summary-col-spacing: 1rem;
$hub-row-spacing: 1.3rem;
.summary {
  &__items {
    border-collapse: collapse;
    border-spacing: 0;
    width: 100%;
    + .summary__group-title {
      margin-top: 1.5rem;
    }
  }
  &__item {
    line-height: 1.4;
    &:not(:last-child),
    &:nth-of-type(1) {
      border-bottom: 1px solid $color-borders;
    }
    &--total {
      @extend .u-fs-m;
      border-width: 2px;
      font-weight: 700;
    }
    &--error {
      background: $color-errors-tint;
      border-left: 8px solid $color-errors;
    }
  }
  &__row-title {
    padding: $summary-row-spacing 0;
    text-align: left;
  }
  &__item-title,
  &__values,
  &__actions {
    hyphens: manual;
    overflow-wrap: break-word;
    padding: 0 0 $summary-row-spacing;
    vertical-align: top;
    word-wrap: break-word;
  }
  &__item-title {
    padding-top: $summary-row-spacing;
    position: relative;
    &--text {
      display: block;
      overflow: hidden;
      padding-left: 2rem;
    }
    &-icon {
      left: 0;
      position: absolute;
      text-align: center;
      &--check {
        fill: $color-leaf-green;
      }
    }
  }
  &__actions {
    white-space: nowrap;
  }
  &__spacer {
    background: $color-black;
    display: inline-block;
    height: 1rem;
    margin: 0 0.25rem;
    vertical-align: middle;
    width: 1px;
  }
  // Item Modifiers
  &__item--total & {
    &__values {
      @extend .u-fs-m;
    }
  }
  &__item--error & {
    &__row-title {
      color: $color-errors;
      font-weight: 700;
      padding: $summary-row-spacing $summary-col-spacing;
    }
    &__item-title,
    &__values,
    &__actions {
      padding-left: $summary-col-spacing;
      padding-right: $summary-col-spacing;
      @include mq('s') {
        padding-left: $summary-col-spacing / 2;
        padding-right: $summary-col-spacing / 2;
        &:first-child {
          padding-left: $summary-col-spacing;
        }
        &:last-child {
          padding-right: $summary-col-spacing;
        }
      }
    }
  }
  // Modifiers
  &--hub & {
    &__actions {
      padding: 0 0 $hub-row-spacing;
    }
    &__item-title {
      @extend .u-fs-r--b;
      padding-top: $hub-row-spacing;
    }
  }
  &:not(&--hub) & {
    &__values {
      @extend .u-fs-r--b;
    }
  }
  // Breakpoints
  @include mq(xxs, s, none, '<') {
    &__item-title,
    &__values,
    &__actions {
      display: block;
    }
    &--hub & {
      &__values {
        display: none;
      }
    }
  }
  @include mq(s) {
    &__item-title,
    &__values,
    &__actions {
      padding-top: $summary-row-spacing;
      vertical-align: top;
      &:not(:last-child) {
        padding-right: $summary-col-spacing;
      }
    }
    &__actions {
      text-align: right;
    }
    &__row--has-values & {
      &__item-title,
      &__values {
        width: 50%;
      }
    }
    &--hub & {
      &__item-title,
      &__values,
      &__actions {
        padding-top: $hub-row-spacing;
      }
    }
  }
}

Total

<div class="summary">
  <div class="summary__group">
    <h2 class="summary__group-title">Summary - Section Title</h2>
    <table class="summary__items">
      <thead class="u-vh">
        <tr>
          <th>Question</th>
          <th>Answer given</th>
          <th>Change answer</th>
        </tr>
      </thead>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Total value of acquisitions for transport assets and equipment </div>
          </td>
          <td class="summary__values">
            £9,000.00
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change answer">Change</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Total value of acquisitions for computers and peripheral devices (hardware) </div>
          </td>
          <td class="summary__values">
            £225,000.00
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change answer">Change</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item summary__item--total">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Grand total for value of acquisitions </div>
          </td>
          <td class="summary__values" colspan="2">
            £234,000.00
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
Nunjucks macro options
Name Type Required Description
summaries Array<Summaries> true An array of summaries
classes string false Classes to add to the summary component
hub boolean false Whether to render the summary in as a hub

Summaries

Name Type Required Description
groups Array<SummaryGroup> true An array of groups within a summary
summaryTitle string false The title for a group of summaries

SummaryGroup

Name Type Required Description
rows Array<SummaryRows> false An array of rows within a group
placeholderText string false A message to be shown as a placeholder if there are no rows in the summary
groupTitle string false The title for a summary within a group
headers Array<SummaryHeaders> false An array of headers to describe the data in the summary
summaryLink Array<SummaryLink> false Settings for the link to apear after the summary

SummaryRow

Name Type Required Description
rowItems Array<SummaryRowItem> true An array of items for this row
rowtitle string false The title for the row
rowTitleAttributes object false HTML attributes (for example data attributes) to add to the rowTitle
error boolean false Whether to render this item as an error
errorMessage string false Error message for the row
total boolean false Whether to render this item as a total

SummaryRowItem

Name Type Required Description
icon string false Name of the icon to be placed next to the title
title string false Label for the row item
valueList Array<SummaryValue> false The value(s) to the row item
actions Array<SummaryAction> false Configurations for action links. If not specified no links will render
attributes object false HTML attributes (for example data attributes) to add to the row item

SummaryValue

Name Type Required Description
text string true The display value
other string false The display value for the “other” input on a checkbox or radio

SummaryAction

Name Type Required Description
text string true Text for the action link
url string true URL to edit the answer
ariaLabel string false An aria-label to apply to the link if you need it to be more verbose for screen readers
attributes object false HTML attributes (for example data attributes) to add to the action link
Name Type Required Description
url string true The url for the link to follow the summary
text string true The text for the link to follow the summary
attributes object false HTML attributes (for example data attributes) to add to the summary link
{% from "components/summary/_macro.njk" import onsSummary %}
{{
    onsSummary({
        "summaries": [
            {
                "groups": [
                    {
                        "groupTitle": "Summary - Section Title",
                        "headers":["Question", "Answer given", "Change answer"],
                        "rows": [
                            {
                                "rowTitle": "Total value of acquisitions for transport assets and equipment",
                                "rowItems": [
                                    {
                                        "valueList": [
                                            {
                                                "text": "£9,000.00"
                                            }
                                        ],
                                        "actions": [
                                            {
                                                "text": "Change",
                                                "ariaLabel": "Change answer",
                                                "url": "#"
                                            }
                                        ]
                                    }
                                ]
                            },
                            {
                                "rowTitle": "Total value of acquisitions for computers and peripheral devices (hardware)",
                                "rowItems": [
                                    {
                                        "valueList": [
                                            {
                                                "text": "£225,000.00"
                                            }
                                        ],
                                        "actions": [
                                            {
                                                "text": "Change",
                                                "ariaLabel": "Change answer",
                                                "url": "#"
                                            }
                                        ]
                                    }
                                ]
                            },
                            {
                                "rowTitle": "Grand total for value of acquisitions",
                                "total": true,
                                "rowItems": [
                                    {
                                        "valueList": [
                                            {
                                                "text": "£234,000.00"
                                            }
                                        ]
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        ]
    })
}}

{% macro onsSummary(params) %}
    {% set className = "summary" %}
    {% set titleSize = "2" %}
    {% if params.classes is defined and params.classes %}
         {% set className = className + " " + params.classes %}
    {% endif %}
    {% if params.hub is defined and params.hub %}
        {% set className = className + " summary--hub" %}
    {% endif %}
    <div class="{{ className }}">
        {% for summary in params.summaries %}
            <div class="summary__group">
                {% if summary.summaryTitle is defined and summary.summaryTitle %}
                    <h2 class="summary__title u-mb-m">{{ summary.summaryTitle }}</h2>
                    {% set titleSize = "3" %}
                {% endif %}
                {% for group in summary.groups %}
                    {% if group.groupTitle is defined and group.groupTitle %}
                        <h{{ titleSize }} class="summary__group-title">{{ group.groupTitle }}</h{{ titleSize }}>
                    {% endif %}
                    {% if group.rows is defined and group.rows %}
                        <table class="summary__items">
                            {% if group.headers is defined and group.headers %}
                                <thead class="u-vh">
                                    <tr>
                                        {% for header in group.headers %}
                                            <th>{{ header }}</th>
                                        {% endfor %}
                                    </tr>
                                </thead>
                            {% endif %}
                            {% for row in (group.rows if group.rows is iterable else group.rows.items()) %}
                                {% set itemClass = "" %}
                                {% if row.error is defined and row.error %} {% set itemClass = " summary__item--error" %}{% endif %}
                                {% if row.total is defined and row.total %} {% set itemClass = itemClass + " summary__item--total" %}{% endif %}
                                <tbody class="summary__item{{ itemClass }}">
                                    {% if row.errorMessage is defined and row.errorMessage or (row.rowItems | length > 1 and row.rowTitle) %}
                                        <tr class="summary__row">
                                            <th colspan="3" class="summary__row-title u-fs-r">{{ row.errorMessage or row.rowTitle }}</th>
                                        </tr>
                                    {% endif %}
                                    {% for rowItem in row.rowItems %}
                                        <tr class="summary__row{{ " summary__row--has-values" if rowItem.valueList else "" }}">
                                            <td
                                                class="summary__item-title"
                                                {% if rowItem.rowTitleAttributes is defined and rowItem.rowTitleAttributes %}{% for attribute, value in (rowItem.rowTitleAttributes.items() if rowItem.rowTitleAttributes is mapping and rowItem.rowTitleAttributes.items else rowItem.rowTitleAttributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                            >
                                                {% if rowItem.icon is defined and rowItem.icon %}
                                                    {% from "components/icons/_macro.njk" import onsIcon %}
                                                    <span class= "summary__item-title-icon {% if rowItem.icon == 'check' %} summary__item-title-icon--check{% endif %}">
                                                        {{
                                                            onsIcon({
                                                                "icon": rowItem.icon
                                                            })
                                                        }}
                                                    </span>
                                                {% endif %}
                                                <div class="summary__item--text{{ ' summary__item-title--text' if rowItem.icon else "" }}">{{ rowItem.rowTitle | default(row.rowTitle) | safe }} {{ hasIcons }}</div>
                                                {# Render section status for mobile if is hub #}
                                                {% if params.hub is defined and params.hub and rowItem.valueList is defined and rowItem.valueList %}
                                                    <span class="u-d-no@s u-fs-r"> — {{ rowItem.valueList[0].text | safe }}</span>
                                                {% endif %}
                                            </td>
                                            {% if rowItem.valueList is defined and rowItem.valueList %}
                                                <td
                                                    class="summary__values"
                                                    {% if rowItem.actions == null %} colspan="2"{% endif %}
                                                    {% if rowItem.attributes is defined and rowItem.attributes %}{% for attribute, value in (rowItem.attributes.items() if rowItem.attributes is mapping and rowItem.attributes.items else rowItem.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                >
                                                    {% if rowItem.valueList | length == 1 %}
                                                        {{ rowItem.valueList[0].text | safe }}
                                                        {% if rowItem.valueList[0].other is defined and rowItem.valueList[0].other or rowItem.valueList[0].other == 0 %}
                                                            <ul class="u-mb-no">
                                                                <li>{{ rowItem.valueList[0].other | safe }}</li>
                                                            </ul>
                                                        {% endif %}
                                                    {% else %}
                                                        <ul class="u-mb-no">
                                                            {% for value in (rowItem.valueList if rowItem.valueList is iterable else rowItem.valueList.items()) %}
                                                                <li>
                                                                    {{ value.text | safe }}
                                                                    {% if value.other is defined and value.other or value.other == 0 %}
                                                                        <ul class="u-mb-no">
                                                                            <li>{{ value.other | safe }}</li>
                                                                        </ul>
                                                                    {% endif %}
                                                                </li>
                                                            {% endfor %}
                                                        </ul>
                                                    {% endif %}
                                                </td>
                                            {% endif %}
                                            {% if rowItem.actions is defined and rowItem.actions %}
                                                <td class="summary__actions">
                                                    {% for action in (rowItem.actions if rowItem.actions is iterable else rowItem.actions.items()) %}
                                                        {% if loop.index > 1 %}<span class="summary__spacer"></span>{% endif %}
                                                        <a
                                                            href="{{ action.url }}"
                                                            class="summary__button"
                                                            {% if action.ariaLabel is defined and action.ariaLabel %} aria-label="{{ action.ariaLabel }}"{% endif %}
                                                            {% if action.attributes is defined and action.attributes %}{% for attribute, value in (action.attributes.items() if action.attributes is mapping and action.attributes.items else action.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                        >{{ action.text }}</a>
                                                    {% endfor %}
                                                </td>
                                            {% endif %}
                                        </tr>
                                    {% endfor %}
                                </tbody>
                            {% endfor %}
                        </table>
                    {% elif group.placeholderText is defined and group.placeholderText %}
                        {{ group.placeholderText }}
                    {% endif %}
                    {% if group.summaryLink is defined and group.summaryLink %}
                        <div class="{% if group.placeholderText is defined and group.placeholderText or group.rows is defined and group.rows %}u-pt-s{% endif %}{% if group.placeholderText is not defined and group.rows is defined and group.rows | length > 1 %} u-bt{% endif %}">
                            <a {% if group.summaryLink.attributes is defined and group.summaryLink.attributes %}{% for attribute, value in (group.summaryLink.attributes.items() if group.summaryLink.attributes is mapping and group.summaryLink.attributes.items else group.summaryLink.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %} href="{{ group.summaryLink.url }}">{{ group.summaryLink.text }}</a>
                        </div>
                    {% endif %}
                {% endfor %}
            </div>
        {% endfor %}
    </div>
{% endmacro %}

$summary-row-spacing: 1rem;
$summary-col-spacing: 1rem;
$hub-row-spacing: 1.3rem;
.summary {
  &__items {
    border-collapse: collapse;
    border-spacing: 0;
    width: 100%;
    + .summary__group-title {
      margin-top: 1.5rem;
    }
  }
  &__item {
    line-height: 1.4;
    &:not(:last-child),
    &:nth-of-type(1) {
      border-bottom: 1px solid $color-borders;
    }
    &--total {
      @extend .u-fs-m;
      border-width: 2px;
      font-weight: 700;
    }
    &--error {
      background: $color-errors-tint;
      border-left: 8px solid $color-errors;
    }
  }
  &__row-title {
    padding: $summary-row-spacing 0;
    text-align: left;
  }
  &__item-title,
  &__values,
  &__actions {
    hyphens: manual;
    overflow-wrap: break-word;
    padding: 0 0 $summary-row-spacing;
    vertical-align: top;
    word-wrap: break-word;
  }
  &__item-title {
    padding-top: $summary-row-spacing;
    position: relative;
    &--text {
      display: block;
      overflow: hidden;
      padding-left: 2rem;
    }
    &-icon {
      left: 0;
      position: absolute;
      text-align: center;
      &--check {
        fill: $color-leaf-green;
      }
    }
  }
  &__actions {
    white-space: nowrap;
  }
  &__spacer {
    background: $color-black;
    display: inline-block;
    height: 1rem;
    margin: 0 0.25rem;
    vertical-align: middle;
    width: 1px;
  }
  // Item Modifiers
  &__item--total & {
    &__values {
      @extend .u-fs-m;
    }
  }
  &__item--error & {
    &__row-title {
      color: $color-errors;
      font-weight: 700;
      padding: $summary-row-spacing $summary-col-spacing;
    }
    &__item-title,
    &__values,
    &__actions {
      padding-left: $summary-col-spacing;
      padding-right: $summary-col-spacing;
      @include mq('s') {
        padding-left: $summary-col-spacing / 2;
        padding-right: $summary-col-spacing / 2;
        &:first-child {
          padding-left: $summary-col-spacing;
        }
        &:last-child {
          padding-right: $summary-col-spacing;
        }
      }
    }
  }
  // Modifiers
  &--hub & {
    &__actions {
      padding: 0 0 $hub-row-spacing;
    }
    &__item-title {
      @extend .u-fs-r--b;
      padding-top: $hub-row-spacing;
    }
  }
  &:not(&--hub) & {
    &__values {
      @extend .u-fs-r--b;
    }
  }
  // Breakpoints
  @include mq(xxs, s, none, '<') {
    &__item-title,
    &__values,
    &__actions {
      display: block;
    }
    &--hub & {
      &__values {
        display: none;
      }
    }
  }
  @include mq(s) {
    &__item-title,
    &__values,
    &__actions {
      padding-top: $summary-row-spacing;
      vertical-align: top;
      &:not(:last-child) {
        padding-right: $summary-col-spacing;
      }
    }
    &__actions {
      text-align: right;
    }
    &__row--has-values & {
      &__item-title,
      &__values {
        width: 50%;
      }
    }
    &--hub & {
      &__item-title,
      &__values,
      &__actions {
        padding-top: $hub-row-spacing;
      }
    }
  }
}

Household

<div class="summary u-mb-l">
  <div class="summary__group">
    <table class="summary__items">
      <thead class="u-vh">
        <tr>
          <th>Name</th>
          <th>Action</th>
        </tr>
      </thead>
      <tbody class="summary__item">
        <tr class="summary__row">
          <td class="summary__item-title">
            <span class="summary__item-title-icon ">
              <svg class="svg-icon" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg" focusable="false">
                <path d="M7,9H9a5,5,0,0,1,5,5H2A5,5,0,0,1,7,9Z" transform="translate(-2 -2)" />
                <circle cx="6" cy="3" r="3" />
              </svg>
            </span>
            <div class="summary__item--text summary__item-title--text">Joe Bloggs (You) </div>
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change details for Joe Bloggs">Change</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row">
          <td class="summary__item-title">
            <span class="summary__item-title-icon ">
              <svg class="svg-icon" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg" focusable="false">
                <path d="M7,9H9a5,5,0,0,1,5,5H2A5,5,0,0,1,7,9Z" transform="translate(-2 -2)" />
                <circle cx="6" cy="3" r="3" />
              </svg>
            </span>
            <div class="summary__item--text summary__item-title--text">Barry Scott </div>
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change details for Barry Scott">Change</a>
            <span class="summary__spacer"></span>
            <a href="#" class="summary__button" aria-label="Remove Barry Scott">Remove</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row">
          <td class="summary__item-title">
            <span class="summary__item-title-icon ">
              <svg class="svg-icon" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg" focusable="false">
                <path d="M7,9H9a5,5,0,0,1,5,5H2A5,5,0,0,1,7,9Z" transform="translate(-2 -2)" />
                <circle cx="6" cy="3" r="3" />
              </svg>
            </span>
            <div class="summary__item--text summary__item-title--text">Wilhelmina Susannah Clementine-Smith </div>
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Change details for Susan Gill">Change</a>
            <span class="summary__spacer"></span>
            <a href="#" class="summary__button" aria-label="Remove Susan Gill">Remove</a>
          </td>
        </tr>
      </tbody>
    </table>
    <div class="u-pt-s u-bt">
      <a data-qa="add-item-link" href="#0">Add someone to this household</a>
    </div>
  </div>
</div>
Nunjucks macro options
Name Type Required Description
summaries Array<Summaries> true An array of summaries
classes string false Classes to add to the summary component
hub boolean false Whether to render the summary in as a hub

Summaries

Name Type Required Description
groups Array<SummaryGroup> true An array of groups within a summary
summaryTitle string false The title for a group of summaries

SummaryGroup

Name Type Required Description
rows Array<SummaryRows> false An array of rows within a group
placeholderText string false A message to be shown as a placeholder if there are no rows in the summary
groupTitle string false The title for a summary within a group
headers Array<SummaryHeaders> false An array of headers to describe the data in the summary
summaryLink Array<SummaryLink> false Settings for the link to apear after the summary

SummaryRow

Name Type Required Description
rowItems Array<SummaryRowItem> true An array of items for this row
rowtitle string false The title for the row
rowTitleAttributes object false HTML attributes (for example data attributes) to add to the rowTitle
error boolean false Whether to render this item as an error
errorMessage string false Error message for the row
total boolean false Whether to render this item as a total

SummaryRowItem

Name Type Required Description
icon string false Name of the icon to be placed next to the title
title string false Label for the row item
valueList Array<SummaryValue> false The value(s) to the row item
actions Array<SummaryAction> false Configurations for action links. If not specified no links will render
attributes object false HTML attributes (for example data attributes) to add to the row item

SummaryValue

Name Type Required Description
text string true The display value
other string false The display value for the “other” input on a checkbox or radio

SummaryAction

Name Type Required Description
text string true Text for the action link
url string true URL to edit the answer
ariaLabel string false An aria-label to apply to the link if you need it to be more verbose for screen readers
attributes object false HTML attributes (for example data attributes) to add to the action link
Name Type Required Description
url string true The url for the link to follow the summary
text string true The text for the link to follow the summary
attributes object false HTML attributes (for example data attributes) to add to the summary link
{% from "components/summary/_macro.njk" import onsSummary %}
{{ onsSummary({
    "classes": "u-mb-l",
    "summaries": [
        {
            "groups": [
                {
                    "headers":["Name", "Action"],
                    "rows": [
                        {
                            "rowTitle": "Joe Bloggs (You)",
                            "rowItems": [
                                {
                                    "icon": "person",
                                    "actions": [
                                        {
                                            "text": "Change",
                                            "ariaLabel": "Change details for Joe Bloggs",
                                            "url": "#"
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            "rowTitle": "Barry Scott",
                            "rowItems": [
                                {
                                    "icon": "person",
                                    "actions": [
                                        {
                                            "text": "Change",
                                            "ariaLabel": "Change details for Barry Scott",
                                            "url": "#"
                                        },
                                        {
                                            "text": "Remove",
                                            "ariaLabel": "Remove Barry Scott",
                                            "url": "#"
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            "rowTitle": "Wilhelmina Susannah Clementine-Smith",
                            "rowItems": [
                                {
                                    "icon": "person",
                                    "actions": [
                                        {
                                            "text": "Change",
                                            "ariaLabel": "Change details for Susan Gill",
                                            "url": "#"
                                        },
                                        {
                                            "text": "Remove",
                                            "ariaLabel": "Remove Susan Gill",
                                            "url": "#"
                                        }
                                    ]
                                }
                            ]
                        }
                    ],
                    "summaryLink": {
                        "text": "Add someone to this household",
                        "url": "#0",
                        "attributes": {
                            "data-qa": "add-item-link"
                        }
                    }
                }
            ]
        }
    ]
}) }}

{% macro onsSummary(params) %}
    {% set className = "summary" %}
    {% set titleSize = "2" %}
    {% if params.classes is defined and params.classes %}
         {% set className = className + " " + params.classes %}
    {% endif %}
    {% if params.hub is defined and params.hub %}
        {% set className = className + " summary--hub" %}
    {% endif %}
    <div class="{{ className }}">
        {% for summary in params.summaries %}
            <div class="summary__group">
                {% if summary.summaryTitle is defined and summary.summaryTitle %}
                    <h2 class="summary__title u-mb-m">{{ summary.summaryTitle }}</h2>
                    {% set titleSize = "3" %}
                {% endif %}
                {% for group in summary.groups %}
                    {% if group.groupTitle is defined and group.groupTitle %}
                        <h{{ titleSize }} class="summary__group-title">{{ group.groupTitle }}</h{{ titleSize }}>
                    {% endif %}
                    {% if group.rows is defined and group.rows %}
                        <table class="summary__items">
                            {% if group.headers is defined and group.headers %}
                                <thead class="u-vh">
                                    <tr>
                                        {% for header in group.headers %}
                                            <th>{{ header }}</th>
                                        {% endfor %}
                                    </tr>
                                </thead>
                            {% endif %}
                            {% for row in (group.rows if group.rows is iterable else group.rows.items()) %}
                                {% set itemClass = "" %}
                                {% if row.error is defined and row.error %} {% set itemClass = " summary__item--error" %}{% endif %}
                                {% if row.total is defined and row.total %} {% set itemClass = itemClass + " summary__item--total" %}{% endif %}
                                <tbody class="summary__item{{ itemClass }}">
                                    {% if row.errorMessage is defined and row.errorMessage or (row.rowItems | length > 1 and row.rowTitle) %}
                                        <tr class="summary__row">
                                            <th colspan="3" class="summary__row-title u-fs-r">{{ row.errorMessage or row.rowTitle }}</th>
                                        </tr>
                                    {% endif %}
                                    {% for rowItem in row.rowItems %}
                                        <tr class="summary__row{{ " summary__row--has-values" if rowItem.valueList else "" }}">
                                            <td
                                                class="summary__item-title"
                                                {% if rowItem.rowTitleAttributes is defined and rowItem.rowTitleAttributes %}{% for attribute, value in (rowItem.rowTitleAttributes.items() if rowItem.rowTitleAttributes is mapping and rowItem.rowTitleAttributes.items else rowItem.rowTitleAttributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                            >
                                                {% if rowItem.icon is defined and rowItem.icon %}
                                                    {% from "components/icons/_macro.njk" import onsIcon %}
                                                    <span class= "summary__item-title-icon {% if rowItem.icon == 'check' %} summary__item-title-icon--check{% endif %}">
                                                        {{
                                                            onsIcon({
                                                                "icon": rowItem.icon
                                                            })
                                                        }}
                                                    </span>
                                                {% endif %}
                                                <div class="summary__item--text{{ ' summary__item-title--text' if rowItem.icon else "" }}">{{ rowItem.rowTitle | default(row.rowTitle) | safe }} {{ hasIcons }}</div>
                                                {# Render section status for mobile if is hub #}
                                                {% if params.hub is defined and params.hub and rowItem.valueList is defined and rowItem.valueList %}
                                                    <span class="u-d-no@s u-fs-r"> — {{ rowItem.valueList[0].text | safe }}</span>
                                                {% endif %}
                                            </td>
                                            {% if rowItem.valueList is defined and rowItem.valueList %}
                                                <td
                                                    class="summary__values"
                                                    {% if rowItem.actions == null %} colspan="2"{% endif %}
                                                    {% if rowItem.attributes is defined and rowItem.attributes %}{% for attribute, value in (rowItem.attributes.items() if rowItem.attributes is mapping and rowItem.attributes.items else rowItem.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                >
                                                    {% if rowItem.valueList | length == 1 %}
                                                        {{ rowItem.valueList[0].text | safe }}
                                                        {% if rowItem.valueList[0].other is defined and rowItem.valueList[0].other or rowItem.valueList[0].other == 0 %}
                                                            <ul class="u-mb-no">
                                                                <li>{{ rowItem.valueList[0].other | safe }}</li>
                                                            </ul>
                                                        {% endif %}
                                                    {% else %}
                                                        <ul class="u-mb-no">
                                                            {% for value in (rowItem.valueList if rowItem.valueList is iterable else rowItem.valueList.items()) %}
                                                                <li>
                                                                    {{ value.text | safe }}
                                                                    {% if value.other is defined and value.other or value.other == 0 %}
                                                                        <ul class="u-mb-no">
                                                                            <li>{{ value.other | safe }}</li>
                                                                        </ul>
                                                                    {% endif %}
                                                                </li>
                                                            {% endfor %}
                                                        </ul>
                                                    {% endif %}
                                                </td>
                                            {% endif %}
                                            {% if rowItem.actions is defined and rowItem.actions %}
                                                <td class="summary__actions">
                                                    {% for action in (rowItem.actions if rowItem.actions is iterable else rowItem.actions.items()) %}
                                                        {% if loop.index > 1 %}<span class="summary__spacer"></span>{% endif %}
                                                        <a
                                                            href="{{ action.url }}"
                                                            class="summary__button"
                                                            {% if action.ariaLabel is defined and action.ariaLabel %} aria-label="{{ action.ariaLabel }}"{% endif %}
                                                            {% if action.attributes is defined and action.attributes %}{% for attribute, value in (action.attributes.items() if action.attributes is mapping and action.attributes.items else action.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                        >{{ action.text }}</a>
                                                    {% endfor %}
                                                </td>
                                            {% endif %}
                                        </tr>
                                    {% endfor %}
                                </tbody>
                            {% endfor %}
                        </table>
                    {% elif group.placeholderText is defined and group.placeholderText %}
                        {{ group.placeholderText }}
                    {% endif %}
                    {% if group.summaryLink is defined and group.summaryLink %}
                        <div class="{% if group.placeholderText is defined and group.placeholderText or group.rows is defined and group.rows %}u-pt-s{% endif %}{% if group.placeholderText is not defined and group.rows is defined and group.rows | length > 1 %} u-bt{% endif %}">
                            <a {% if group.summaryLink.attributes is defined and group.summaryLink.attributes %}{% for attribute, value in (group.summaryLink.attributes.items() if group.summaryLink.attributes is mapping and group.summaryLink.attributes.items else group.summaryLink.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %} href="{{ group.summaryLink.url }}">{{ group.summaryLink.text }}</a>
                        </div>
                    {% endif %}
                {% endfor %}
            </div>
        {% endfor %}
    </div>
{% endmacro %}

$summary-row-spacing: 1rem;
$summary-col-spacing: 1rem;
$hub-row-spacing: 1.3rem;
.summary {
  &__items {
    border-collapse: collapse;
    border-spacing: 0;
    width: 100%;
    + .summary__group-title {
      margin-top: 1.5rem;
    }
  }
  &__item {
    line-height: 1.4;
    &:not(:last-child),
    &:nth-of-type(1) {
      border-bottom: 1px solid $color-borders;
    }
    &--total {
      @extend .u-fs-m;
      border-width: 2px;
      font-weight: 700;
    }
    &--error {
      background: $color-errors-tint;
      border-left: 8px solid $color-errors;
    }
  }
  &__row-title {
    padding: $summary-row-spacing 0;
    text-align: left;
  }
  &__item-title,
  &__values,
  &__actions {
    hyphens: manual;
    overflow-wrap: break-word;
    padding: 0 0 $summary-row-spacing;
    vertical-align: top;
    word-wrap: break-word;
  }
  &__item-title {
    padding-top: $summary-row-spacing;
    position: relative;
    &--text {
      display: block;
      overflow: hidden;
      padding-left: 2rem;
    }
    &-icon {
      left: 0;
      position: absolute;
      text-align: center;
      &--check {
        fill: $color-leaf-green;
      }
    }
  }
  &__actions {
    white-space: nowrap;
  }
  &__spacer {
    background: $color-black;
    display: inline-block;
    height: 1rem;
    margin: 0 0.25rem;
    vertical-align: middle;
    width: 1px;
  }
  // Item Modifiers
  &__item--total & {
    &__values {
      @extend .u-fs-m;
    }
  }
  &__item--error & {
    &__row-title {
      color: $color-errors;
      font-weight: 700;
      padding: $summary-row-spacing $summary-col-spacing;
    }
    &__item-title,
    &__values,
    &__actions {
      padding-left: $summary-col-spacing;
      padding-right: $summary-col-spacing;
      @include mq('s') {
        padding-left: $summary-col-spacing / 2;
        padding-right: $summary-col-spacing / 2;
        &:first-child {
          padding-left: $summary-col-spacing;
        }
        &:last-child {
          padding-right: $summary-col-spacing;
        }
      }
    }
  }
  // Modifiers
  &--hub & {
    &__actions {
      padding: 0 0 $hub-row-spacing;
    }
    &__item-title {
      @extend .u-fs-r--b;
      padding-top: $hub-row-spacing;
    }
  }
  &:not(&--hub) & {
    &__values {
      @extend .u-fs-r--b;
    }
  }
  // Breakpoints
  @include mq(xxs, s, none, '<') {
    &__item-title,
    &__values,
    &__actions {
      display: block;
    }
    &--hub & {
      &__values {
        display: none;
      }
    }
  }
  @include mq(s) {
    &__item-title,
    &__values,
    &__actions {
      padding-top: $summary-row-spacing;
      vertical-align: top;
      &:not(:last-child) {
        padding-right: $summary-col-spacing;
      }
    }
    &__actions {
      text-align: right;
    }
    &__row--has-values & {
      &__item-title,
      &__values {
        width: 50%;
      }
    }
    &--hub & {
      &__item-title,
      &__values,
      &__actions {
        padding-top: $hub-row-spacing;
      }
    }
  }
}

Household no rows

If there are no rows returned the summary will render placholder text

<div class="summary">
  <div class="summary__group">
    There are no householders
    <div class="u-pt-s">
      <a data-qa="add-item-link" href="#0">Add someone to this household</a>
    </div>
  </div>
</div>
Nunjucks macro options
Name Type Required Description
summaries Array<Summaries> true An array of summaries
classes string false Classes to add to the summary component
hub boolean false Whether to render the summary in as a hub

Summaries

Name Type Required Description
groups Array<SummaryGroup> true An array of groups within a summary
summaryTitle string false The title for a group of summaries

SummaryGroup

Name Type Required Description
rows Array<SummaryRows> false An array of rows within a group
placeholderText string false A message to be shown as a placeholder if there are no rows in the summary
groupTitle string false The title for a summary within a group
headers Array<SummaryHeaders> false An array of headers to describe the data in the summary
summaryLink Array<SummaryLink> false Settings for the link to apear after the summary

SummaryRow

Name Type Required Description
rowItems Array<SummaryRowItem> true An array of items for this row
rowtitle string false The title for the row
rowTitleAttributes object false HTML attributes (for example data attributes) to add to the rowTitle
error boolean false Whether to render this item as an error
errorMessage string false Error message for the row
total boolean false Whether to render this item as a total

SummaryRowItem

Name Type Required Description
icon string false Name of the icon to be placed next to the title
title string false Label for the row item
valueList Array<SummaryValue> false The value(s) to the row item
actions Array<SummaryAction> false Configurations for action links. If not specified no links will render
attributes object false HTML attributes (for example data attributes) to add to the row item

SummaryValue

Name Type Required Description
text string true The display value
other string false The display value for the “other” input on a checkbox or radio

SummaryAction

Name Type Required Description
text string true Text for the action link
url string true URL to edit the answer
ariaLabel string false An aria-label to apply to the link if you need it to be more verbose for screen readers
attributes object false HTML attributes (for example data attributes) to add to the action link
Name Type Required Description
url string true The url for the link to follow the summary
text string true The text for the link to follow the summary
attributes object false HTML attributes (for example data attributes) to add to the summary link
{% from "components/summary/_macro.njk" import onsSummary %}
{{ onsSummary({
    "summaries": [
        {
            "groups": [
                {
                    "headers":["Name", "Action"],
                    "placeholderText": "There are no householders",
                    "summaryLink": {
                        "text": "Add someone to this household",
                        "url": "#0",
                        "attributes": {
                            "data-qa": "add-item-link"
                        }
                    }
                }
            ]
        }
    ]
}) }}

{% macro onsSummary(params) %}
    {% set className = "summary" %}
    {% set titleSize = "2" %}
    {% if params.classes is defined and params.classes %}
         {% set className = className + " " + params.classes %}
    {% endif %}
    {% if params.hub is defined and params.hub %}
        {% set className = className + " summary--hub" %}
    {% endif %}
    <div class="{{ className }}">
        {% for summary in params.summaries %}
            <div class="summary__group">
                {% if summary.summaryTitle is defined and summary.summaryTitle %}
                    <h2 class="summary__title u-mb-m">{{ summary.summaryTitle }}</h2>
                    {% set titleSize = "3" %}
                {% endif %}
                {% for group in summary.groups %}
                    {% if group.groupTitle is defined and group.groupTitle %}
                        <h{{ titleSize }} class="summary__group-title">{{ group.groupTitle }}</h{{ titleSize }}>
                    {% endif %}
                    {% if group.rows is defined and group.rows %}
                        <table class="summary__items">
                            {% if group.headers is defined and group.headers %}
                                <thead class="u-vh">
                                    <tr>
                                        {% for header in group.headers %}
                                            <th>{{ header }}</th>
                                        {% endfor %}
                                    </tr>
                                </thead>
                            {% endif %}
                            {% for row in (group.rows if group.rows is iterable else group.rows.items()) %}
                                {% set itemClass = "" %}
                                {% if row.error is defined and row.error %} {% set itemClass = " summary__item--error" %}{% endif %}
                                {% if row.total is defined and row.total %} {% set itemClass = itemClass + " summary__item--total" %}{% endif %}
                                <tbody class="summary__item{{ itemClass }}">
                                    {% if row.errorMessage is defined and row.errorMessage or (row.rowItems | length > 1 and row.rowTitle) %}
                                        <tr class="summary__row">
                                            <th colspan="3" class="summary__row-title u-fs-r">{{ row.errorMessage or row.rowTitle }}</th>
                                        </tr>
                                    {% endif %}
                                    {% for rowItem in row.rowItems %}
                                        <tr class="summary__row{{ " summary__row--has-values" if rowItem.valueList else "" }}">
                                            <td
                                                class="summary__item-title"
                                                {% if rowItem.rowTitleAttributes is defined and rowItem.rowTitleAttributes %}{% for attribute, value in (rowItem.rowTitleAttributes.items() if rowItem.rowTitleAttributes is mapping and rowItem.rowTitleAttributes.items else rowItem.rowTitleAttributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                            >
                                                {% if rowItem.icon is defined and rowItem.icon %}
                                                    {% from "components/icons/_macro.njk" import onsIcon %}
                                                    <span class= "summary__item-title-icon {% if rowItem.icon == 'check' %} summary__item-title-icon--check{% endif %}">
                                                        {{
                                                            onsIcon({
                                                                "icon": rowItem.icon
                                                            })
                                                        }}
                                                    </span>
                                                {% endif %}
                                                <div class="summary__item--text{{ ' summary__item-title--text' if rowItem.icon else "" }}">{{ rowItem.rowTitle | default(row.rowTitle) | safe }} {{ hasIcons }}</div>
                                                {# Render section status for mobile if is hub #}
                                                {% if params.hub is defined and params.hub and rowItem.valueList is defined and rowItem.valueList %}
                                                    <span class="u-d-no@s u-fs-r"> — {{ rowItem.valueList[0].text | safe }}</span>
                                                {% endif %}
                                            </td>
                                            {% if rowItem.valueList is defined and rowItem.valueList %}
                                                <td
                                                    class="summary__values"
                                                    {% if rowItem.actions == null %} colspan="2"{% endif %}
                                                    {% if rowItem.attributes is defined and rowItem.attributes %}{% for attribute, value in (rowItem.attributes.items() if rowItem.attributes is mapping and rowItem.attributes.items else rowItem.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                >
                                                    {% if rowItem.valueList | length == 1 %}
                                                        {{ rowItem.valueList[0].text | safe }}
                                                        {% if rowItem.valueList[0].other is defined and rowItem.valueList[0].other or rowItem.valueList[0].other == 0 %}
                                                            <ul class="u-mb-no">
                                                                <li>{{ rowItem.valueList[0].other | safe }}</li>
                                                            </ul>
                                                        {% endif %}
                                                    {% else %}
                                                        <ul class="u-mb-no">
                                                            {% for value in (rowItem.valueList if rowItem.valueList is iterable else rowItem.valueList.items()) %}
                                                                <li>
                                                                    {{ value.text | safe }}
                                                                    {% if value.other is defined and value.other or value.other == 0 %}
                                                                        <ul class="u-mb-no">
                                                                            <li>{{ value.other | safe }}</li>
                                                                        </ul>
                                                                    {% endif %}
                                                                </li>
                                                            {% endfor %}
                                                        </ul>
                                                    {% endif %}
                                                </td>
                                            {% endif %}
                                            {% if rowItem.actions is defined and rowItem.actions %}
                                                <td class="summary__actions">
                                                    {% for action in (rowItem.actions if rowItem.actions is iterable else rowItem.actions.items()) %}
                                                        {% if loop.index > 1 %}<span class="summary__spacer"></span>{% endif %}
                                                        <a
                                                            href="{{ action.url }}"
                                                            class="summary__button"
                                                            {% if action.ariaLabel is defined and action.ariaLabel %} aria-label="{{ action.ariaLabel }}"{% endif %}
                                                            {% if action.attributes is defined and action.attributes %}{% for attribute, value in (action.attributes.items() if action.attributes is mapping and action.attributes.items else action.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                        >{{ action.text }}</a>
                                                    {% endfor %}
                                                </td>
                                            {% endif %}
                                        </tr>
                                    {% endfor %}
                                </tbody>
                            {% endfor %}
                        </table>
                    {% elif group.placeholderText is defined and group.placeholderText %}
                        {{ group.placeholderText }}
                    {% endif %}
                    {% if group.summaryLink is defined and group.summaryLink %}
                        <div class="{% if group.placeholderText is defined and group.placeholderText or group.rows is defined and group.rows %}u-pt-s{% endif %}{% if group.placeholderText is not defined and group.rows is defined and group.rows | length > 1 %} u-bt{% endif %}">
                            <a {% if group.summaryLink.attributes is defined and group.summaryLink.attributes %}{% for attribute, value in (group.summaryLink.attributes.items() if group.summaryLink.attributes is mapping and group.summaryLink.attributes.items else group.summaryLink.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %} href="{{ group.summaryLink.url }}">{{ group.summaryLink.text }}</a>
                        </div>
                    {% endif %}
                {% endfor %}
            </div>
        {% endfor %}
    </div>
{% endmacro %}

$summary-row-spacing: 1rem;
$summary-col-spacing: 1rem;
$hub-row-spacing: 1.3rem;
.summary {
  &__items {
    border-collapse: collapse;
    border-spacing: 0;
    width: 100%;
    + .summary__group-title {
      margin-top: 1.5rem;
    }
  }
  &__item {
    line-height: 1.4;
    &:not(:last-child),
    &:nth-of-type(1) {
      border-bottom: 1px solid $color-borders;
    }
    &--total {
      @extend .u-fs-m;
      border-width: 2px;
      font-weight: 700;
    }
    &--error {
      background: $color-errors-tint;
      border-left: 8px solid $color-errors;
    }
  }
  &__row-title {
    padding: $summary-row-spacing 0;
    text-align: left;
  }
  &__item-title,
  &__values,
  &__actions {
    hyphens: manual;
    overflow-wrap: break-word;
    padding: 0 0 $summary-row-spacing;
    vertical-align: top;
    word-wrap: break-word;
  }
  &__item-title {
    padding-top: $summary-row-spacing;
    position: relative;
    &--text {
      display: block;
      overflow: hidden;
      padding-left: 2rem;
    }
    &-icon {
      left: 0;
      position: absolute;
      text-align: center;
      &--check {
        fill: $color-leaf-green;
      }
    }
  }
  &__actions {
    white-space: nowrap;
  }
  &__spacer {
    background: $color-black;
    display: inline-block;
    height: 1rem;
    margin: 0 0.25rem;
    vertical-align: middle;
    width: 1px;
  }
  // Item Modifiers
  &__item--total & {
    &__values {
      @extend .u-fs-m;
    }
  }
  &__item--error & {
    &__row-title {
      color: $color-errors;
      font-weight: 700;
      padding: $summary-row-spacing $summary-col-spacing;
    }
    &__item-title,
    &__values,
    &__actions {
      padding-left: $summary-col-spacing;
      padding-right: $summary-col-spacing;
      @include mq('s') {
        padding-left: $summary-col-spacing / 2;
        padding-right: $summary-col-spacing / 2;
        &:first-child {
          padding-left: $summary-col-spacing;
        }
        &:last-child {
          padding-right: $summary-col-spacing;
        }
      }
    }
  }
  // Modifiers
  &--hub & {
    &__actions {
      padding: 0 0 $hub-row-spacing;
    }
    &__item-title {
      @extend .u-fs-r--b;
      padding-top: $hub-row-spacing;
    }
  }
  &:not(&--hub) & {
    &__values {
      @extend .u-fs-r--b;
    }
  }
  // Breakpoints
  @include mq(xxs, s, none, '<') {
    &__item-title,
    &__values,
    &__actions {
      display: block;
    }
    &--hub & {
      &__values {
        display: none;
      }
    }
  }
  @include mq(s) {
    &__item-title,
    &__values,
    &__actions {
      padding-top: $summary-row-spacing;
      vertical-align: top;
      &:not(:last-child) {
        padding-right: $summary-col-spacing;
      }
    }
    &__actions {
      text-align: right;
    }
    &__row--has-values & {
      &__item-title,
      &__values {
        width: 50%;
      }
    }
    &--hub & {
      &__item-title,
      &__values,
      &__actions {
        padding-top: $hub-row-spacing;
      }
    }
  }
}

Hub

<div class="summary summary--hub">
  <div class="summary__group">
    <table class="summary__items">
      <thead class="u-vh">
        <tr>
          <th>Name of section or person</th>
          <th>Section progress</th>
          <th>Access section</th>
        </tr>
      </thead>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <span class="summary__item-title-icon  summary__item-title-icon--check">
              <svg class="svg-icon" viewBox="0 0 13 10" xmlns="http://www.w3.org/2000/svg" focusable="false">
                <path d="M14.35,3.9l-.71-.71a.5.5,0,0,0-.71,0h0L5.79,10.34,3.07,7.61a.51.51,0,0,0-.71,0l-.71.71a.51.51,0,0,0,0,.71l3.78,3.78a.5.5,0,0,0,.71,0h0L14.35,4.6A.5.5,0,0,0,14.35,3.9Z" transform="translate(-1.51 -3.04)" />
              </svg>
            </span>
            <div class="summary__item--text summary__item-title--text">People who live here </div>
            <span class="u-d-no@s u-fs-r"> — Completed</span>
          </td>
          <td class="summary__values">
            Completed
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="View answers for People who live here">View answers</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <span class="summary__item-title-icon  summary__item-title-icon--check">
              <svg class="svg-icon" viewBox="0 0 13 10" xmlns="http://www.w3.org/2000/svg" focusable="false">
                <path d="M14.35,3.9l-.71-.71a.5.5,0,0,0-.71,0h0L5.79,10.34,3.07,7.61a.51.51,0,0,0-.71,0l-.71.71a.51.51,0,0,0,0,.71l3.78,3.78a.5.5,0,0,0,.71,0h0L14.35,4.6A.5.5,0,0,0,14.35,3.9Z" transform="translate(-1.51 -3.04)" />
              </svg>
            </span>
            <div class="summary__item--text summary__item-title--text">Accomodation </div>
            <span class="u-d-no@s u-fs-r"> — Completed</span>
          </td>
          <td class="summary__values">
            Completed
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="View answers for Accomodation">View answers</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <span class="summary__item-title-icon  summary__item-title-icon--check">
              <svg class="svg-icon" viewBox="0 0 13 10" xmlns="http://www.w3.org/2000/svg" focusable="false">
                <path d="M14.35,3.9l-.71-.71a.5.5,0,0,0-.71,0h0L5.79,10.34,3.07,7.61a.51.51,0,0,0-.71,0l-.71.71a.51.51,0,0,0,0,.71l3.78,3.78a.5.5,0,0,0,.71,0h0L14.35,4.6A.5.5,0,0,0,14.35,3.9Z" transform="translate(-1.51 -3.04)" />
              </svg>
            </span>
            <div class="summary__item--text summary__item-title--text">Mary Smith (You) </div>
            <span class="u-d-no@s u-fs-r"> — Completed</span>
          </td>
          <td class="summary__values">
            Completed
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="View answers for Mary Smith">View answers</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">John Smith </div>
            <span class="u-d-no@s u-fs-r"> — Partially completed</span>
          </td>
          <td class="summary__values">
            Partially completed
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Continue with John Smith&#39;s section">Continue with section</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Billy Smith </div>
            <span class="u-d-no@s u-fs-r"> — Not started</span>
          </td>
          <td class="summary__values">
            Not started
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Start Billy Smith&#39;s section">Start section</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Sally Smith </div>
            <span class="u-d-no@s u-fs-r"> — Not started</span>
          </td>
          <td class="summary__values">
            Not started
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Start Sally Smith&#39;s section">Start section</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Wilhelmina Susannah Clementine-Smith (Visitor) </div>
            <span class="u-d-no@s u-fs-r"> — Not started</span>
          </td>
          <td class="summary__values">
            Not started
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Start Wilhelmina Susannah Clementine-Smith&#39;s section">Start section</a>
          </td>
        </tr>
      </tbody>
      <tbody class="summary__item">
        <tr class="summary__row summary__row--has-values">
          <td class="summary__item-title">
            <div class="summary__item--text">Vera Jones (Visitor) </div>
            <span class="u-d-no@s u-fs-r"> — Not started</span>
          </td>
          <td class="summary__values">
            Not started
          </td>
          <td class="summary__actions">
            <a href="#" class="summary__button" aria-label="Start Vera Jones&#39;s section">Start section</a>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
Nunjucks macro options
Name Type Required Description
summaries Array<Summaries> true An array of summaries
classes string false Classes to add to the summary component
hub boolean false Whether to render the summary in as a hub

Summaries

Name Type Required Description
groups Array<SummaryGroup> true An array of groups within a summary
summaryTitle string false The title for a group of summaries

SummaryGroup

Name Type Required Description
rows Array<SummaryRows> false An array of rows within a group
placeholderText string false A message to be shown as a placeholder if there are no rows in the summary
groupTitle string false The title for a summary within a group
headers Array<SummaryHeaders> false An array of headers to describe the data in the summary
summaryLink Array<SummaryLink> false Settings for the link to apear after the summary

SummaryRow

Name Type Required Description
rowItems Array<SummaryRowItem> true An array of items for this row
rowtitle string false The title for the row
rowTitleAttributes object false HTML attributes (for example data attributes) to add to the rowTitle
error boolean false Whether to render this item as an error
errorMessage string false Error message for the row
total boolean false Whether to render this item as a total

SummaryRowItem

Name Type Required Description
icon string false Name of the icon to be placed next to the title
title string false Label for the row item
valueList Array<SummaryValue> false The value(s) to the row item
actions Array<SummaryAction> false Configurations for action links. If not specified no links will render
attributes object false HTML attributes (for example data attributes) to add to the row item

SummaryValue

Name Type Required Description
text string true The display value
other string false The display value for the “other” input on a checkbox or radio

SummaryAction

Name Type Required Description
text string true Text for the action link
url string true URL to edit the answer
ariaLabel string false An aria-label to apply to the link if you need it to be more verbose for screen readers
attributes object false HTML attributes (for example data attributes) to add to the action link
Name Type Required Description
url string true The url for the link to follow the summary
text string true The text for the link to follow the summary
attributes object false HTML attributes (for example data attributes) to add to the summary link
{% from "components/summary/_macro.njk" import onsSummary %}
{{ onsSummary({
    "hub": true,
    "summaries": [
            {
                "groups": [
                    {
                    "headers":["Name of section or person", "Section progress", "Access section"],
                    "rows": [
                        {
                            "rowTitle": "People who live here",
                            "rowItems": [
                                {
                                    "icon": "check",
                                    "valueList": [
                                        {
                                            "text": "Completed"
                                        }
                                    ],
                                    "actions": [
                                        {
                                            "text": "View answers",
                                            "ariaLabel": "View answers for People who live here",
                                            "url": "#"
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            "rowTitle": "Accomodation",
                            "rowItems": [
                                {
                                    "icon": "check",
                                    "valueList": [
                                        {
                                            "text": "Completed"
                                        }
                                    ],
                                    "actions": [
                                        {
                                            "text": "View answers",
                                            "ariaLabel": "View answers for Accomodation",
                                            "url": "#"
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            "rowTitle": "Mary Smith (You)",
                            "rowItems": [
                                {
                                    "icon": "check",
                                    "valueList": [
                                        {
                                            "text": "Completed"
                                        }
                                    ],
                                    "actions": [
                                        {
                                            "text": "View answers",
                                            "ariaLabel": "View answers for Mary Smith",
                                            "url": "#"
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            "rowTitle": "John Smith",
                            "rowItems": [
                                {
                                    "valueList": [
                                        {
                                            "text": "Partially completed"
                                        }
                                    ],
                                    "actions": [
                                        {
                                            "text": "Continue with section",
                                            "ariaLabel": "Continue with John Smith's section",
                                            "url": "#"
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            "rowTitle": "Billy Smith",
                            "rowItems": [
                                {
                                    "valueList": [
                                        {
                                            "text": "Not started"
                                        }
                                    ],
                                    "actions": [
                                        {
                                            "text": "Start section",
                                            "ariaLabel": "Start Billy Smith's section",
                                            "url": "#"
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            "rowTitle": "Sally Smith",
                            "rowItems": [
                                {
                                    "valueList": [
                                        {
                                            "text": "Not started"
                                        }
                                    ],
                                    "actions": [
                                        {
                                            "text": "Start section",
                                            "ariaLabel": "Start Sally Smith's section",
                                            "url": "#"
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            "rowTitle": "Wilhelmina Susannah Clementine-Smith (Visitor)",
                            "rowItems": [
                                {
                                    "valueList": [
                                        {
                                            "text": "Not started"
                                        }
                                    ],
                                    "actions": [
                                        {
                                            "text": "Start section",
                                            "ariaLabel": "Start Wilhelmina Susannah Clementine-Smith's section",
                                            "url": "#"
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            "rowTitle": "Vera Jones (Visitor)",
                            "rowItems": [
                                {
                                    "valueList": [
                                        {
                                            "text": "Not started"
                                        }
                                    ],
                                    "actions": [
                                        {
                                            "text": "Start section",
                                            "ariaLabel": "Start Vera Jones's section",
                                            "url": "#"
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ]
}) }}

{% macro onsSummary(params) %}
    {% set className = "summary" %}
    {% set titleSize = "2" %}
    {% if params.classes is defined and params.classes %}
         {% set className = className + " " + params.classes %}
    {% endif %}
    {% if params.hub is defined and params.hub %}
        {% set className = className + " summary--hub" %}
    {% endif %}
    <div class="{{ className }}">
        {% for summary in params.summaries %}
            <div class="summary__group">
                {% if summary.summaryTitle is defined and summary.summaryTitle %}
                    <h2 class="summary__title u-mb-m">{{ summary.summaryTitle }}</h2>
                    {% set titleSize = "3" %}
                {% endif %}
                {% for group in summary.groups %}
                    {% if group.groupTitle is defined and group.groupTitle %}
                        <h{{ titleSize }} class="summary__group-title">{{ group.groupTitle }}</h{{ titleSize }}>
                    {% endif %}
                    {% if group.rows is defined and group.rows %}
                        <table class="summary__items">
                            {% if group.headers is defined and group.headers %}
                                <thead class="u-vh">
                                    <tr>
                                        {% for header in group.headers %}
                                            <th>{{ header }}</th>
                                        {% endfor %}
                                    </tr>
                                </thead>
                            {% endif %}
                            {% for row in (group.rows if group.rows is iterable else group.rows.items()) %}
                                {% set itemClass = "" %}
                                {% if row.error is defined and row.error %} {% set itemClass = " summary__item--error" %}{% endif %}
                                {% if row.total is defined and row.total %} {% set itemClass = itemClass + " summary__item--total" %}{% endif %}
                                <tbody class="summary__item{{ itemClass }}">
                                    {% if row.errorMessage is defined and row.errorMessage or (row.rowItems | length > 1 and row.rowTitle) %}
                                        <tr class="summary__row">
                                            <th colspan="3" class="summary__row-title u-fs-r">{{ row.errorMessage or row.rowTitle }}</th>
                                        </tr>
                                    {% endif %}
                                    {% for rowItem in row.rowItems %}
                                        <tr class="summary__row{{ " summary__row--has-values" if rowItem.valueList else "" }}">
                                            <td
                                                class="summary__item-title"
                                                {% if rowItem.rowTitleAttributes is defined and rowItem.rowTitleAttributes %}{% for attribute, value in (rowItem.rowTitleAttributes.items() if rowItem.rowTitleAttributes is mapping and rowItem.rowTitleAttributes.items else rowItem.rowTitleAttributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                            >
                                                {% if rowItem.icon is defined and rowItem.icon %}
                                                    {% from "components/icons/_macro.njk" import onsIcon %}
                                                    <span class= "summary__item-title-icon {% if rowItem.icon == 'check' %} summary__item-title-icon--check{% endif %}">
                                                        {{
                                                            onsIcon({
                                                                "icon": rowItem.icon
                                                            })
                                                        }}
                                                    </span>
                                                {% endif %}
                                                <div class="summary__item--text{{ ' summary__item-title--text' if rowItem.icon else "" }}">{{ rowItem.rowTitle | default(row.rowTitle) | safe }} {{ hasIcons }}</div>
                                                {# Render section status for mobile if is hub #}
                                                {% if params.hub is defined and params.hub and rowItem.valueList is defined and rowItem.valueList %}
                                                    <span class="u-d-no@s u-fs-r"> — {{ rowItem.valueList[0].text | safe }}</span>
                                                {% endif %}
                                            </td>
                                            {% if rowItem.valueList is defined and rowItem.valueList %}
                                                <td
                                                    class="summary__values"
                                                    {% if rowItem.actions == null %} colspan="2"{% endif %}
                                                    {% if rowItem.attributes is defined and rowItem.attributes %}{% for attribute, value in (rowItem.attributes.items() if rowItem.attributes is mapping and rowItem.attributes.items else rowItem.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                >
                                                    {% if rowItem.valueList | length == 1 %}
                                                        {{ rowItem.valueList[0].text | safe }}
                                                        {% if rowItem.valueList[0].other is defined and rowItem.valueList[0].other or rowItem.valueList[0].other == 0 %}
                                                            <ul class="u-mb-no">
                                                                <li>{{ rowItem.valueList[0].other | safe }}</li>
                                                            </ul>
                                                        {% endif %}
                                                    {% else %}
                                                        <ul class="u-mb-no">
                                                            {% for value in (rowItem.valueList if rowItem.valueList is iterable else rowItem.valueList.items()) %}
                                                                <li>
                                                                    {{ value.text | safe }}
                                                                    {% if value.other is defined and value.other or value.other == 0 %}
                                                                        <ul class="u-mb-no">
                                                                            <li>{{ value.other | safe }}</li>
                                                                        </ul>
                                                                    {% endif %}
                                                                </li>
                                                            {% endfor %}
                                                        </ul>
                                                    {% endif %}
                                                </td>
                                            {% endif %}
                                            {% if rowItem.actions is defined and rowItem.actions %}
                                                <td class="summary__actions">
                                                    {% for action in (rowItem.actions if rowItem.actions is iterable else rowItem.actions.items()) %}
                                                        {% if loop.index > 1 %}<span class="summary__spacer"></span>{% endif %}
                                                        <a
                                                            href="{{ action.url }}"
                                                            class="summary__button"
                                                            {% if action.ariaLabel is defined and action.ariaLabel %} aria-label="{{ action.ariaLabel }}"{% endif %}
                                                            {% if action.attributes is defined and action.attributes %}{% for attribute, value in (action.attributes.items() if action.attributes is mapping and action.attributes.items else action.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
                                                        >{{ action.text }}</a>
                                                    {% endfor %}
                                                </td>
                                            {% endif %}
                                        </tr>
                                    {% endfor %}
                                </tbody>
                            {% endfor %}
                        </table>
                    {% elif group.placeholderText is defined and group.placeholderText %}
                        {{ group.placeholderText }}
                    {% endif %}
                    {% if group.summaryLink is defined and group.summaryLink %}
                        <div class="{% if group.placeholderText is defined and group.placeholderText or group.rows is defined and group.rows %}u-pt-s{% endif %}{% if group.placeholderText is not defined and group.rows is defined and group.rows | length > 1 %} u-bt{% endif %}">
                            <a {% if group.summaryLink.attributes is defined and group.summaryLink.attributes %}{% for attribute, value in (group.summaryLink.attributes.items() if group.summaryLink.attributes is mapping and group.summaryLink.attributes.items else group.summaryLink.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %} href="{{ group.summaryLink.url }}">{{ group.summaryLink.text }}</a>
                        </div>
                    {% endif %}
                {% endfor %}
            </div>
        {% endfor %}
    </div>
{% endmacro %}

$summary-row-spacing: 1rem;
$summary-col-spacing: 1rem;
$hub-row-spacing: 1.3rem;
.summary {
  &__items {
    border-collapse: collapse;
    border-spacing: 0;
    width: 100%;
    + .summary__group-title {
      margin-top: 1.5rem;
    }
  }
  &__item {
    line-height: 1.4;
    &:not(:last-child),
    &:nth-of-type(1) {
      border-bottom: 1px solid $color-borders;
    }
    &--total {
      @extend .u-fs-m;
      border-width: 2px;
      font-weight: 700;
    }
    &--error {
      background: $color-errors-tint;
      border-left: 8px solid $color-errors;
    }
  }
  &__row-title {
    padding: $summary-row-spacing 0;
    text-align: left;
  }
  &__item-title,
  &__values,
  &__actions {
    hyphens: manual;
    overflow-wrap: break-word;
    padding: 0 0 $summary-row-spacing;
    vertical-align: top;
    word-wrap: break-word;
  }
  &__item-title {
    padding-top: $summary-row-spacing;
    position: relative;
    &--text {
      display: block;
      overflow: hidden;
      padding-left: 2rem;
    }
    &-icon {
      left: 0;
      position: absolute;
      text-align: center;
      &--check {
        fill: $color-leaf-green;
      }
    }
  }
  &__actions {
    white-space: nowrap;
  }
  &__spacer {
    background: $color-black;
    display: inline-block;
    height: 1rem;
    margin: 0 0.25rem;
    vertical-align: middle;
    width: 1px;
  }
  // Item Modifiers
  &__item--total & {
    &__values {
      @extend .u-fs-m;
    }
  }
  &__item--error & {
    &__row-title {
      color: $color-errors;
      font-weight: 700;
      padding: $summary-row-spacing $summary-col-spacing;
    }
    &__item-title,
    &__values,
    &__actions {
      padding-left: $summary-col-spacing;
      padding-right: $summary-col-spacing;
      @include mq('s') {
        padding-left: $summary-col-spacing / 2;
        padding-right: $summary-col-spacing / 2;
        &:first-child {
          padding-left: $summary-col-spacing;
        }
        &:last-child {
          padding-right: $summary-col-spacing;
        }
      }
    }
  }
  // Modifiers
  &--hub & {
    &__actions {
      padding: 0 0 $hub-row-spacing;
    }
    &__item-title {
      @extend .u-fs-r--b;
      padding-top: $hub-row-spacing;
    }
  }
  &:not(&--hub) & {
    &__values {
      @extend .u-fs-r--b;
    }
  }
  // Breakpoints
  @include mq(xxs, s, none, '<') {
    &__item-title,
    &__values,
    &__actions {
      display: block;
    }
    &--hub & {
      &__values {
        display: none;
      }
    }
  }
  @include mq(s) {
    &__item-title,
    &__values,
    &__actions {
      padding-top: $summary-row-spacing;
      vertical-align: top;
      &:not(:last-child) {
        padding-right: $summary-col-spacing;
      }
    }
    &__actions {
      text-align: right;
    }
    &__row--has-values & {
      &__item-title,
      &__values {
        width: 50%;
      }
    }
    &--hub & {
      &__item-title,
      &__values,
      &__actions {
        padding-top: $hub-row-spacing;
      }
    }
  }
}

Research on this component

If you have conducted any user research using this component, please feed back your findings via the Design System forum 

Design System forum

Discuss ‘Summary’ on GitHub