Skip to content

USWDS - Button: Add basic support for usa-icon in buttons #5398

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Feb 26, 2024

Conversation

mejiaj
Copy link
Contributor

@mejiaj mejiaj commented Jul 20, 2023

Summary

Improved the vertical alignment of usa-icon elements inside of usa-button. Use the new $theme-button-icon-gap setting to set the width of the horizontal gap between the button's text and icon.

New features:

  • Improved icon alignment in buttons. Buttons that include an inline usa-icon are now visually centered.

  • Improved control of inner content. Buttons use flexbox for vertical alignment and column spacing. Added a new setting $theme-button-icon-gap: 1 !default; that takes units for inner content.

  • New Button controls in Storybook. There are two new controls for internal testing: add_icon & icon_name.

    Control: add_icon

    A toggle for including an icon in stories.
    image

    Control: icon_name (Depends on add_icon)

    A dropdown of all USA icons with add_circle_outline as the default. Icon was mentioned in the original issue and was used as the basis for styling.

    image

Breaking change

This is not a breaking change.

Related issue

Closes #5359.

Related pull requests

Preview links

Problem statement

USA Icons in buttons weren't centered vertically.

Before
image

After

Added icon to both sides to illustrate spacing via $theme-button-icon-gap.

image

Solution

Improved support for buttons with inline usa-icons using inline-flex.

Why this approach was chosen

  1. Improved control over inner spacing via the column-gap property.
  2. Icons before/after will be properly spaced.
  3. The move from inline-block → inline-flex doesn't seem like a big departure in display.

Follows a similar pattern to what's been done in breadcrumb:14 & external link:32-40. A small enhancement seemed less heavy handed than other solution.

How I implemented

Switched from inline-block → inline-flex. Added properties for column gap and justify content (for centering text).

Added vertical alignment and negative margin to visually center.

Alternatives

Using the :has() selector to use inline-grid or inline-flex. These features provide more control, but have their own problems:

  1. :has() doesn't have crossbrowser support.
  2. There are conflicts with postcsso and :has() pseudoselector. The plugin for postcss requires a JS polyfill to be included & has performance issues.

Major changes

Variable Default Type Description
$theme-button-icon-gap 1 units The inner flexbox column gap size.

Testing and review

Icon alignment

  1. Visit button icon preview link.
  2. Confirm icon is visually centered.

Storybook Controls

  1. Go to any button variant, like Accent warm.
  2. Confirm new control add_icon is visible.
  3. Toggle to True.
  4. Confirm that new control icon_name shows as a dropdown for setting icon.
  5. Confirm that all USA icons are available as options in dropdown.
  6. Confirm that icon changes on selection.

Testing checklist

  • Icons in buttons should be visually centered.
  • Button stories have a control to toggle icons.
    • If Include icon is true, show a dropdown of icons.
    • Icons should update on select.
  • There should be no html:build errors.

Copy link
Contributor

@mahoneycm mahoneycm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diggin' this one! Excited for the potential addition to the copy-code button!

I personally would like to still be able to view icons when is_demo is false. Let me know if you disagree!

Testing checklist

  • Icons in buttons should be visually centered.
  • Button stories have a control to toggle icons.
    • If Include icon is true, show a dropdown of icons.
    • Icons should update on select.
  • There should be no html:build errors.

Copy link
Contributor

@amyleadem amyleadem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mejiaj I really like how you set up the Storybook controls here. The conditional control is great and importing the icon data was a really nice touch.

I added a couple of notes in the comments. Mostly, I am curious if it is possible to use flexbox for button alignment. I was looking at #5324 about text wrapping in button groups at the same time and it made me curious if there was a solution that would work for both issues. I added more detail in the comments.

There is a chance I am missing something, so I'm curious to hear what you think. Please let me know if you have any questions.

options: iconNames,
defaultValue: "add_circle_outline",
},
if: { arg: "icon_included" },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Love a conditional Storybook control. Cool find.

Comment on lines 55 to 61
// @TODO: Use `:has()` selector once browser support improves.
// https://developer.mozilla.org/en-US/docs/Web/CSS/:has#browser_compatibility
.usa-icon {
margin-top: -0.1em; // Similar pattern to _usa-breadcrumb.scss:14.
vertical-align: middle;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about using flexbox for alignment on usa-button elements instead of creating a rule with negative margins here? I’d have to do some testing to confirm, but a quick experiment showed that it created more consistently centered elements at varying font and icon sizes, as well as allowed for buttons to be the same height when placed next to each other. It also didn't seem to impact visual display if a single button had no icon added.

For example, in this PR buttons in a segmented button group do not have a consistent height if icons are added to only some buttons in a row.

image

Additionally, I was looking at the open PR for button group wrap alignment, and it got me thinking that display: inline-flex and align-items: stretch might offer the answer to both scenarios.

I just did some quick poking and it looks like adding the style rules below would result in the following. Curious to hear what you think.

image

.usa-button {
 align-items: center;
  justify-content: center;
  display: inline-flex;
  flex-direction: row;
 }

 .usa-button-group{
   align-items: stretch;
}

.usa-button-group__item {
  display: inline-flex;
}

.usa-icon {
  min-width: $icon-inline-size-magic-number;
}

For reference, the HTML I used:

<ul class="usa-button-group usa-button-group--segmented">
    <li class="usa-button-group__item">
        <button type="button" class="usa-button"><svg class="usa-icon" aria-hidden="true" focusable="false" role="img">
                <use xlink:href="./img/sprite.svg#navigate_before"></use>
            </svg>Previous</button>
    </li>
    <li class="usa-button-group__item">
        <button type="button" class="usa-button usa-button--outline">Current</button>
    </li>
    <li class="usa-button-group__item">
        <button type="button" class="usa-button usa-button--outline">Next<svg class="usa-icon" aria-hidden="true"
                focusable="false" role="img">
                <use xlink:href="./img/sprite.svg#navigate_next"></use>
            </svg></button>
    </li>
</ul><!-- start segmented styles -->
<ul class="usa-button-group usa-button-group--segmented">
    <li class="usa-button-group__item">
        <button type="button" class="usa-button"><svg class="usa-icon" aria-hidden="true" focusable="false" role="img">
                <use xlink:href="./img/sprite.svg#navigate_before"></use>
            </svg>Previous</button>
    </li>
    <li class="usa-button-group__item">
        <button type="button" class="usa-button usa-button--outline">Current</button>
    </li>
    <li class="usa-button-group__item">
        <button type="button" class="usa-button usa-button--outline">Next with wrapping text<svg class="usa-icon"
                aria-hidden="true" focusable="false" role="img">
                <use xlink:href="./img/sprite.svg#navigate_next"></use>
            </svg></button>
    </li>
</ul>
<ul class="usa-button-group usa-button-group--segmented">
    <li class="usa-button-group__item">
        <button type="button" class="usa-button font-body-xl">Map<svg class="usa-icon usa-icon--size-3"
                aria-hidden="true" focusable="false" role="img">
                <use xlink:href="./img/sprite.svg#navigate_next"></use>
            </svg></button>
    </li>
    <li class="usa-button-group__item">
        <button type="button" class="usa-button usa-button--outline">Hybrid</button>
    </li>
    <li class="usa-button-group__item">
        <button type="button" class="usa-button usa-button--outline">Satellite<svg class="usa-icon usa-icon--size-4"
                aria-hidden="true" focusable="false" role="img">
                <use xlink:href="./img/sprite.svg#navigate_next"></use>
            </svg></button>
    </li>
</ul>

<ul class="usa-button-group usa-button-group--segmented">
    <li class="usa-button-group__item">
        <button type="button" class="usa-button ">Map</button>
    </li>
    <li class="usa-button-group__item">
        <button type="button" class="usa-button ">Hybrid</button>
    </li>
    <li class="usa-button-group__item">
        <button type="button" class="usa-button ">Satellite</button>
    </li>
</ul>

Copy link
Contributor Author

@mejiaj mejiaj Sep 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amyleadem

Re: display: inline-flex. Because this is such a widely used button ― I wanted to minimize any potentially breaking changes as much as possible.

Since we already specify inline-block, I don't think the switch to inline-flex is as drastic as I imagined. Double-checking MDN display - CSS: Cascading Style Sheets | MDN and there should be very little display difference at all.

This addition improves the experience, but might require a new theme setting for the column gap. I'll play with this.


I've added flex box and a new column gap setting in 03082ea. For now, items are centered. I'd like to keep the button group changes separate, if possible. This would keep the scope of our testing more manageable.

Example with icons on both sides (for testing only)
image

Small screens
image

@mejiaj mejiaj marked this pull request as draft August 7, 2023 19:43
@mejiaj mejiaj marked this pull request as ready for review September 11, 2023 14:20
@mejiaj mejiaj requested a review from thisisdano September 11, 2023 14:20
Copy link
Contributor

@mahoneycm mahoneycm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! One quick question about the PR description:

Is this note from your PR still correct? Seems like it was from your previous implementation

Why this approach was chosen

Follows a similar pattern to what's been done in breadcrumb:14 & external link:32-40. A small enhancement seemed less heavy handed than other solution.

How I implemented

Added vertical alignment and negative margin to visually center.


Review checklist

  • Icons in buttons should be visually centered.
  • Button stories have a control to toggle icons.
    • If Include icon is true, show a dropdown of icons.
    • Icons should update on select.
  • There should be no html:build errors.
  • Code looks good
  • No visual regressions where ` is used
  • Tested on site with Copy Code button and it worked like a charm 👍
  • Template w/ Macros still easily modifiable
  • PR description is up to date

@mejiaj mejiaj requested a review from mahoneycm September 12, 2023 13:53
@mejiaj
Copy link
Contributor Author

mejiaj commented Sep 12, 2023

@mahoneycm thanks for the review. I've responded to questions & updated PR description ― good catch!

Copy link
Contributor

@amyleadem amyleadem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking good! I had just a few notes:

  • I like the new setting but was initially confused about its purpose based solely on the name. Wondering if it might be clearer to name$theme-button-column-gap something like $theme-button-icon-gap
  • In the card component, I noticed that the text was aligning to the left in the button when the line broke (Details in comment below).
  • Some PR description things:
    • In the PR description, the control is referenced as “Icon included” but in storybook it is called “Add icon”
    • I wonder if we should flag that this as “potentially breaking” breaking because it might adjust visual presentation if users have already added inline svgs to their buttons

Here are the things I tested in Chrome, Safari, and Firefox:

  • Confirm that new storybook controls work as expected
    • Setting “Add icon” to true adds an icon to the button and adds a dropdown control to select the icon
    • Changing the icon in the “icon name” control changes the icon in the button
  • Confirm that icons are vertically centered:
    • with a single line of text
    • with multiple lines of text
    • with large font sizes
    • with small font sizes
    • with large icon sizes
    • with small icon sizes
  • Confirm that icons are aligned when added before the text
  • Confirm that updating the value in $theme-button-column-gap changes the space between buttons as expected
  • Confirm no visual regressions in button or button group components
  • Confirm that button groups are aligned in height when only some buttons in the group have an icon
    • Adding an icon to one button in a group makes the button a different height. I think this is ok but it would be nice to do a fast follow-up to fix this.
      image

@mahoneycm
Copy link
Contributor

I like @amyleadem's idea of renaming the setting from $theme-button-column-gap to something like $theme-button-icon-gap. It's a bit more descriptive which I appreciate!

James Mejia added 3 commits September 25, 2023 12:28
- Renamed from `$theme-button-column-gap → $theme-button-icon-gap` for clarity.
- Sorted button settings in alphabetical order.
@mejiaj mejiaj requested a review from amyleadem September 25, 2023 17:49
@mejiaj
Copy link
Contributor Author

mejiaj commented Sep 25, 2023

@amyleadem @mahoneycm appreciate the suggestions. I've made the following changes:

  • Renamed icon setting to $theme-button-column-gap → $theme-button-icon-gap.
  • Update PR description.
  • Added text-align: center back to button.
  • Internal: Renamed storybook control icon_included → add_icon.

Copy link
Contributor

@amyleadem amyleadem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

All updates look good. I also was able to successfully test both the visuals and settings configuration for $theme-button-icon-gap in uswds-sandbox.

<button class="usa-button" type="button">
    Default
    <svg class="usa-icon" aria-hidden="true" focusable="false" role="img">
        <use xlink:href="/assets/img/sprite.svg#add"></use>
      </svg>
</button>

$theme-button-icon-gap: 1

image

$theme-button-icon-gap: 3

image

@amyleadem
Copy link
Contributor

@mejiaj One more question - should we consider this a potentially breaking change since users might have already added custom/conflicting styles to add icons? Probably worth warning them to confirm that their buttons with icons display as expected.

Copy link
Contributor

@mahoneycm mahoneycm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review checklist

  • Icons in buttons should be visually centered.
  • Button stories have a control to toggle icons.
    • If Include icon is true, show a dropdown of icons.
    • Icons should update on select.
  • $theme-button-icon-gap works as expected.
  • There should be no html:build errors.
  • Code looks good
  • No visual regressions where <button class="usa-button"></button> is used
  • Tested on site with Copy Code button and it worked like a charm 👍
  • Template w/ Macros still easily modifiable
  • PR description is up to date

@mejiaj
Copy link
Contributor Author

mejiaj commented Oct 11, 2023

@mejiaj One more question - should we consider this a potentially breaking change since users might have already added custom/conflicting styles to add icons? Probably worth warning them to confirm that their buttons with icons display as expected.

Undecided on this. I don't feel like the impact is that big, but open to suggestions.

It would be worth flagging that it's now supported so users can remove their custom styles. But labelling it Potentially breaking seems heavy.

Copy link
Contributor

@thisisdano thisisdano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good update

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

USWDS - Feature: Improve appearance of icons in buttons
4 participants