Skip to content

Commit

Permalink
feat(button): icon set (#1859)
Browse files Browse the repository at this point in the history
* fix(button): use rh-icon

* fix(button): narrow type of icon and set

* fix(footer): document accepted icons in social links

* chore: max out netlify's card

* perf(button): lazy-load icon

* fix(button): icon layouts

* fix(button): fancy icon layouts, etc

* docs(button): icon usage

* perf(button): shadow classes
  • Loading branch information
bennypowers authored Sep 16, 2024
1 parent 0440570 commit caa1abf
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 95 deletions.
9 changes: 9 additions & 0 deletions .changeset/slimy-guests-rescue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@rhds/elements": minor
---
`<rh-button>`: add `icon-set` attribute, corresponding to `<rh-icon set="...">`

```html
<rh-button icon="giftbox"
icon-set="standard">Donate</rh-button>
```
22 changes: 22 additions & 0 deletions elements/rh-button/demo/icon.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<section id="button-with-icon">
<rh-button icon="error-fill" danger>Danger</rh-button>
<rh-button icon="information-fill">Primary</rh-button>
<rh-button icon="external-link" icon-set="microns" variant="link">Link</rh-button>
<rh-button icon="bug-fill" variant="secondary">Secondary</rh-button>
<rh-button icon="bug-fill" variant="secondary" danger>Secondary Danger</rh-button>
<rh-button icon="close" icon-set="microns" variant="tertiary">Tertiary</rh-button>
<rh-button icon="close" icon-set="microns" disabled>Disabled</rh-button>
</section>

<script type="module">
import '@rhds/elements/rh-button/rh-button.js';
</script>

<style>
#button-with-icon {
display: flex;
align-items: start;
flex-wrap: wrap;
gap: var(--rh-space-lg, 16px);
}
</style>
34 changes: 19 additions & 15 deletions elements/rh-button/docs/20-guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function to users. Therefore, it is important that each variant is implemented
consistently so they communicate the correct actions.

<uxdot-example width-adjustment="494px">
<img src="{{ '../button-variants.png' | url }}" alt="Image of the seven available button variant">
<img src="../button-variants.png" alt="Image of the seven available button variant">
</uxdot-example>

<rh-table>
Expand Down Expand Up @@ -77,7 +77,7 @@ Use a Play button to indicate that audio or video will play when selected.
</rh-alert>

<uxdot-example width-adjustment="806px">
<img src="{{ '../button-usage-play.png' | url }}" alt="Image of play button examples; a video thumbnail on the left and a text layout on the right">
<img src="../button-usage-play.png" alt="Image of play button examples; a video thumbnail on the left and a text layout on the right">
</uxdot-example>

### Close button
Expand All @@ -86,9 +86,13 @@ Use a Close button to indicate that a window will close when selected.
Close buttons are mostly found in [dialogs](/elements/dialog/).

<uxdot-example width-adjustment="1000px" alignment="left" variant="full" no-border>
<img src="{{ '../button-usage-close.png' | url }}" alt="Image of a dialog with a close button in the top right corner">
<img src="../button-usage-close.png" alt="Image of a dialog with a close button in the top right corner">
</uxdot-example>

### Other icons

When adding icons, prefer to use the [microns](/icons/#micron-icons) as they fit
the button layout better.

### Disabled

Expand All @@ -97,7 +101,7 @@ completed first, most buttons can become disabled. However, the Play and Close
buttons do not include a disabled state.

<uxdot-example width-adjustment="494px">
<img src="{{ '../button-usage-disabled.png' | url }}" alt="Image of five disabled buttons not including play and close buttons, underneath is a dropdown with a disabled button">
<img src="../button-usage-disabled.png" alt="Image of five disabled buttons not including play and close buttons, underneath is a dropdown with a disabled button">
</uxdot-example>

## Writing content
Expand All @@ -124,7 +128,7 @@ When writing link button text labels, use specific and action-focused language
that matches what users will see when they arrive at their location.

<uxdot-example width-adjustment="525px">
<img src="{{ '../button-link-text-labels.png' | url }}" alt="Image of link button text labels">
<img src="../button-link-text-labels.png" alt="Image of link button text labels">
</uxdot-example>

### Button vs. call to action text labels
Expand All @@ -133,7 +137,7 @@ Button text labels are written to be short and communicate an action whereas
call to action text labels are written to entice users to select a link.

<uxdot-example width-adjustment="696px">
<img src="{{ '../button-vs-cta-text-labels.png' | url }}" alt="Image of two buttons on the left and two calls to action on the right">
<img src="../button-vs-cta-text-labels.png" alt="Image of two buttons on the left and two calls to action on the right">
</uxdot-example>

### Character and word count
Expand Down Expand Up @@ -178,7 +182,7 @@ consistent across all contexts
elements are stacked vertically

<uxdot-example width-adjustment="1000px" variant="full" no-border alignment="left">
<img src="{{ '../button-layout-placement.png' | url }}" alt="Image of buttons used in a dialog and a form">
<img src="../button-layout-placement.png" alt="Image of buttons used in a dialog and a form">
</uxdot-example>

### Hierarchy
Expand All @@ -187,7 +191,7 @@ Buttons are ordered by hierarchy from left to right. Do not use multiple Danger,
Primary, or Close buttons in the same area.

<uxdot-example width-adjustment="797px">
<img src="{{ '../button-layout-hierarchy.png' | url }}" alt="Image of buttons grouped by hierarchy from left to right">
<img src="../button-layout-hierarchy.png" alt="Image of buttons grouped by hierarchy from left to right">
</uxdot-example>

### Grouping
Expand All @@ -196,7 +200,7 @@ Grouping buttons is a useful way of aligning buttons that have a relationship.
Group buttons logically into sets based on hierarchy and usage.

<uxdot-example width-adjustment="740px">
<img src="{{ '../button-layout-grouping.png' | url }}" alt="Image of button groups and their hierarchy from left to right">
<img src="../button-layout-grouping.png" alt="Image of button groups and their hierarchy from left to right">
</uxdot-example>

### Space in groups
Expand All @@ -206,7 +210,7 @@ buttons. If buttons are stacked, the spacing between each button should be
`8px`.

<uxdot-example width-adjustment="508px">
<img src="{{ '../button-layout-spacing.png' | url }}" alt="Image of button groups and their horizontal and vertical spacing in between each button">
<img src="../button-layout-spacing.png" alt="Image of button groups and their horizontal and vertical spacing in between each button">
</uxdot-example>

## Best practices
Expand All @@ -216,31 +220,31 @@ buttons. If buttons are stacked, the spacing between each button should be
Buttons should never have more than one line of text.

<uxdot-example width-adjustment="80px" danger>
<img src="{{ '../button-best-practice-1.png' | url }}" alt="Image of a button with two lines of text which is incorrect usage">
<img src="../button-best-practice-1.png" alt="Image of a button with two lines of text which is incorrect usage">
</uxdot-example>

### Multiple buttons

Do not use multiple Danger or Primary buttons in the same area.

<uxdot-example width-adjustment="544px" danger>
<img src="{{ '../button-best-practice-2.png' | url }}" alt="Image of two danger and two primary button groups which is incorrect usage">
<img src="../button-best-practice-2.png" alt="Image of two danger and two primary button groups which is incorrect usage">
</uxdot-example>

### Text labels

Do not write button text labels that are expressive or ambiguous.

<uxdot-example width-adjustment="358px" danger>
<img src="{{ '../button-best-practice-3.png' | url }}" alt="Image of two buttons; one has expressive language and the other has ambiguous language which is incorrect usage">
<img src="../button-best-practice-3.png" alt="Image of two buttons; one has expressive language and the other has ambiguous language which is incorrect usage">
</uxdot-example>

### Danger button

Do not use a Danger button for non-destructive purposes.

<uxdot-example width-adjustment="680px" danger>
<img src="{{ '../button-best-practice-4.png' | url }}" alt="Image of a search bar using a danger button which is incorrect usage">
<img src="../button-best-practice-4.png" alt="Image of a search bar using a danger button which is incorrect usage">
</uxdot-example>

### Button as a call to action
Expand All @@ -249,5 +253,5 @@ Do not use buttons as links or change the Primary button styling, use a link or
call to action instead.

<uxdot-example width-adjustment="433px" danger>
<img src="{{ '../button-best-practice-5.png' | url }}" alt="Image of text styles with a button underneath that resembles a call to action which is incorrect usage">
<img src="../button-best-practice-5.png" alt="Image of text styles with a button underneath that resembles a call to action which is incorrect usage">
</uxdot-example>
92 changes: 41 additions & 51 deletions elements/rh-button/rh-button.css
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,13 @@ button > span {
.hasIcon {
position: relative;
display: flex;
gap: var(--rh-space-sm, 6px);
align-items: center;
}
padding-inline-start: calc(var(--rh-space-lg, 16px) * 0.75);

.hasIcon [part='icon'] {
display: inline-flex;
align-items: center;
position: absolute;
width: 16px;
& [part='icon'] {
display: contents;
}
}

[part='icon'] ::slotted(*) {
Expand All @@ -77,11 +76,6 @@ button > span {
max-height: 16px;
}

.hasIcon button {
position: absolute;
inset: 0;
}

.light {
/* PRIMARY */
--_primary-color: var(--rh-color-text-primary-on-dark, #ffffff);
Expand Down Expand Up @@ -277,11 +271,6 @@ button > span {
--_play-hover-background-color: rgb(var(--_white-rgb) / var(--rh-opacity-80, 80%));
}

:host([hidden]),
[hidden] {
display: none !important;
}

rh-icon {
color: currentcolor;
}
Expand Down Expand Up @@ -328,7 +317,7 @@ button:hover {
* *
******************************/

:host([danger]) button {
button.danger {
--_default-color: var(--_danger-color);
--_default-background-color: var(--_danger-background-color);
--_default-border-color: var(--_danger-border-color);
Expand All @@ -349,7 +338,7 @@ button:hover {
* *
******************************/

:host([variant='secondary' i]) button {
button.secondary {
--_default-color: var(--_secondary-color);
--_default-background-color: var(--_secondary-background-color);
--_default-border-color: var(--_secondary-border-color);
Expand All @@ -373,7 +362,7 @@ button:hover {
* *
******************************/

:host([variant='tertiary' i]) button {
button.tertiary {
--_default-color: var(--_tertiary-color);
--_default-background-color: var(--_tertiary-background-color);
--_default-border-color: var(--_tertiary-border-color);
Expand All @@ -396,8 +385,12 @@ button:hover {
* *
******************************/

:host([variant='link' i]) button {
display: inline;
button.link {
display: inline-flex;

& rh-icon {
order: 1;
}

--_default-color: var(--_link-color);
--_default-background-color: var(--_link-background-color);
Expand All @@ -420,7 +413,7 @@ button:hover {
* *
******************************/

:host([variant='close' i]) button {
button.close {
--_default-color: var(--_close-color);
--_default-background-color: var(--_close-background-color);
--_active-color: var(--_close-active-color);
Expand All @@ -444,10 +437,11 @@ button:hover {
* *
******************************/

:host([variant='play' i]) button {
button.play {
border-radius: 100%;
width: var(--rh-length-4xl, 64px);

--rh-icon-size: var(--rh-size-icon-02, 24px);
--_default-color: var(--_play-color);
--_default-background-color: var(--_play-background-color);
--_default-background-opacity: var(--_play-background-opacity);
Expand All @@ -462,44 +456,40 @@ button:hover {
--_hover-background-color: var(--_play-hover-background-color);
--_hover-background-opacity: var(--_play-hover-background-opacity);
--_icon-size: var(--rh-size-icon-02, 24px);
}

:host(:is([variant='play'])) [part='icon'] {
position: relative;
inset-inline-start: 3px;
& [part='icon'] {
display: contents;
}

& rh-icon {
translate: 10%; /* perceptually center play icon only */
}
}

:host(:is([variant='play' i], [variant='close' i])) button {
button:is(.play,.close) {
aspect-ratio: 1;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0;
}

:host(:is([variant='play' i], [variant='close' i])) [part='icon'] {
display: inline-block;
width: var(--_icon-size, var(--rh-size-icon-01, 16px));
height: var(--_icon-size, var(--rh-size-icon-01, 16px));
}

:host(:is([variant='play' i], [variant='close' i])) svg {
fill: currentcolor;
stroke: currentcolor;
/* visually hidden */
& #text {
display: inline;
position: absolute !important;
width: 1px !important;
height: 1px !important;
padding: 0 !important;
margin: -1px !important;
overflow: hidden !important;
clip: rect(0, 0, 0, 0) !important;
white-space: nowrap !important;
border: 0 !important;
}
}

/* visually hidden */
:host(:is([variant='play' i], [variant='close' i])) #text {
display: inline;
position: absolute !important;
width: 1px !important;
height: 1px !important;
padding: 0 !important;
margin: -1px !important;
overflow: hidden !important;
clip: rect(0, 0, 0, 0) !important;
white-space: nowrap !important;
border: 0 !important;
:host(:is([variant='play' i], [variant='close' i])) {
line-height: 0;
}

/******************************
Expand Down Expand Up @@ -534,7 +524,7 @@ button[disabled] {
* *
******************************/

:host([variant='secondary' i][danger]) button {
button.secondary.danger {
--_default-color: var(--_secondary-danger-color);
--_default-background-color: transparent;
--_default-border-color: var(--_danger-background-color);
Expand Down
Loading

0 comments on commit caa1abf

Please sign in to comment.