Skip to content

Commit

Permalink
Add optional icon to buttons [fix mozilla#893] (mozilla#925)
Browse files Browse the repository at this point in the history
  • Loading branch information
craigcook authored Apr 4, 2024
1 parent 99d36e4 commit 6138683
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Features

* **component** Remove the format option from Newsletter component
* **component:** Allow an optional icon in buttons (#893)

# 19.0.0

Expand Down
28 changes: 28 additions & 0 deletions assets/sass/protocol/components/_button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -291,3 +291,31 @@ a.mzp-c-button {
text-decoration: underline;
}
}

// * -------------------------------------------------------------------------- */
// Icon

.mzp-c-button-icon-start,
.mzp-c-button-icon-end {
display: inline-block;
font-size: 1em;
height: 1em;
line-height: 1em;
vertical-align: baseline;
width: 1em;

img,
svg {
height: 100%;
margin-bottom: -0.15em;
width: 100%;
}
}

.mzp-c-button-icon-start {
@include bidi(((margin-right, 0.5ch, 0), (margin-left, 0, 0.5ch),));
}

.mzp-c-button-icon-end {
@include bidi(((margin-left, 0.5ch, 0), (margin-right, 0, 0.5ch),));
}
63 changes: 63 additions & 0 deletions components/button/button--with-icon.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<p>
{% render '@button', { label: 'Button with Icon',
iconEnd:
'<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 24 24" width="24" height="24" fill="currentColor">
<path d="m21.3 4.5-8-4c-.8-.4-1.8-.4-2.7 0l-8 4C1.6 5.1 1 6.1 1 7.2v9.5c0 1.1.6 2.2 1.7 2.7l8 4c.4.2.9.3 1.3.3s.9-.1 1.3-.3l8-4c1-.5 1.7-1.5 1.7-2.7V7.2c0-1.1-.6-2.1-1.7-2.7zm-9.7-2.2c.1-.1.3-.1.4-.1.2 0 .3 0 .4.1L19.8 6 12 9.9 4.2 6l7.4-3.7zm-8 15.4c-.4-.2-.6-.6-.6-.9V7.6l8 4v9.8l-7.4-3.7zm16.8 0L13 21.4v-9.8l8-4v9.2c0 .3-.2.7-.6.9z"/>
</svg>' }
%}
</p>

<p>
{% render '@button', { label: 'Button with Icon',
iconStart:
'<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 24 24" width="24" height="24" fill="currentColor">
<path d="m21.3 4.5-8-4c-.8-.4-1.8-.4-2.7 0l-8 4C1.6 5.1 1 6.1 1 7.2v9.5c0 1.1.6 2.2 1.7 2.7l8 4c.4.2.9.3 1.3.3s.9-.1 1.3-.3l8-4c1-.5 1.7-1.5 1.7-2.7V7.2c0-1.1-.6-2.1-1.7-2.7zm-9.7-2.2c.1-.1.3-.1.4-.1.2 0 .3 0 .4.1L19.8 6 12 9.9 4.2 6l7.4-3.7zm-8 15.4c-.4-.2-.6-.6-.6-.9V7.6l8 4v9.8l-7.4-3.7zm16.8 0L13 21.4v-9.8l8-4v9.2c0 .3-.2.7-.6.9z"/>
</svg>' }
%}
</p>

<p>
{% render '@button', { class: 'mzp-t-xl mzp-t-product', label: 'Download Firefox', link: 'https://www.mozilla.org/firefox/new/',
iconEnd:
'<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 16 16" width="16" height="16" fill="currentColor">
<path d="M8 13c.2 0 .4-.1.5-.2l4.4-4.4-1.1-1.1-3.1 3.1V1H7.2v9.4L4.1 7.3l-1 1.1 4.4 4.4c.1.1.3.2.5.2z"/>
<path d="M13.5 12v2c0 .3-.2.5-.5.5H3c-.3 0-.5-.2-.5-.5v-2H1v2c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2v-2h-1.5z"/>
</svg>' }
%}
</p>

<p>
{% render '@button', { class: 'mzp-t-product mzp-t-secondary', label: 'Try Reader Mode',
iconStart:
'<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 16 16" width="16" height="16" fill="currentColor">
<path d="M12 15H4c-1.1 0-2-.9-2-2V2c0-1.1.9-2 2-2h8c1.1 0 2 .9 2 2v11c0 1.1-.9 2-2 2zM4 1.5c-.3 0-.5.2-.5.5v11c0 .3.2.5.5.5h8c.3 0 .5-.2.5-.5V2c0-.3-.2-.5-.5-.5H4z"/>
<path d="M5.5 3.5h5V5h-5z"/>
<path d="M5.5 6.5h5V8h-5z"/>
<path d="M5.5 9.5h3V11h-3z"/>
</svg>' }
%}
</p>

<p>
{% render '@button', { class: 'mzp-t-sm mzp-t-secondary', label: 'Previous', link: '#',
iconStart:
'<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 16 16" width="16" height="16" fill="currentColor">
<path d="m1.2 7.7 5.5-5.5 1.1 1.1-4.2 4.2H15V9H3.6l4.2 4.2-1.1 1.1-5.5-5.5c-.1-.2-.2-.4-.2-.6s.1-.3.2-.5z"/>
</svg>' }
%}

{% render '@button', { class: 'mzp-t-sm mzp-t-secondary', label: 'Next', link: '#',
iconEnd:
'<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 16 16" width="16" height="16" fill="currentColor">
<path d="M14.8 7.7 9.3 2.2 8.2 3.3l4.2 4.2H1V9h11.4l-4.2 4.2 1.1 1.1 5.5-5.5c.1-.2.2-.4.2-.6s-.1-.3-.2-.5z"/>
</svg>' }
%}
</p>

<p>
{% render '@button', { label: 'Character', iconEnd: '❤︎' } %}
</p>

<p>
{% render '@button', { label: 'Emoji', iconEnd: '❤️' } %}
</p>
47 changes: 47 additions & 0 deletions components/button/button--with-icon.readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
You can add an icon to a button as an inline image enclosed in a `span` with the
class `mzp-c-button-icon-start` if the icon appears before the text label or
`mzp-c-button-icon-end` if it appears after the label.

You can optionally use a standard unicode character or symbol, but be aware not
all platforms will support all characters. Icon fonts are also an option, with
all the usual caveats about using webfonts. You can use an emoji but they also
may not be supported equally across platforms and even on supporting platforms
they’ll be rendered in completely different styles by different systems. For
consistency and reliability, use an image.

### Tips
- Prefer simple, single-color icons. Complex images likely won’t render well at
such a small size. Multicolored icons or logos may not adapt to different
backgrounds as the button state changes.

- Prefer embedded SVG over an external `img` (whether SVG or other format). An
inline SVG icon can more easily change color for the different button states
and style variants. Be aware that very old browsers don’t support SVG.

- Consider the text direction of the page language. Arrows in particular indicate
a specific orientation that may be confusing in text that flows the opposite
direction. The “Next” and “Previous” buttons shown here are a good example of
how this can go wrong. In a right-to-left language, the “Next” arrow moves to
the left of the text label, but still points to the right. A properly
bi-directional design should reverse those icons as well.

### Tips for inline SVG
- Optimize SVG files for embedding inline in the HTML document. Strip out unnecessary
comments or metadata added by editing tools. Use [SVGO](https://svgo.dev/)
either locally on [online](https://jakearchibald.github.io/svgomg/).

- Merge shapes and paths where possible to reduce the number of elements and points.

- Avoid unnecessary grouping of elements.

- Define colors with `currentColor`. This will inherit the icon’s color from the
button text, including color changes in hover and focus states. An icon with
its own defined colors will need to accommodate background color changes,
either with a color that is visible on all backgrounds, or facilitating a
color change some other way besides `currentColor` (e.g. with additional CSS).

### No-Nos
- Don’t add multiple icons to a button. Technically Protocol doesn’t prevent it,
it’s just a bad idea.


20 changes: 10 additions & 10 deletions components/button/button.config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,54 +16,54 @@ variants:
preview: '@preview-dark'
notes: A light variation of the secondary button for dark backgrounds, adding the class `mzp-t-dark` (the button itself is light).
context:
class: mzp-t-secondary mzp-t-dark
class: 'mzp-t-secondary mzp-t-dark'
label: Secondary Button
- name: Product
notes: Use this theme style for product-related transactions, such as downloading software or creating an account.
context:
class: mzp-t-product
class: 'mzp-t-product'
label: Download Firefox
- name: Product Secondary
notes: This secondary product button theme should be used when the CTA is a product-related transaction, but not the main action a person should take on a page.
context:
class: mzp-t-product mzp-t-secondary
class: 'mzp-t-product mzp-t-secondary'
label: Download Firefox
- name: Product Secondary Dark
preview: '@preview-dark'
notes: A light variation of the secondary product button for use on dark backgrounds. Add the class `mzp-t-dark` (the button itself is light).
context:
class: mzp-t-product mzp-t-secondary mzp-t-dark
class: 'mzp-t-product mzp-t-secondary mzp-t-dark'
label: Download Firefox
- name: Neutral
notes: A neutral button for less important actions.
context:
class: mzp-t-neutral
class: 'mzp-t-neutral'
label: Neutral Button
- name: Neutral Dark
preview: '@preview-dark'
notes: A light variation of the neutral button for use on dark backgrounds. Add the class `mzp-t-dark` (the button itself is light).
context:
class: mzp-t-neutral mzp-t-dark
class: 'mzp-t-neutral mzp-t-dark'
label: Neutral Button
- name: Size small
notes: A small button. Use this size with caution because small buttons are harder to read and present smaller targets for pointing devices (clicks and taps).
context:
class: mzp-t-sm
class: 'mzp-t-sm'
label: Small Button
- name: Size medium
notes: A medium button.
context:
class: mzp-t-md
class: 'mzp-t-md'
label: Medium Button
- name: Size large
notes: This is the default size if no size class is provided.
context:
class: mzp-t-lg
class: 'mzp-t-lg'
label: Large Button
- name: Size Extra Large
notes: An extra large button. Use this sparingly.
context:
class: mzp-t-xl
class: 'mzp-t-xl'
label: Extra Large Button
- name: Disabled
notes: |
Expand Down
32 changes: 29 additions & 3 deletions components/button/button.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,35 @@
# link - URL
# type - type attribute value (button, submit, reset)
# disabled - Boolean
# iconStart - markup
# iconEnd - markup
#}
{%- if href -%}
<a class="mzp-c-button{% if class %} {{ class }}{% endif %}" href="{{ link }}">{{ label }}</a>
{%- if link -%}
<a class="mzp-c-button{% if class %} {{ class }}{% endif %}" href="{{ link }}">
{%- if iconStart %}
<span class="mzp-c-button-icon-start">
{{ iconStart | safe }}
</span>
{% endif -%}
{{ label }}
{%- if iconEnd %}
<span class="mzp-c-button-icon-end">
{{ iconEnd | safe }}
</span>
{% endif -%}
</a>
{%- else -%}
<button class="mzp-c-button{% if class %} {{ class }}{% endif %}" type="{% if type %}{{ type }}{% else %}button{% endif %}"{{ " disabled" if disabled }}>{{ label }}</button>
<button class="mzp-c-button{% if class %} {{ class }}{% endif %}" type="{% if type %}{{ type }}{% else %}button{% endif %}"{{ " disabled" if disabled }}>
{%- if iconStart %}
<span class="mzp-c-button-icon-start">
{{ iconStart | safe }}
</span>
{% endif -%}
{{ label }}
{%- if iconEnd %}
<span class="mzp-c-button-icon-end">
{{ iconEnd | safe }}
</span>
{% endif -%}
</button>
{%- endif -%}

0 comments on commit 6138683

Please sign in to comment.