-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Conversation

There was a problem hiding this 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.
- If
- There should be no
html:build
errors.

There was a problem hiding this 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" }, |
There was a problem hiding this comment.
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.
// @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; | ||
} | ||
|
There was a problem hiding this comment.
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.
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.
.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>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Co-authored-by: Amy Leadem <[email protected]>
Includes new setting $theme-button-column-gap, which takes units for the inner spacing.
Ensure type is passed & fix aria-disabled on big variant.
There was a problem hiding this 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.
- If
- 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
@mahoneycm thanks for the review. I've responded to questions & updated PR description ― good catch! |
There was a problem hiding this 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
- Setting “Add icon” to
- 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
I like @amyleadem's idea of renaming the setting from |
- Renamed from `$theme-button-column-gap → $theme-button-icon-gap` for clarity. - Sorted button settings in alphabetical order.
@amyleadem @mahoneycm appreciate the suggestions. I've made the following changes:
|
There was a problem hiding this 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
$theme-button-icon-gap: 3
@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. |
There was a problem hiding this 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.
- If
-
$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
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good update
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.

Control:
icon_name
(Depends onadd_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.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

After
Added icon to both sides to illustrate spacing via
$theme-button-icon-gap
.Solution
Improved support for buttons with inline
usa-icons
usinginline-flex
.Why this approach was chosen
column-gap
property.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 useinline-grid
or. These features provide more control, but have their own problems:inline-flex
:has()
doesn't have crossbrowser support.:has()
pseudoselector. The plugin for postcss requires a JS polyfill to be included & has performance issues.Major changes
$theme-button-icon-gap
Testing and review
Icon alignment
Storybook Controls
add_icon
is visible.True
.icon_name
shows as a dropdown for setting icon.Testing checklist
Include icon
is true, show a dropdown of icons.html:build
errors.