diff --git a/docs/components/badge.md b/docs/components/badge.md new file mode 100644 index 0000000..f19fe99 --- /dev/null +++ b/docs/components/badge.md @@ -0,0 +1,60 @@ +--- +layout: layouts/component.njk +title: Badge +description: Use badges to alert users to unread information. Badges can include a number count. +backlogID: 0 +tags: + - component +--- + +## When to use + +Badges can be placed: + +- on the edge of an icon +- on a card + +Badges help to notify users about unread information that needs their attention. This could include new messages or new documents. + +## How to use + +Badges should be dynamic and temporary. After users have viewed the relevant information, badges should either: + +- disappear +- remain if there are still unread items (but with an adjusted number count, if one is used) + +There are different size and colour variations of badges. + +### Large badges + +{% example "badges/badge-large.njk" %} + +Large badges always include a number count. This tells users how many items need their attention. + +Above the count of 9, large badges always display 9+. This allows the width of the badge to be restricted to two characters. + +### Small badges + +Small badges are simple circles. They can be placed: + +- on the edge of icons, such as on the bottom navigation +- on cards, alongside text, such as “Document attached” on appointment cards + +{% example "badges/badge-small.njk" %} + +The colour of small badges can be: + +- red for important notifications that needs to stand out on a page +- blue for secondary notifications that can afford to be less prominent + +{% example "badges/badge-small-red.njk" %} + +For example, users will see a red badge on the bottom navigation to indicate unread messages. When they then navigate to their messages inbox to view those messages, unread message headings are indicated by blue badges. + +## Accessibility + +Badges are designed to stand out when placed over icons and cards. The contrast ratio is 3:1, meeting [WCAG 2.2. Contrast (Minimum) (Level AA)](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum). + +We use visually hidden text to convey badges to screen reader users. Large badges announce the number count up to 9. They announce "nine plus" after that to match the visual display of 9+. + +Small badges could announce "New notification", "Important" or "You have unread messages" depending on the context. diff --git a/docs/components/card-links.md b/docs/components/card-links.md index 364f811..5d48c4c 100644 --- a/docs/components/card-links.md +++ b/docs/components/card-links.md @@ -52,7 +52,7 @@ If you are using icons, they should have [aria labels/hidden text?] so that scre Use badges to alert users to new, important information that sits beyond a card link. This could include unread messages or new appointment details. -[embed badge example] +{% example "cards/card-link-with-badge.njk" %} ## Content guidance diff --git a/docs/examples/badges/badge-large.njk b/docs/examples/badges/badge-large.njk new file mode 100644 index 0000000..86c5eaa --- /dev/null +++ b/docs/examples/badges/badge-large.njk @@ -0,0 +1,13 @@ +--- +layout: layouts/example.njk +title: Badge Large +figmaLink: "https://www.figma.com/design/6f2CbcZ7cnpNrtKEcfQp8X/NHS-App-Design-System?node-id=128-7303&t=UdzCaY5YPtBypveQ-0" +vueLink: "https://nhsappvuecomponentlibraryv1.nonlive.nhsapp.service.nhs.uk/?path=/docs/components-nhsbadge-large--docs" +--- + +{% from "badge/large/macro.njk" import badgeLarge %} + +{{ badgeLarge({ + count: 3, + label: 'notifications' +}) }} diff --git a/docs/examples/badges/badge-small-red.njk b/docs/examples/badges/badge-small-red.njk new file mode 100644 index 0000000..eb29fe6 --- /dev/null +++ b/docs/examples/badges/badge-small-red.njk @@ -0,0 +1,15 @@ +--- +layout: layouts/example.njk +title: Badge Small +figmaLink: "https://www.figma.com/design/6f2CbcZ7cnpNrtKEcfQp8X/NHS-App-Design-System?node-id=128-7303&t=UdzCaY5YPtBypveQ-0" +vueLink: "https://nhsappvuecomponentlibraryv1.nonlive.nhsapp.service.nhs.uk/?path=/docs/components-nhsbadge-small--docs" +--- + +{% from "badge/small/macro.njk" import badgeSmall %} + +{{ badgeSmall({ +label: 'New', +color: 'red', +text: 'Document attached', +classes: 'nhsuk-body-m' +}) }} \ No newline at end of file diff --git a/docs/examples/badges/badge-small.njk b/docs/examples/badges/badge-small.njk new file mode 100644 index 0000000..6ebc0ec --- /dev/null +++ b/docs/examples/badges/badge-small.njk @@ -0,0 +1,14 @@ +--- +layout: layouts/example.njk +title: Badge Small +figmaLink: "https://www.figma.com/design/6f2CbcZ7cnpNrtKEcfQp8X/NHS-App-Design-System?node-id=128-7303&t=UdzCaY5YPtBypveQ-0" +vueLink: "https://nhsappvuecomponentlibraryv1.nonlive.nhsapp.service.nhs.uk/?path=/docs/components-nhsbadge-small--docs" +--- + +{% from "badge/small/macro.njk" import badgeSmall %} + +{{ badgeSmall({ +label: 'New', +text: 'Document attached', +classes: 'nhsuk-body-m' +}) }} diff --git a/docs/examples/cards/card-link-with-badge.njk b/docs/examples/cards/card-link-with-badge.njk new file mode 100644 index 0000000..ce3fd63 --- /dev/null +++ b/docs/examples/cards/card-link-with-badge.njk @@ -0,0 +1,17 @@ +--- +layout: layouts/example.njk +title: Card link with description +figmaLink: "https://www.figma.com/file/6f2CbcZ7cnpNrtKEcfQp8X/NHS-App-Design-System?type=design&node-id=128%3A7303&mode=design&t=DLiyCHcTTAYkEDa0-1" +vueLink: "https://nhsappvuecomponentlibraryv1.nonlive.nhsapp.service.nhs.uk/?path=/docs/components-nhscardlink--docs" +--- + +{% from "card/macro.njk" import card %} + +{{ card({ + title: 'Messages', + href: '#', + badgeLarge: { + count: 4, + label: 'unread messages' + } +}) }} diff --git a/docs/index.njk b/docs/index.njk index 00537af..a53d5e7 100644 --- a/docs/index.njk +++ b/docs/index.njk @@ -4,6 +4,7 @@ {%- from 'hero/macro.njk' import hero -%} {%- from 'card/macro.njk' import card -%} +{%- from 'badge/large/macro.njk' import badgeLarge -%} {% block header %} {{ super() }} diff --git a/src/all.scss b/src/all.scss index 2b8643e..183da6a 100644 --- a/src/all.scss +++ b/src/all.scss @@ -1,4 +1,5 @@ @import "node_modules/nhsuk-frontend/packages/core/tools/all.scss"; @import "node_modules/nhsuk-frontend/packages/core/settings/all.scss"; -@import "./components/card/card.scss"; +@import "./components/card/card"; +@import "./components/badge/badge"; diff --git a/src/components/badge/_badge.scss b/src/components/badge/_badge.scss new file mode 100644 index 0000000..debc2fc --- /dev/null +++ b/src/components/badge/_badge.scss @@ -0,0 +1,73 @@ +// ========================================================================== +// COMPONENTS / #BADGE +// ========================================================================== + +@use "sass:math"; + +.nhsapp-badge { + @include nhsuk-typography-responsive(19); + + display: inline-block; + + background-color: $nhsuk-error-color; + border-radius: nhsuk-spacing(1); + color: $color_nhsuk-white; + font-weight: bold; + padding: 0 nhsuk-spacing(2); + + @include mq($from: tablet) { + padding: 0 12px; + } +} + +.nhsapp-badge-small { + position: relative; + + display: inline-flex; + align-items: baseline; +} + +/** + * Mixin to position the small badge + * @param {number} $size - The size of the badge + */ +@mixin small-badge-position($size: 8px) { + position: relative; + width: $size; + height: $size; + margin-right: $size; + border-radius: math.div($size, 2); + + $font-height: 0.7em; // The height of a capital letter in the specific font we use (Frutiger) + bottom: calc(0.5 * ($font-height - $size)); +} + +$nhsapp-badge-size-mobile: 8px; +$nhsapp-badge-size-tablet: 12px; + +.nhsapp-badge-small__indicator { + @include small-badge-position($nhsapp-badge-size-mobile); + + @include mq($from: tablet) { + @include small-badge-position($nhsapp-badge-size-tablet); + } + + background-color: $color_nhsuk-blue; +} + +.nhsapp-badge-small--red { + .nhsapp-badge-small__indicator { + background-color: $nhsuk-error-color; + } +} + +.nhsapp-badge-small--absolute { + .nhsapp-badge-small__indicator { + position: absolute; + + left: -2 * $nhsapp-badge-size-mobile; + @include mq($from: tablet) { + left: -2 * $nhsapp-badge-size-tablet; + } + } +} diff --git a/src/components/badge/large/badge-large.njk b/src/components/badge/large/badge-large.njk new file mode 100644 index 0000000..ef0799c --- /dev/null +++ b/src/components/badge/large/badge-large.njk @@ -0,0 +1,11 @@ +{%- if params.count -%} + + You have + {% if params.count > 9 %} + +9 + {% else %} + {{ params.count }} + {% endif %} + {{ params.label }} + +{%- endif -%} \ No newline at end of file diff --git a/src/components/badge/large/macro.njk b/src/components/badge/large/macro.njk new file mode 100644 index 0000000..db66e95 --- /dev/null +++ b/src/components/badge/large/macro.njk @@ -0,0 +1,3 @@ +{% macro badgeLarge(params) %} + {%- include "./badge-large.njk" -%} +{% endmacro %} diff --git a/src/components/badge/small/badge-small.njk b/src/components/badge/small/badge-small.njk new file mode 100644 index 0000000..c35c2df --- /dev/null +++ b/src/components/badge/small/badge-small.njk @@ -0,0 +1,9 @@ + + + {{ params.label }} + {{ params.text }} + \ No newline at end of file diff --git a/src/components/badge/small/macro.njk b/src/components/badge/small/macro.njk new file mode 100644 index 0000000..d3afe9a --- /dev/null +++ b/src/components/badge/small/macro.njk @@ -0,0 +1,3 @@ +{% macro badgeSmall(params) %} + {%- include "./badge-small.njk" -%} +{% endmacro %} diff --git a/src/components/card/card.njk b/src/components/card/card.njk index 80a92e7..2056b51 100644 --- a/src/components/card/card.njk +++ b/src/components/card/card.njk @@ -1,3 +1,7 @@ +{% from "badge/large/macro.njk" import badgeLarge %} + +{% set hasBadgeLarge = true if params.badgeLarge.count > 1 %} +
@@ -10,6 +14,12 @@
{%- endif -%}
+ {% if hasBadgeLarge %} + {{ badgeLarge({ + count: params.badgeLarge.count, + label: params.badgeLarge.label + }) }} + {% endif %}