diff --git a/.bundlewatch.config.json b/.bundlewatch.config.json index bb0a5a85a694..3bcc296890bd 100644 --- a/.bundlewatch.config.json +++ b/.bundlewatch.config.json @@ -26,11 +26,11 @@ }, { "path": "./dist/css/bootstrap.css", - "maxSize": "32.5 kB" + "maxSize": "32.75 kB" }, { "path": "./dist/css/bootstrap.min.css", - "maxSize": "30.25 kB" + "maxSize": "30.75 kB" }, { "path": "./dist/js/bootstrap.bundle.js", diff --git a/scss/_chip.scss b/scss/_chip.scss new file mode 100644 index 000000000000..c3f677a6641c --- /dev/null +++ b/scss/_chip.scss @@ -0,0 +1,106 @@ +// stylelint-disable function-disallowed-list + +// Base class +// + +.chip { + // scss-docs-start chip-css-vars + --#{$prefix}chip-gap: #{$chip-gap}; + --#{$prefix}chip-padding-x: #{$chip-padding-x}; + --#{$prefix}chip-padding-y: #{$chip-padding-y}; + @include rfs($chip-font-size, --#{$prefix}chip-font-size); + --#{$prefix}chip-font-shift: #{$chip-font-shift}; + --#{$prefix}chip-font-weight: #{$chip-font-weight}; + --#{$prefix}chip-icon-size: #{$chip-icon-size}; + --#{$prefix}chip-icon-margin-start: #{$chip-icon-margin-start}; + --#{$prefix}chip-close-size: .5rem; + --#{$prefix}chip-close-margin-end: #{$chip-close-margin-end}; + --#{$prefix}chip-close-margin-start: #{$chip-close-margin-start}; + --#{$prefix}chip-border-width: #{$chip-border-width}; + --#{$prefix}chip-border-radius: #{$chip-border-radius}; + --#{$prefix}chip-border-color: #{$chip-border-color}; + --#{$prefix}chip-active-color: #{$chip-active-color}; + --#{$prefix}chip-active-decoration-color: #{$chip-active-decoration-color}; + --#{$prefix}chip-disabled-color: #{$chip-disabled-color}; + --#{$prefix}chip-outline-color: var(--#{$prefix}link-hover-color); + // scss-docs-end chip-css-vars + + display: inline-flex; + gap: var(--#{$prefix}chip-gap); + align-items: center; + padding: subtract(var(--#{$prefix}chip-padding-y), calc(var(--#{$prefix}chip-font-shift) * .5)) var(--#{$prefix}chip-padding-x) add(var(--#{$prefix}chip-padding-y), calc(var(--#{$prefix}chip-font-shift) * .5)); + @include font-size(var(--#{$prefix}chip-font-size)); + font-weight: var(--#{$prefix}chip-font-weight); + line-height: add(var(--#{$prefix}chip-font-size), .125rem); + color: inherit; + background-color: transparent; + border: var(--#{$prefix}chip-border-width) solid var(--#{$prefix}chip-border-color); + @include border-radius(var(--#{$prefix}chip-border-radius)); + + img, + svg { + width: var(--#{$prefix}chip-icon-size); + min-width: var(--#{$prefix}chip-icon-size); // Here to avoid weird behavior on wrap + height: var(--#{$prefix}chip-icon-size); + margin: add(calc(-.5 * var(--#{$prefix}chip-icon-size)), var(--#{$prefix}chip-font-shift)) 0 calc(-.5 * var(--#{$prefix}chip-icon-size)) var(--#{$prefix}chip-icon-margin-start); + } + + > .btn-close { + width: var(--#{$prefix}chip-close-size); + height: var(--#{$prefix}chip-close-size); + padding: .25em; + } + + &[disabled], + &.disabled { + color: var(--#{$prefix}chip-disabled-color); + pointer-events: none; + border-color: var(--#{$prefix}chip-disabled-color); + } +} + +// stylelint-disable selector-no-qualifying-type +a.chip, +button.chip, +label.chip { + color: inherit; + text-decoration: none; + cursor: pointer; + // outline-offset: $outline-offset; + + &:hover { + border-color: var(--#{$prefix}chip-active-decoration-color); + } + + /* &:focus[data-focus-visible-added] { + outline: $outline-width * 1.5 solid var(--#{$prefix}chip-outline-color); + outline-offset: $outline-offset; + } */ + + &.active, + &:active { + color: var(--#{$prefix}chip-active-color); + background-color: var(--#{$prefix}chip-active-decoration-color); + border-color: var(--#{$prefix}chip-active-decoration-color); + + &[disabled], + &.disabled { + background-color: var(--#{$prefix}chip-disabled-color); + border-color: var(--#{$prefix}chip-disabled-color); + } + } +} +// stylelint-enable selector-no-qualifying-type + +.chip-sm { + // scss-docs-start chip-sm-css-vars + --#{$prefix}chip-padding-x: #{$chip-padding-x-sm}; + --#{$prefix}chip-padding-y: #{$chip-padding-y-sm}; + --#{$prefix}chip-font-size: #{$chip-font-size-sm}; + --#{$prefix}chip-icon-size: #{$chip-icon-size-sm}; + --#{$prefix}chip-icon-margin-start: #{$chip-icon-margin-start-sm}; + --#{$prefix}chip-close-margin-end: #{$chip-close-margin-end-sm}; + --#{$prefix}chip-close-margin-start: #{$chip-close-margin-start-sm}; + // scss-docs-end chip-sm-css-vars +} + diff --git a/scss/_variables.scss b/scss/_variables.scss index 06531395ea78..d1609774c4d3 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -1494,6 +1494,38 @@ $badge-padding-x: .65em !default; $badge-border-radius: var(--#{$prefix}border-radius) !default; // scss-docs-end badge-variables +// Chips + +// scss-docs-start chip-variables +$chip-gap: map-get($spacers, 1) !default; +$chip-font-shift: $spacer * .1 !default; +$chip-font-weight: $font-weight-normal !default; +$chip-border-width: $border-width !default; +$chip-border-radius: $border-radius !default; + +$chip-padding-x: $spacer * .65 !default; +$chip-padding-y: $spacer * .45 !default; +$chip-icon-size: $spacer * 1.2 !default; +$chip-icon-margin-start: -$spacer * .35 !default; +$chip-close-margin-end: -$spacer * .3 !default; +$chip-close-margin-start: $spacer * .2 !default; +$chip-font-size: $font-size-base !default; + +$chip-active-color: $component-active-color !default; +$chip-disabled-color: $gray-500 !default; +$chip-border-color: $gray-500 !default; +$chip-active-decoration-color: $component-active-bg !default; +// scss-docs-end chip-variables + +// scss-docs-start chip-sm-variables +$chip-padding-x-sm: $spacer * .4 !default; +$chip-padding-y-sm: $spacer * .25 !default; +$chip-icon-size-sm: $spacer !default; +$chip-icon-margin-start-sm: -$spacer * .1 !default; +$chip-close-margin-end-sm: -$spacer * .25 !default; +$chip-close-margin-start-sm: 0 !default; +$chip-font-size-sm: $font-size-sm !default; +// scss-docs-end chip-sm-variables // Modals diff --git a/scss/bootstrap.scss b/scss/bootstrap.scss index 449d704878fa..e94368d08308 100644 --- a/scss/bootstrap.scss +++ b/scss/bootstrap.scss @@ -43,6 +43,7 @@ @import "spinners"; @import "offcanvas"; @import "placeholders"; +@import "chip"; // Helpers @import "helpers"; diff --git a/scss/forms/_form-check.scss b/scss/forms/_form-check.scss index 8a1b639dfe6f..df4815b59179 100644 --- a/scss/forms/_form-check.scss +++ b/scss/forms/_form-check.scss @@ -177,6 +177,32 @@ filter: none; opacity: $form-check-btn-check-disabled-opacity; } + + + .chip { + color: var(--#{$prefix}chip-disabled-color); + pointer-events: none; + border-color: var(--#{$prefix}chip-disabled-color); + } + + &:checked + .chip { + color: var(--#{$prefix}chip-active-color); + background-color: var(--#{$prefix}chip-disabled-color); + } + } + + &:checked { + + .chip { + color: var(--bs-chip-active-color); + background-color: var(--bs-chip-active-decoration-color); + border-color: var(--bs-chip-active-decoration-color); + } + } + + &:focus-visible { + + .chip { + outline: 1px * 1.5 solid var(--#{$prefix}chip-outline-color); + outline-offset: .125rem; + } } } diff --git a/site/content/docs/5.3/components/chip.md b/site/content/docs/5.3/components/chip.md new file mode 100644 index 000000000000..80496865026b --- /dev/null +++ b/site/content/docs/5.3/components/chip.md @@ -0,0 +1,206 @@ +--- +layout: docs +title: Chips +description: Use chips to convey information, apply filters or display a selection of items. +group: components +toc: true +added: "5.3" +--- + +## Examples + +A chip is basically a `` that can contain text, and optionally an image and/or a close button. Please **adapt the HTML** to be semantically correct. + +{{< callout warning >}} +You shouldn't mix the different chips versions in the same area since they look the same and have different behaviors. +{{< /callout >}} + +### Informative + +Informative chips are built on top of `` and are usually used to display categories. They have no specific interaction. + +For a list of chips of an article, for example, add a heading (`

`) to explain that we are in a chips list and use `
    ` or `
      ` depending on the use case. + +{{< example >}} +
        +
      • Bird
      • +
      • + + + Twitter + +
      • +
      +{{< /example >}} + +### Filter + +A chip can be actionable either when built on top of a ` +
    1. + +
    2. +
+{{< /example >}} + +### Navigation + +Another way to build actionable chips is to build them on top of ``. These kind of chips are usually used as anchor links. + +Put an explicit heading to add semantics. The text of the link must be clear enough to explain the destination of the chip. +Most of the time, chips must be inside a list (`
    ` or `
      `). + +{{< example >}} +
        +
      1. 1. Introduction
      2. +
      3. 2. Exposure
      4. +
      +{{< /example >}} + +### Input + +This kind of chips are built on ``. + +For a list of selected items use `
        ` or `
          `. + +{{< example class="d-flex gap-2 align-items-center" >}} +
            +
          • + Dismissible chip + +
          • +
          • + + Dismissible chip + +
          • +
          +{{< /example >}} + +## Sizes + +{{< callout info >}} +We add an extra `

          ` around the `` here for accessibility concerns. +{{< /callout >}} + +Add `.chip-sm` to the `.chip` for a small variant. + +{{< example class="d-flex gap-2 align-items-center" >}} +

          Small chip variant

          +

          Informative

          + +Navigation +

          + + Input + +

          +{{< /example >}} + +## Disabled state + +{{< callout info >}} +We add an extra `

          ` around the `` here for accessibility concerns. +{{< /callout >}} + +Add `.disabled` to the `.chip` for a disabled variant. Don't forget to add `aria-disabled` to `` and `disabled` attribute to ` +Navigation +

          + + Input + +

          +{{< /example >}} + +## Rounded chips + +Use the `.rounded-pill` utility class to make chips more rounded with a larger `border-radius`. + +{{< example class="d-flex gap-2 align-items-center" >}} +

          Rounded chip variant

          +

          Informative

          + +Navigation +

          + + Input + +

          +{{< /example >}} + +## CSS + +### Variables + +Values for the CSS variables are set via Sass, so Sass customization is still supported, too. + +{{< scss-docs name="chip-css-vars" file="scss/_chip.scss" >}} + +Customization through CSS variables can be seen on the `.chip-sm` class where we override specific values without adding duplicate CSS selectors. + +{{< scss-docs name="chip-sm-css-vars" file="scss/_chip.scss" >}} + +### Sass Variables + +Variables for all chips: + +{{< scss-docs name="chip-variables" file="scss/_variables.scss" >}} + +Variables for the [small chip](#sizes): + +{{< scss-docs name="chip-sm-variables" file="scss/_variables.scss" >}} diff --git a/site/content/docs/5.3/customize/overview.md b/site/content/docs/5.3/customize/overview.md index ed890acd0153..7cb63a463f09 100644 --- a/site/content/docs/5.3/customize/overview.md +++ b/site/content/docs/5.3/customize/overview.md @@ -49,5 +49,6 @@ Several Bootstrap components include embedded SVGs in our CSS to style component - [Form validation icons]({{< docsref "/forms/validation#server-side" >}}) - [Navbar toggle buttons]({{< docsref "/components/navbar#responsive-behaviors" >}}) - [Select menus]({{< docsref "/forms/select" >}}) +- [Chips]({{< docsref "/components/chip" >}}) Based on [community conversation](https://github.com/twbs/bootstrap/issues/25394), some options for addressing this in your own codebase include [replacing the URLs with locally hosted assets]({{< docsref "/getting-started/webpack#extracting-svg-files" >}}), removing the images and using inline images (not possible in all components), and modifying your CSP. Our recommendation is to carefully review your own security policies and decide on the best path forward, if necessary. diff --git a/site/data/sidebar.yml b/site/data/sidebar.yml index dea26b401a9e..989dede353cd 100644 --- a/site/data/sidebar.yml +++ b/site/data/sidebar.yml @@ -80,6 +80,7 @@ - title: Button group - title: Card - title: Carousel + - title: Chip - title: Close button - title: Collapse - title: Dropdowns