diff --git a/BREAKING.md b/BREAKING.md
index f9e61176941..746fcab9488 100644
--- a/BREAKING.md
+++ b/BREAKING.md
@@ -50,7 +50,86 @@ This is a comprehensive list of the breaking changes introduced in the major ver
Button
-- The `border-radius` of the `ios` and `md` button now defaults to `6px` and `999px` instead of `14px` and `4px`, respectively, in accordance with the iOS and Material Design 3 guidelines. To revert to the previous appearance, set the `shape` to `"soft"` for `md` and override the `--border-radius` CSS variable for `ios` to `14px`, or set it to a different value entirely.
+The following breaking changes apply to `ion-button`:
+
+1. The `border-radius` of the `ios` button is now `6px` at every size, instead of `6px`, `14px` and `16px` for the small, default and large sizes. The `md` button now defaults to `999px` instead of `4px`. Both follow the iOS and Material Design 3 guidelines. To revert to the previous appearance, set the `shape` to `"soft"` for `md`. For `ios`, set `IonButton.shape.soft.border.radius` for global styles or `--ion-button-shape-soft-border-radius` for component-specific styles to `14px`, and to `6px` and `16px` on small and large buttons.
+2. Icon-only buttons in the `start` and `end` slots of `ion-input`, `ion-select` and `ion-textarea` now follow the button's `shape` instead of always being circles. For `ios`, set the `shape` to `"round"` to keep them circular.
+3. The font size of `clear` buttons in the `ios` theme now matches the other fills at each size, instead of `17px` at the default size. To keep the previous size, set `--ion-button-size-medium-font-size` to `17px` on those buttons.
+4. The `ios` button is now `28px`, `34px` and `50px` tall at the small, default and large sizes, with less padding, following the iOS guidelines. To revert to the previous appearance, set `IonButton.size..min.height` for global styles or `--ion-button-size--min-height` for component-specific styles to `2.1em`, `3.1em` and `3.1em`, and the padding (`IonButton.size..padding` or `--ion-button-size--padding-*`) to `4px 0.9em`, `13px 1em` and `17px 1em`.
+5. Icon-only buttons are now squares as tall as a text button of the same size. In `md`, this makes them a few pixels smaller at the small and default sizes and larger at the large size. To change their size, set the size's `min.height` as described above.
+6. CSS variables have been replaced. [6](#version-10x-button-replaced-css-variables)
+7. `--padding-*` CSS variables are no longer part of the documented public API (but remain functional). [7](#version-10x-button-padding-variables)
+8. The fill, size, shape and expand classes have been renamed. [8](#version-10x-button-renamed-classes)
+9. The `default` size has been deprecated. [9](#version-10x-button-deprecated-default-size)
+10. Theme classes (`ion-button.md`, `ion-button.ios`) are no longer supported. [10](#version-10x-button-theme-classes)
+
+
Replaced CSS variables
+
+Use the new token structure for global styles, or the corresponding CSS variable for component-specific overrides. Replace `` with `solid`, `outline` or `clear`, and `` with `crisp`, `soft`, `round` or `rectangular`. Buttons with a `color` read the same tokens under `semantic`, for example `IonButton.hue.bold.solid.semantic.default.background`.
+
+| Old (9.x) | New token (global) | New CSS variable (component-specific) |
+|---|---|---|
+| `--background` | `IonButton.hue.bold..default.background` | `--ion-button-hue-bold--default-background` |
+| `--background-activated` | `IonButton.hue.bold..activated.background` | `--ion-button-hue-bold--activated-background` |
+| `--background-focused` | `IonButton.hue.bold..focus.background` | `--ion-button-hue-bold--focus-background` |
+| `--background-hover` | `IonButton.hue.bold..hover.background` | `--ion-button-hue-bold--hover-background` |
+| `--border-color` | `IonButton.hue.bold..default.border.color` | `--ion-button-hue-bold--default-border-color` |
+| `--border-radius` | `IonButton.shape..border.radius` | `--ion-button-shape--border-radius` |
+| `--border-style` | `IonButton.hue.bold..default.border.style` | `--ion-button-hue-bold--default-border-style` |
+| `--border-width` | `IonButton.hue.bold..default.border.width` | `--ion-button-hue-bold--default-border-width` |
+| `--box-shadow` | `IonButton.hue.bold..default.box.shadow` | `--ion-button-hue-bold--default-box-shadow` |
+| `--color` | `IonButton.hue.bold..default.color` | `--ion-button-hue-bold--default-color` |
+| `--color-activated` | `IonButton.hue.bold..activated.color` | `--ion-button-hue-bold--activated-color` |
+| `--color-focused` | `IonButton.hue.bold..focus.color` | `--ion-button-hue-bold--focus-color` |
+| `--color-hover` | `IonButton.hue.bold..hover.color` | `--ion-button-hue-bold--hover-color` |
+| `--ripple-color` | `IonButton.hue.bold..rippleEffect.color` | `--ion-button-hue-bold--ripple-effect-color` |
+| `--transition` | `IonButton.transition` | `--ion-button-transition` |
+
+> [!NOTE]
+> `--background-activated-opacity`, `--background-focused-opacity` and `--background-hover-opacity` have been removed with no one-to-one replacement. Each state's background is now a single color that includes its opacity, so set the final color, for example `color-mix(in srgb, var(--ion-color-primary) 12%, transparent)`. States are also drawn on the native element itself, so styles targeting `::part(native)::after` no longer affect them.
+
+> [!NOTE]
+> `--opacity` has been removed with no replacement. Set `opacity` on `ion-button` instead.
+
+
Padding variables
+
+New code should use the token-based API. Replace `` with `small`, `medium` or `large`, and use `iconOnly.padding` under the size for icon-only buttons:
+
+| Old (9.x) | New token (global) | New CSS variable (component-specific) |
+|---|---|---|
+| `--padding-top` | `IonButton.size..padding.top` | `--ion-button-size--padding-top` |
+| `--padding-end` | `IonButton.size..padding.end` | `--ion-button-size--padding-end` |
+| `--padding-bottom` | `IonButton.size..padding.bottom` | `--ion-button-size--padding-bottom` |
+| `--padding-start` | `IonButton.size..padding.start` | `--ion-button-size--padding-start` |
+
+> [!NOTE]
+> The `--padding-*` overrides and the `.ion-padding`, `.ion-padding-*` utility classes in `css/padding.scss` continue to work when set on the button itself: `ion-button` honors them ahead of the new tokens. They are no longer part of the documented public API (only `--ion-button-size--padding-*` is listed in `core/api.txt`), but existing usage will not break.
+
+
+
+The `default` value of the `size` property is deprecated. It logs a warning and renders the same as `medium`. Use `size="medium"` instead.
+
+
Theme classes
+
+Remove any instances that target the theme classes: `ion-button.md`, `ion-button.ios`.
Card
diff --git a/core/api.txt b/core/api.txt
index 5b4a827ab45..4236009ffa4 100644
--- a/core/api.txt
+++ b/core/api.txt
@@ -443,83 +443,248 @@ ion-button,prop,mode,"ios" | "md",undefined,false,false
ion-button,prop,rel,string | undefined,undefined,false,false
ion-button,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-button,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
-ion-button,prop,shape,"rectangular" | "round" | "soft" | undefined,undefined,false,true
+ion-button,prop,shape,"crisp" | "rectangular" | "round" | "soft" | undefined,undefined,false,true
ion-button,prop,size,"default" | "large" | "medium" | "small" | undefined,undefined,false,true
ion-button,prop,strong,boolean,false,false,false
ion-button,prop,target,string | undefined,undefined,false,false
-ion-button,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-button,prop,type,"button" | "reset" | "submit",'button',false,false
ion-button,event,ionBlur,void,true
ion-button,event,ionFocus,void,true
-ion-button,css-prop,--background,ionic
-ion-button,css-prop,--background,ios
-ion-button,css-prop,--background,md
-ion-button,css-prop,--background-activated,ionic
-ion-button,css-prop,--background-activated,ios
-ion-button,css-prop,--background-activated,md
-ion-button,css-prop,--background-activated-opacity,ionic
-ion-button,css-prop,--background-activated-opacity,ios
-ion-button,css-prop,--background-activated-opacity,md
-ion-button,css-prop,--background-focused,ionic
-ion-button,css-prop,--background-focused,ios
-ion-button,css-prop,--background-focused,md
-ion-button,css-prop,--background-focused-opacity,ionic
-ion-button,css-prop,--background-focused-opacity,ios
-ion-button,css-prop,--background-focused-opacity,md
-ion-button,css-prop,--background-hover,ionic
-ion-button,css-prop,--background-hover,ios
-ion-button,css-prop,--background-hover,md
-ion-button,css-prop,--background-hover-opacity,ionic
-ion-button,css-prop,--background-hover-opacity,ios
-ion-button,css-prop,--background-hover-opacity,md
-ion-button,css-prop,--border-color,ionic
-ion-button,css-prop,--border-color,ios
-ion-button,css-prop,--border-color,md
-ion-button,css-prop,--border-radius,ionic
-ion-button,css-prop,--border-radius,ios
-ion-button,css-prop,--border-radius,md
-ion-button,css-prop,--border-style,ionic
-ion-button,css-prop,--border-style,ios
-ion-button,css-prop,--border-style,md
-ion-button,css-prop,--border-width,ionic
-ion-button,css-prop,--border-width,ios
-ion-button,css-prop,--border-width,md
-ion-button,css-prop,--box-shadow,ionic
-ion-button,css-prop,--box-shadow,ios
-ion-button,css-prop,--box-shadow,md
-ion-button,css-prop,--color,ionic
-ion-button,css-prop,--color,ios
-ion-button,css-prop,--color,md
-ion-button,css-prop,--color-activated,ionic
-ion-button,css-prop,--color-activated,ios
-ion-button,css-prop,--color-activated,md
-ion-button,css-prop,--color-focused,ionic
-ion-button,css-prop,--color-focused,ios
-ion-button,css-prop,--color-focused,md
-ion-button,css-prop,--color-hover,ionic
-ion-button,css-prop,--color-hover,ios
-ion-button,css-prop,--color-hover,md
-ion-button,css-prop,--opacity,ionic
-ion-button,css-prop,--opacity,ios
-ion-button,css-prop,--opacity,md
-ion-button,css-prop,--padding-bottom,ionic
-ion-button,css-prop,--padding-bottom,ios
-ion-button,css-prop,--padding-bottom,md
-ion-button,css-prop,--padding-end,ionic
-ion-button,css-prop,--padding-end,ios
-ion-button,css-prop,--padding-end,md
-ion-button,css-prop,--padding-start,ionic
-ion-button,css-prop,--padding-start,ios
-ion-button,css-prop,--padding-start,md
-ion-button,css-prop,--padding-top,ionic
-ion-button,css-prop,--padding-top,ios
-ion-button,css-prop,--padding-top,md
-ion-button,css-prop,--ripple-color,ionic
-ion-button,css-prop,--ripple-color,ios
-ion-button,css-prop,--ripple-color,md
-ion-button,css-prop,--transition,ionic
-ion-button,css-prop,--transition,ios
-ion-button,css-prop,--transition,md
+ion-button,css-prop,--ion-button-font-family
+ion-button,css-prop,--ion-button-hue-bold-clear-activated-background
+ion-button,css-prop,--ion-button-hue-bold-clear-activated-box-shadow
+ion-button,css-prop,--ion-button-hue-bold-clear-activated-color
+ion-button,css-prop,--ion-button-hue-bold-clear-activated-opacity
+ion-button,css-prop,--ion-button-hue-bold-clear-default-background
+ion-button,css-prop,--ion-button-hue-bold-clear-default-border-color
+ion-button,css-prop,--ion-button-hue-bold-clear-default-border-style
+ion-button,css-prop,--ion-button-hue-bold-clear-default-border-width
+ion-button,css-prop,--ion-button-hue-bold-clear-default-box-shadow
+ion-button,css-prop,--ion-button-hue-bold-clear-default-color
+ion-button,css-prop,--ion-button-hue-bold-clear-default-font-weight
+ion-button,css-prop,--ion-button-hue-bold-clear-disabled-background
+ion-button,css-prop,--ion-button-hue-bold-clear-disabled-opacity
+ion-button,css-prop,--ion-button-hue-bold-clear-focus-background
+ion-button,css-prop,--ion-button-hue-bold-clear-focus-color
+ion-button,css-prop,--ion-button-hue-bold-clear-hover-background
+ion-button,css-prop,--ion-button-hue-bold-clear-hover-color
+ion-button,css-prop,--ion-button-hue-bold-clear-hover-opacity
+ion-button,css-prop,--ion-button-hue-bold-clear-ripple-effect-color
+ion-button,css-prop,--ion-button-hue-bold-clear-ripple-effect-opacity
+ion-button,css-prop,--ion-button-hue-bold-clear-semantic-activated-background
+ion-button,css-prop,--ion-button-hue-bold-clear-semantic-activated-color
+ion-button,css-prop,--ion-button-hue-bold-clear-semantic-default-background
+ion-button,css-prop,--ion-button-hue-bold-clear-semantic-default-border-color
+ion-button,css-prop,--ion-button-hue-bold-clear-semantic-default-color
+ion-button,css-prop,--ion-button-hue-bold-clear-semantic-disabled-background
+ion-button,css-prop,--ion-button-hue-bold-clear-semantic-focus-background
+ion-button,css-prop,--ion-button-hue-bold-clear-semantic-focus-color
+ion-button,css-prop,--ion-button-hue-bold-clear-semantic-hover-background
+ion-button,css-prop,--ion-button-hue-bold-clear-semantic-hover-color
+ion-button,css-prop,--ion-button-hue-bold-clear-semantic-ripple-effect-color
+ion-button,css-prop,--ion-button-hue-bold-clear-semantic-ripple-effect-opacity
+ion-button,css-prop,--ion-button-hue-bold-clear-strong-font-weight
+ion-button,css-prop,--ion-button-hue-bold-outline-activated-background
+ion-button,css-prop,--ion-button-hue-bold-outline-activated-box-shadow
+ion-button,css-prop,--ion-button-hue-bold-outline-activated-color
+ion-button,css-prop,--ion-button-hue-bold-outline-activated-opacity
+ion-button,css-prop,--ion-button-hue-bold-outline-default-background
+ion-button,css-prop,--ion-button-hue-bold-outline-default-border-color
+ion-button,css-prop,--ion-button-hue-bold-outline-default-border-style
+ion-button,css-prop,--ion-button-hue-bold-outline-default-border-width
+ion-button,css-prop,--ion-button-hue-bold-outline-default-box-shadow
+ion-button,css-prop,--ion-button-hue-bold-outline-default-color
+ion-button,css-prop,--ion-button-hue-bold-outline-default-font-weight
+ion-button,css-prop,--ion-button-hue-bold-outline-disabled-background
+ion-button,css-prop,--ion-button-hue-bold-outline-disabled-opacity
+ion-button,css-prop,--ion-button-hue-bold-outline-focus-background
+ion-button,css-prop,--ion-button-hue-bold-outline-focus-color
+ion-button,css-prop,--ion-button-hue-bold-outline-hover-background
+ion-button,css-prop,--ion-button-hue-bold-outline-hover-color
+ion-button,css-prop,--ion-button-hue-bold-outline-hover-opacity
+ion-button,css-prop,--ion-button-hue-bold-outline-ripple-effect-color
+ion-button,css-prop,--ion-button-hue-bold-outline-ripple-effect-opacity
+ion-button,css-prop,--ion-button-hue-bold-outline-semantic-activated-background
+ion-button,css-prop,--ion-button-hue-bold-outline-semantic-activated-color
+ion-button,css-prop,--ion-button-hue-bold-outline-semantic-default-background
+ion-button,css-prop,--ion-button-hue-bold-outline-semantic-default-border-color
+ion-button,css-prop,--ion-button-hue-bold-outline-semantic-default-color
+ion-button,css-prop,--ion-button-hue-bold-outline-semantic-disabled-background
+ion-button,css-prop,--ion-button-hue-bold-outline-semantic-focus-background
+ion-button,css-prop,--ion-button-hue-bold-outline-semantic-focus-color
+ion-button,css-prop,--ion-button-hue-bold-outline-semantic-hover-background
+ion-button,css-prop,--ion-button-hue-bold-outline-semantic-hover-color
+ion-button,css-prop,--ion-button-hue-bold-outline-semantic-ripple-effect-color
+ion-button,css-prop,--ion-button-hue-bold-outline-semantic-ripple-effect-opacity
+ion-button,css-prop,--ion-button-hue-bold-outline-strong-font-weight
+ion-button,css-prop,--ion-button-hue-bold-solid-activated-background
+ion-button,css-prop,--ion-button-hue-bold-solid-activated-box-shadow
+ion-button,css-prop,--ion-button-hue-bold-solid-activated-color
+ion-button,css-prop,--ion-button-hue-bold-solid-activated-opacity
+ion-button,css-prop,--ion-button-hue-bold-solid-default-background
+ion-button,css-prop,--ion-button-hue-bold-solid-default-border-color
+ion-button,css-prop,--ion-button-hue-bold-solid-default-border-style
+ion-button,css-prop,--ion-button-hue-bold-solid-default-border-width
+ion-button,css-prop,--ion-button-hue-bold-solid-default-box-shadow
+ion-button,css-prop,--ion-button-hue-bold-solid-default-color
+ion-button,css-prop,--ion-button-hue-bold-solid-default-font-weight
+ion-button,css-prop,--ion-button-hue-bold-solid-disabled-background
+ion-button,css-prop,--ion-button-hue-bold-solid-disabled-opacity
+ion-button,css-prop,--ion-button-hue-bold-solid-focus-background
+ion-button,css-prop,--ion-button-hue-bold-solid-focus-color
+ion-button,css-prop,--ion-button-hue-bold-solid-hover-background
+ion-button,css-prop,--ion-button-hue-bold-solid-hover-color
+ion-button,css-prop,--ion-button-hue-bold-solid-hover-opacity
+ion-button,css-prop,--ion-button-hue-bold-solid-ripple-effect-color
+ion-button,css-prop,--ion-button-hue-bold-solid-ripple-effect-opacity
+ion-button,css-prop,--ion-button-hue-bold-solid-semantic-activated-background
+ion-button,css-prop,--ion-button-hue-bold-solid-semantic-activated-color
+ion-button,css-prop,--ion-button-hue-bold-solid-semantic-default-background
+ion-button,css-prop,--ion-button-hue-bold-solid-semantic-default-border-color
+ion-button,css-prop,--ion-button-hue-bold-solid-semantic-default-color
+ion-button,css-prop,--ion-button-hue-bold-solid-semantic-disabled-background
+ion-button,css-prop,--ion-button-hue-bold-solid-semantic-focus-background
+ion-button,css-prop,--ion-button-hue-bold-solid-semantic-focus-color
+ion-button,css-prop,--ion-button-hue-bold-solid-semantic-hover-background
+ion-button,css-prop,--ion-button-hue-bold-solid-semantic-hover-color
+ion-button,css-prop,--ion-button-hue-bold-solid-semantic-ripple-effect-color
+ion-button,css-prop,--ion-button-hue-bold-solid-semantic-ripple-effect-opacity
+ion-button,css-prop,--ion-button-hue-bold-solid-strong-font-weight
+ion-button,css-prop,--ion-button-letter-spacing
+ion-button,css-prop,--ion-button-margin-bottom
+ion-button,css-prop,--ion-button-margin-end
+ion-button,css-prop,--ion-button-margin-start
+ion-button,css-prop,--ion-button-margin-top
+ion-button,css-prop,--ion-button-shape-crisp-border-radius
+ion-button,css-prop,--ion-button-shape-rectangular-border-radius
+ion-button,css-prop,--ion-button-shape-round-border-radius
+ion-button,css-prop,--ion-button-shape-soft-border-radius
+ion-button,css-prop,--ion-button-size-large-font-size
+ion-button,css-prop,--ion-button-size-large-icon-font-size
+ion-button,css-prop,--ion-button-size-large-icon-leading-margin-bottom
+ion-button,css-prop,--ion-button-size-large-icon-leading-margin-end
+ion-button,css-prop,--ion-button-size-large-icon-leading-margin-start
+ion-button,css-prop,--ion-button-size-large-icon-leading-margin-top
+ion-button,css-prop,--ion-button-size-large-icon-only-icon-font-size
+ion-button,css-prop,--ion-button-size-large-icon-only-padding-bottom
+ion-button,css-prop,--ion-button-size-large-icon-only-padding-end
+ion-button,css-prop,--ion-button-size-large-icon-only-padding-start
+ion-button,css-prop,--ion-button-size-large-icon-only-padding-top
+ion-button,css-prop,--ion-button-size-large-icon-trailing-margin-bottom
+ion-button,css-prop,--ion-button-size-large-icon-trailing-margin-end
+ion-button,css-prop,--ion-button-size-large-icon-trailing-margin-start
+ion-button,css-prop,--ion-button-size-large-icon-trailing-margin-top
+ion-button,css-prop,--ion-button-size-large-line-height
+ion-button,css-prop,--ion-button-size-large-min-height
+ion-button,css-prop,--ion-button-size-large-min-width
+ion-button,css-prop,--ion-button-size-large-padding-bottom
+ion-button,css-prop,--ion-button-size-large-padding-end
+ion-button,css-prop,--ion-button-size-large-padding-start
+ion-button,css-prop,--ion-button-size-large-padding-top
+ion-button,css-prop,--ion-button-size-large-spinner-leading-margin-bottom
+ion-button,css-prop,--ion-button-size-large-spinner-leading-margin-end
+ion-button,css-prop,--ion-button-size-large-spinner-leading-margin-start
+ion-button,css-prop,--ion-button-size-large-spinner-leading-margin-top
+ion-button,css-prop,--ion-button-size-large-spinner-size-large-height
+ion-button,css-prop,--ion-button-size-large-spinner-size-large-width
+ion-button,css-prop,--ion-button-size-large-spinner-size-medium-height
+ion-button,css-prop,--ion-button-size-large-spinner-size-medium-width
+ion-button,css-prop,--ion-button-size-large-spinner-size-small-height
+ion-button,css-prop,--ion-button-size-large-spinner-size-small-width
+ion-button,css-prop,--ion-button-size-large-spinner-size-xlarge-height
+ion-button,css-prop,--ion-button-size-large-spinner-size-xlarge-width
+ion-button,css-prop,--ion-button-size-large-spinner-size-xsmall-height
+ion-button,css-prop,--ion-button-size-large-spinner-size-xsmall-width
+ion-button,css-prop,--ion-button-size-large-spinner-trailing-margin-bottom
+ion-button,css-prop,--ion-button-size-large-spinner-trailing-margin-end
+ion-button,css-prop,--ion-button-size-large-spinner-trailing-margin-start
+ion-button,css-prop,--ion-button-size-large-spinner-trailing-margin-top
+ion-button,css-prop,--ion-button-size-medium-font-size
+ion-button,css-prop,--ion-button-size-medium-icon-font-size
+ion-button,css-prop,--ion-button-size-medium-icon-leading-margin-bottom
+ion-button,css-prop,--ion-button-size-medium-icon-leading-margin-end
+ion-button,css-prop,--ion-button-size-medium-icon-leading-margin-start
+ion-button,css-prop,--ion-button-size-medium-icon-leading-margin-top
+ion-button,css-prop,--ion-button-size-medium-icon-only-icon-font-size
+ion-button,css-prop,--ion-button-size-medium-icon-only-padding-bottom
+ion-button,css-prop,--ion-button-size-medium-icon-only-padding-end
+ion-button,css-prop,--ion-button-size-medium-icon-only-padding-start
+ion-button,css-prop,--ion-button-size-medium-icon-only-padding-top
+ion-button,css-prop,--ion-button-size-medium-icon-trailing-margin-bottom
+ion-button,css-prop,--ion-button-size-medium-icon-trailing-margin-end
+ion-button,css-prop,--ion-button-size-medium-icon-trailing-margin-start
+ion-button,css-prop,--ion-button-size-medium-icon-trailing-margin-top
+ion-button,css-prop,--ion-button-size-medium-line-height
+ion-button,css-prop,--ion-button-size-medium-min-height
+ion-button,css-prop,--ion-button-size-medium-min-width
+ion-button,css-prop,--ion-button-size-medium-padding-bottom
+ion-button,css-prop,--ion-button-size-medium-padding-end
+ion-button,css-prop,--ion-button-size-medium-padding-start
+ion-button,css-prop,--ion-button-size-medium-padding-top
+ion-button,css-prop,--ion-button-size-medium-spinner-leading-margin-bottom
+ion-button,css-prop,--ion-button-size-medium-spinner-leading-margin-end
+ion-button,css-prop,--ion-button-size-medium-spinner-leading-margin-start
+ion-button,css-prop,--ion-button-size-medium-spinner-leading-margin-top
+ion-button,css-prop,--ion-button-size-medium-spinner-size-large-height
+ion-button,css-prop,--ion-button-size-medium-spinner-size-large-width
+ion-button,css-prop,--ion-button-size-medium-spinner-size-medium-height
+ion-button,css-prop,--ion-button-size-medium-spinner-size-medium-width
+ion-button,css-prop,--ion-button-size-medium-spinner-size-small-height
+ion-button,css-prop,--ion-button-size-medium-spinner-size-small-width
+ion-button,css-prop,--ion-button-size-medium-spinner-size-xlarge-height
+ion-button,css-prop,--ion-button-size-medium-spinner-size-xlarge-width
+ion-button,css-prop,--ion-button-size-medium-spinner-size-xsmall-height
+ion-button,css-prop,--ion-button-size-medium-spinner-size-xsmall-width
+ion-button,css-prop,--ion-button-size-medium-spinner-trailing-margin-bottom
+ion-button,css-prop,--ion-button-size-medium-spinner-trailing-margin-end
+ion-button,css-prop,--ion-button-size-medium-spinner-trailing-margin-start
+ion-button,css-prop,--ion-button-size-medium-spinner-trailing-margin-top
+ion-button,css-prop,--ion-button-size-small-font-size
+ion-button,css-prop,--ion-button-size-small-icon-font-size
+ion-button,css-prop,--ion-button-size-small-icon-leading-margin-bottom
+ion-button,css-prop,--ion-button-size-small-icon-leading-margin-end
+ion-button,css-prop,--ion-button-size-small-icon-leading-margin-start
+ion-button,css-prop,--ion-button-size-small-icon-leading-margin-top
+ion-button,css-prop,--ion-button-size-small-icon-only-icon-font-size
+ion-button,css-prop,--ion-button-size-small-icon-only-padding-bottom
+ion-button,css-prop,--ion-button-size-small-icon-only-padding-end
+ion-button,css-prop,--ion-button-size-small-icon-only-padding-start
+ion-button,css-prop,--ion-button-size-small-icon-only-padding-top
+ion-button,css-prop,--ion-button-size-small-icon-trailing-margin-bottom
+ion-button,css-prop,--ion-button-size-small-icon-trailing-margin-end
+ion-button,css-prop,--ion-button-size-small-icon-trailing-margin-start
+ion-button,css-prop,--ion-button-size-small-icon-trailing-margin-top
+ion-button,css-prop,--ion-button-size-small-line-height
+ion-button,css-prop,--ion-button-size-small-min-height
+ion-button,css-prop,--ion-button-size-small-min-width
+ion-button,css-prop,--ion-button-size-small-padding-bottom
+ion-button,css-prop,--ion-button-size-small-padding-end
+ion-button,css-prop,--ion-button-size-small-padding-start
+ion-button,css-prop,--ion-button-size-small-padding-top
+ion-button,css-prop,--ion-button-size-small-spinner-leading-margin-bottom
+ion-button,css-prop,--ion-button-size-small-spinner-leading-margin-end
+ion-button,css-prop,--ion-button-size-small-spinner-leading-margin-start
+ion-button,css-prop,--ion-button-size-small-spinner-leading-margin-top
+ion-button,css-prop,--ion-button-size-small-spinner-size-large-height
+ion-button,css-prop,--ion-button-size-small-spinner-size-large-width
+ion-button,css-prop,--ion-button-size-small-spinner-size-medium-height
+ion-button,css-prop,--ion-button-size-small-spinner-size-medium-width
+ion-button,css-prop,--ion-button-size-small-spinner-size-small-height
+ion-button,css-prop,--ion-button-size-small-spinner-size-small-width
+ion-button,css-prop,--ion-button-size-small-spinner-size-xlarge-height
+ion-button,css-prop,--ion-button-size-small-spinner-size-xlarge-width
+ion-button,css-prop,--ion-button-size-small-spinner-size-xsmall-height
+ion-button,css-prop,--ion-button-size-small-spinner-size-xsmall-width
+ion-button,css-prop,--ion-button-size-small-spinner-trailing-margin-bottom
+ion-button,css-prop,--ion-button-size-small-spinner-trailing-margin-end
+ion-button,css-prop,--ion-button-size-small-spinner-trailing-margin-start
+ion-button,css-prop,--ion-button-size-small-spinner-trailing-margin-top
+ion-button,css-prop,--ion-button-state-focus-ring-color
+ion-button,css-prop,--ion-button-state-focus-ring-offset
+ion-button,css-prop,--ion-button-state-focus-ring-style
+ion-button,css-prop,--ion-button-state-focus-ring-width
+ion-button,css-prop,--ion-button-text-transform
+ion-button,css-prop,--ion-button-transition
ion-button,part,native
ion-buttons,scoped
diff --git a/core/src/components.d.ts b/core/src/components.d.ts
index a25784da787..77dc1472557 100644
--- a/core/src/components.d.ts
+++ b/core/src/components.d.ts
@@ -15,6 +15,7 @@ import { Hue } from "./themes/themes.interfaces";
import { IonBadgeShape, IonBadgeSize, IonBadgeVerticalPosition } from "./components/badge/badge.interfaces";
import { RouteID, RouterDirection, RouterEventDetail, RouteWrite } from "./components/router/utils/interface";
import { BreadcrumbCollapsedClickEventDetail } from "./components/breadcrumb/breadcrumb-interface";
+import { IonButtonExpand, IonButtonFill, IonButtonShape, IonButtonSize } from "./components/button/button.interface";
import { CheckboxChangeEventDetail } from "./components/checkbox/checkbox-interface";
import { IonChipFill, IonChipShape, IonChipSize } from "./components/chip/chip.interfaces";
import { ScrollBaseDetail, ScrollDetail } from "./components/content/content.interfaces";
@@ -61,6 +62,7 @@ export { Hue } from "./themes/themes.interfaces";
export { IonBadgeShape, IonBadgeSize, IonBadgeVerticalPosition } from "./components/badge/badge.interfaces";
export { RouteID, RouterDirection, RouterEventDetail, RouteWrite } from "./components/router/utils/interface";
export { BreadcrumbCollapsedClickEventDetail } from "./components/breadcrumb/breadcrumb-interface";
+export { IonButtonExpand, IonButtonFill, IonButtonShape, IonButtonSize } from "./components/button/button.interface";
export { CheckboxChangeEventDetail } from "./components/checkbox/checkbox-interface";
export { IonChipFill, IonChipShape, IonChipSize } from "./components/chip/chip.interfaces";
export { ScrollBaseDetail, ScrollDetail } from "./components/content/content.interfaces";
@@ -610,11 +612,11 @@ export namespace Components {
/**
* Set to `"block"` for a full-width button or to `"full"` for a full-width button with square corners and no left or right borders.
*/
- "expand"?: 'full' | 'block';
+ "expand"?: IonButtonExpand;
/**
- * Set to `"clear"` for a transparent button that resembles a flat button, to `"outline"` for a transparent button with a border, or to `"solid"` for a button with a filled background. The default fill is `"solid"` except when inside of a buttons or datetime component, where the default fill is `"clear"`.
+ * Set to `"clear"` for a transparent button that resembles a flat button, `"outline"` for a transparent button with a border, or `"solid"` for a button with a filled background. Defaults to `"solid"` if both the fill property and theme config are unset, or `"clear"` inside of buttons, datetime, or list header.
*/
- "fill"?: 'clear' | 'outline' | 'solid' | 'default';
+ "fill"?: IonButtonFill | 'default';
/**
* The HTML form element or form element id. Used to submit a form when the button is not a child of the form.
*/
@@ -641,13 +643,13 @@ export namespace Components {
*/
"routerDirection": RouterDirection;
/**
- * Set to `"soft"` for a button with slightly rounded corners, `"round"` for a button with fully rounded corners, or `"rectangular"` for a button without rounded corners. Defaults to `"soft"` for the `"ios"` theme and `"round"` for all other themes.
+ * Set to `"crisp"` for a button with even slightly rounded corners, `"soft"` for a button with slightly rounded corners, `"round"` for a button with fully rounded corners, or `"rectangular"` for a button without rounded corners. Defaults to `"round"` if both the shape property and theme config are unset.
*/
- "shape"?: 'soft' | 'round' | 'rectangular';
+ "shape"?: IonButtonShape;
/**
- * Set to `"small"` for a button with less height and padding, to `"medium"` for a button with the medium height and padding, or to `"large"` for a button with more height and padding. By default the size is unset, unless the button is inside of an item, where the size is `"small"` by default. Set the size to `"default"` inside of an item to make it a standard size button.
+ * Set to `"small"` for a button with less height and padding, `"medium"` for a button with the standard height and padding, or `"large"` for a button with more height and padding. Defaults to `"medium"` if both the size property and theme config are unset, or `"small"` inside of an item. `"default"` is deprecated and renders the same as `"medium"`.
*/
- "size"?: 'small' | 'default' | 'medium' | 'large';
+ "size"?: IonButtonSize | 'default';
/**
* If `true`, activates a button with a heavier font weight.
* @default false
@@ -657,10 +659,6 @@ export namespace Components {
* Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`.
*/
"target": string | undefined;
- /**
- * The theme determines the visual appearance of the component.
- */
- "theme"?: "ios" | "md" | "ionic";
/**
* The type of the button.
* @default 'button'
@@ -6467,11 +6465,11 @@ declare namespace LocalJSX {
/**
* Set to `"block"` for a full-width button or to `"full"` for a full-width button with square corners and no left or right borders.
*/
- "expand"?: 'full' | 'block';
+ "expand"?: IonButtonExpand;
/**
- * Set to `"clear"` for a transparent button that resembles a flat button, to `"outline"` for a transparent button with a border, or to `"solid"` for a button with a filled background. The default fill is `"solid"` except when inside of a buttons or datetime component, where the default fill is `"clear"`.
+ * Set to `"clear"` for a transparent button that resembles a flat button, `"outline"` for a transparent button with a border, or `"solid"` for a button with a filled background. Defaults to `"solid"` if both the fill property and theme config are unset, or `"clear"` inside of buttons, datetime, or list header.
*/
- "fill"?: 'clear' | 'outline' | 'solid' | 'default';
+ "fill"?: IonButtonFill | 'default';
/**
* The HTML form element or form element id. Used to submit a form when the button is not a child of the form.
*/
@@ -6506,13 +6504,13 @@ declare namespace LocalJSX {
*/
"routerDirection"?: RouterDirection;
/**
- * Set to `"soft"` for a button with slightly rounded corners, `"round"` for a button with fully rounded corners, or `"rectangular"` for a button without rounded corners. Defaults to `"soft"` for the `"ios"` theme and `"round"` for all other themes.
+ * Set to `"crisp"` for a button with even slightly rounded corners, `"soft"` for a button with slightly rounded corners, `"round"` for a button with fully rounded corners, or `"rectangular"` for a button without rounded corners. Defaults to `"round"` if both the shape property and theme config are unset.
*/
- "shape"?: 'soft' | 'round' | 'rectangular';
+ "shape"?: IonButtonShape;
/**
- * Set to `"small"` for a button with less height and padding, to `"medium"` for a button with the medium height and padding, or to `"large"` for a button with more height and padding. By default the size is unset, unless the button is inside of an item, where the size is `"small"` by default. Set the size to `"default"` inside of an item to make it a standard size button.
+ * Set to `"small"` for a button with less height and padding, `"medium"` for a button with the standard height and padding, or `"large"` for a button with more height and padding. Defaults to `"medium"` if both the size property and theme config are unset, or `"small"` inside of an item. `"default"` is deprecated and renders the same as `"medium"`.
*/
- "size"?: 'small' | 'default' | 'medium' | 'large';
+ "size"?: IonButtonSize | 'default';
/**
* If `true`, activates a button with a heavier font weight.
* @default false
@@ -6522,10 +6520,6 @@ declare namespace LocalJSX {
* Specifies where to display the linked URL. Only applies when an `href` is provided. Special keywords: `"_blank"`, `"_self"`, `"_parent"`, `"_top"`.
*/
"target"?: string | undefined;
- /**
- * The theme determines the visual appearance of the component.
- */
- "theme"?: "ios" | "md" | "ionic";
/**
* The type of the button.
* @default 'button'
@@ -10481,14 +10475,14 @@ declare namespace LocalJSX {
"color": Color;
"buttonType": string;
"disabled": boolean;
- "expand": 'full' | 'block';
- "fill": 'clear' | 'outline' | 'solid' | 'default';
+ "expand": IonButtonExpand;
+ "fill": IonButtonFill | 'default';
"routerDirection": RouterDirection;
"download": string | undefined;
"href": string | undefined;
"rel": string | undefined;
- "shape": 'soft' | 'round' | 'rectangular';
- "size": 'small' | 'default' | 'medium' | 'large';
+ "shape": IonButtonShape;
+ "size": IonButtonSize | 'default';
"strong": boolean;
"target": string | undefined;
"type": 'submit' | 'reset' | 'button';
diff --git a/core/src/components/button/_button.docs.scss b/core/src/components/button/_button.docs.scss
new file mode 100644
index 00000000000..58d9d03d87b
--- /dev/null
+++ b/core/src/components/button/_button.docs.scss
@@ -0,0 +1,237 @@
+/**
+ * @prop --ion-button-margin-top: Top margin of the button
+ * @prop --ion-button-margin-end: Right margin if direction is left-to-right, and left margin if direction is right-to-left of the button
+ * @prop --ion-button-margin-bottom: Bottom margin of the button
+ * @prop --ion-button-margin-start: Left margin if direction is left-to-right, and right margin if direction is right-to-left of the button
+ * @prop --ion-button-font-family: Font family of the button
+ * @prop --ion-button-letter-spacing: Letter spacing of the button
+ * @prop --ion-button-text-transform: Text transform of the button
+ * @prop --ion-button-transition: Transition of the button
+ * @prop --ion-button-hue-bold-solid-default-font-weight: Font weight of the `bold` hue and `solid` fill combination in the default state
+ * @prop --ion-button-hue-bold-solid-strong-font-weight: Font weight of the `bold` hue and `solid` fill combination on a `strong` button
+ * @prop --ion-button-hue-bold-outline-default-font-weight: Font weight of the `bold` hue and `outline` fill combination in the default state
+ * @prop --ion-button-hue-bold-outline-strong-font-weight: Font weight of the `bold` hue and `outline` fill combination on a `strong` button
+ * @prop --ion-button-hue-bold-clear-default-font-weight: Font weight of the `bold` hue and `clear` fill combination in the default state
+ * @prop --ion-button-hue-bold-clear-strong-font-weight: Font weight of the `bold` hue and `clear` fill combination on a `strong` button
+ * @prop --ion-button-size-small-min-width: Minimum width of the `small` button size
+ * @prop --ion-button-size-small-min-height: Minimum height of the `small` button size, and the width and height of an icon-only button of that size
+ * @prop --ion-button-size-small-font-size: Font size of the `small` button size
+ * @prop --ion-button-size-small-line-height: Line height of the `small` button size
+ * @prop --ion-button-size-small-padding-top: Top padding of the `small` button size
+ * @prop --ion-button-size-small-padding-end: Right padding if direction is left-to-right, and left padding if direction is right-to-left of the `small` button size
+ * @prop --ion-button-size-small-padding-bottom: Bottom padding of the `small` button size
+ * @prop --ion-button-size-small-padding-start: Left padding if direction is left-to-right, and right padding if direction is right-to-left of the `small` button size
+ * @prop --ion-button-size-small-icon-font-size: Font size of the icons of the `small` button size
+ * @prop --ion-button-size-small-icon-leading-margin-top: Top margin of an icon in the `start` slot of the `small` button size
+ * @prop --ion-button-size-small-icon-leading-margin-end: Right margin if direction is left-to-right, and left margin if direction is right-to-left of an icon in the `start` slot of the `small` button size
+ * @prop --ion-button-size-small-icon-leading-margin-bottom: Bottom margin of an icon in the `start` slot of the `small` button size
+ * @prop --ion-button-size-small-icon-leading-margin-start: Left margin if direction is left-to-right, and right margin if direction is right-to-left of an icon in the `start` slot of the `small` button size
+ * @prop --ion-button-size-small-icon-trailing-margin-top: Top margin of an icon in the `end` slot of the `small` button size
+ * @prop --ion-button-size-small-icon-trailing-margin-end: Right margin if direction is left-to-right, and left margin if direction is right-to-left of an icon in the `end` slot of the `small` button size
+ * @prop --ion-button-size-small-icon-trailing-margin-bottom: Bottom margin of an icon in the `end` slot of the `small` button size
+ * @prop --ion-button-size-small-icon-trailing-margin-start: Left margin if direction is left-to-right, and right margin if direction is right-to-left of an icon in the `end` slot of the `small` button size
+ * @prop --ion-button-size-small-icon-only-padding-top: Top padding of an icon-only button of the `small` size
+ * @prop --ion-button-size-small-icon-only-padding-end: Right padding if direction is left-to-right, and left padding if direction is right-to-left of an icon-only button of the `small` size
+ * @prop --ion-button-size-small-icon-only-padding-bottom: Bottom padding of an icon-only button of the `small` size
+ * @prop --ion-button-size-small-icon-only-padding-start: Left padding if direction is left-to-right, and right padding if direction is right-to-left of an icon-only button of the `small` size
+ * @prop --ion-button-size-small-icon-only-icon-font-size: Font size of the icon in an icon-only button of the `small` size
+ * @prop --ion-button-size-small-spinner-size-xsmall-width: Width of an `xsmall` spinner in the `start`, `end` or `icon-only` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-size-xsmall-height: Height of an `xsmall` spinner in the `start`, `end` or `icon-only` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-size-small-width: Width of a `small` spinner in the `start`, `end` or `icon-only` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-size-small-height: Height of a `small` spinner in the `start`, `end` or `icon-only` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-size-medium-width: Width of a `medium` spinner in the `start`, `end` or `icon-only` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-size-medium-height: Height of a `medium` spinner in the `start`, `end` or `icon-only` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-size-large-width: Width of a `large` spinner in the `start`, `end` or `icon-only` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-size-large-height: Height of a `large` spinner in the `start`, `end` or `icon-only` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-size-xlarge-width: Width of an `xlarge` spinner in the `start`, `end` or `icon-only` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-size-xlarge-height: Height of an `xlarge` spinner in the `start`, `end` or `icon-only` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-leading-margin-top: Top margin of a spinner in the `start` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-leading-margin-end: Right margin if direction is left-to-right, and left margin if direction is right-to-left of a spinner in the `start` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-leading-margin-bottom: Bottom margin of a spinner in the `start` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-leading-margin-start: Left margin if direction is left-to-right, and right margin if direction is right-to-left of a spinner in the `start` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-trailing-margin-top: Top margin of a spinner in the `end` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-trailing-margin-end: Right margin if direction is left-to-right, and left margin if direction is right-to-left of a spinner in the `end` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-trailing-margin-bottom: Bottom margin of a spinner in the `end` slot of the `small` button size
+ * @prop --ion-button-size-small-spinner-trailing-margin-start: Left margin if direction is left-to-right, and right margin if direction is right-to-left of a spinner in the `end` slot of the `small` button size
+ * @prop --ion-button-size-medium-min-width: Minimum width of the `medium` button size
+ * @prop --ion-button-size-medium-min-height: Minimum height of the `medium` button size, and the width and height of an icon-only button of that size
+ * @prop --ion-button-size-medium-font-size: Font size of the `medium` button size
+ * @prop --ion-button-size-medium-line-height: Line height of the `medium` button size
+ * @prop --ion-button-size-medium-padding-top: Top padding of the `medium` button size
+ * @prop --ion-button-size-medium-padding-end: Right padding if direction is left-to-right, and left padding if direction is right-to-left of the `medium` button size
+ * @prop --ion-button-size-medium-padding-bottom: Bottom padding of the `medium` button size
+ * @prop --ion-button-size-medium-padding-start: Left padding if direction is left-to-right, and right padding if direction is right-to-left of the `medium` button size
+ * @prop --ion-button-size-medium-icon-font-size: Font size of the icons of the `medium` button size
+ * @prop --ion-button-size-medium-icon-leading-margin-top: Top margin of an icon in the `start` slot of the `medium` button size
+ * @prop --ion-button-size-medium-icon-leading-margin-end: Right margin if direction is left-to-right, and left margin if direction is right-to-left of an icon in the `start` slot of the `medium` button size
+ * @prop --ion-button-size-medium-icon-leading-margin-bottom: Bottom margin of an icon in the `start` slot of the `medium` button size
+ * @prop --ion-button-size-medium-icon-leading-margin-start: Left margin if direction is left-to-right, and right margin if direction is right-to-left of an icon in the `start` slot of the `medium` button size
+ * @prop --ion-button-size-medium-icon-trailing-margin-top: Top margin of an icon in the `end` slot of the `medium` button size
+ * @prop --ion-button-size-medium-icon-trailing-margin-end: Right margin if direction is left-to-right, and left margin if direction is right-to-left of an icon in the `end` slot of the `medium` button size
+ * @prop --ion-button-size-medium-icon-trailing-margin-bottom: Bottom margin of an icon in the `end` slot of the `medium` button size
+ * @prop --ion-button-size-medium-icon-trailing-margin-start: Left margin if direction is left-to-right, and right margin if direction is right-to-left of an icon in the `end` slot of the `medium` button size
+ * @prop --ion-button-size-medium-icon-only-padding-top: Top padding of an icon-only button of the `medium` size
+ * @prop --ion-button-size-medium-icon-only-padding-end: Right padding if direction is left-to-right, and left padding if direction is right-to-left of an icon-only button of the `medium` size
+ * @prop --ion-button-size-medium-icon-only-padding-bottom: Bottom padding of an icon-only button of the `medium` size
+ * @prop --ion-button-size-medium-icon-only-padding-start: Left padding if direction is left-to-right, and right padding if direction is right-to-left of an icon-only button of the `medium` size
+ * @prop --ion-button-size-medium-icon-only-icon-font-size: Font size of the icon in an icon-only button of the `medium` size
+ * @prop --ion-button-size-medium-spinner-size-xsmall-width: Width of an `xsmall` spinner in the `start`, `end` or `icon-only` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-size-xsmall-height: Height of an `xsmall` spinner in the `start`, `end` or `icon-only` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-size-small-width: Width of a `small` spinner in the `start`, `end` or `icon-only` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-size-small-height: Height of a `small` spinner in the `start`, `end` or `icon-only` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-size-medium-width: Width of a `medium` spinner in the `start`, `end` or `icon-only` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-size-medium-height: Height of a `medium` spinner in the `start`, `end` or `icon-only` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-size-large-width: Width of a `large` spinner in the `start`, `end` or `icon-only` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-size-large-height: Height of a `large` spinner in the `start`, `end` or `icon-only` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-size-xlarge-width: Width of an `xlarge` spinner in the `start`, `end` or `icon-only` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-size-xlarge-height: Height of an `xlarge` spinner in the `start`, `end` or `icon-only` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-leading-margin-top: Top margin of a spinner in the `start` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-leading-margin-end: Right margin if direction is left-to-right, and left margin if direction is right-to-left of a spinner in the `start` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-leading-margin-bottom: Bottom margin of a spinner in the `start` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-leading-margin-start: Left margin if direction is left-to-right, and right margin if direction is right-to-left of a spinner in the `start` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-trailing-margin-top: Top margin of a spinner in the `end` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-trailing-margin-end: Right margin if direction is left-to-right, and left margin if direction is right-to-left of a spinner in the `end` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-trailing-margin-bottom: Bottom margin of a spinner in the `end` slot of the `medium` button size
+ * @prop --ion-button-size-medium-spinner-trailing-margin-start: Left margin if direction is left-to-right, and right margin if direction is right-to-left of a spinner in the `end` slot of the `medium` button size
+ * @prop --ion-button-size-large-min-width: Minimum width of the `large` button size
+ * @prop --ion-button-size-large-min-height: Minimum height of the `large` button size, and the width and height of an icon-only button of that size
+ * @prop --ion-button-size-large-font-size: Font size of the `large` button size
+ * @prop --ion-button-size-large-line-height: Line height of the `large` button size
+ * @prop --ion-button-size-large-padding-top: Top padding of the `large` button size
+ * @prop --ion-button-size-large-padding-end: Right padding if direction is left-to-right, and left padding if direction is right-to-left of the `large` button size
+ * @prop --ion-button-size-large-padding-bottom: Bottom padding of the `large` button size
+ * @prop --ion-button-size-large-padding-start: Left padding if direction is left-to-right, and right padding if direction is right-to-left of the `large` button size
+ * @prop --ion-button-size-large-icon-font-size: Font size of the icons of the `large` button size
+ * @prop --ion-button-size-large-icon-leading-margin-top: Top margin of an icon in the `start` slot of the `large` button size
+ * @prop --ion-button-size-large-icon-leading-margin-end: Right margin if direction is left-to-right, and left margin if direction is right-to-left of an icon in the `start` slot of the `large` button size
+ * @prop --ion-button-size-large-icon-leading-margin-bottom: Bottom margin of an icon in the `start` slot of the `large` button size
+ * @prop --ion-button-size-large-icon-leading-margin-start: Left margin if direction is left-to-right, and right margin if direction is right-to-left of an icon in the `start` slot of the `large` button size
+ * @prop --ion-button-size-large-icon-trailing-margin-top: Top margin of an icon in the `end` slot of the `large` button size
+ * @prop --ion-button-size-large-icon-trailing-margin-end: Right margin if direction is left-to-right, and left margin if direction is right-to-left of an icon in the `end` slot of the `large` button size
+ * @prop --ion-button-size-large-icon-trailing-margin-bottom: Bottom margin of an icon in the `end` slot of the `large` button size
+ * @prop --ion-button-size-large-icon-trailing-margin-start: Left margin if direction is left-to-right, and right margin if direction is right-to-left of an icon in the `end` slot of the `large` button size
+ * @prop --ion-button-size-large-icon-only-padding-top: Top padding of an icon-only button of the `large` size
+ * @prop --ion-button-size-large-icon-only-padding-end: Right padding if direction is left-to-right, and left padding if direction is right-to-left of an icon-only button of the `large` size
+ * @prop --ion-button-size-large-icon-only-padding-bottom: Bottom padding of an icon-only button of the `large` size
+ * @prop --ion-button-size-large-icon-only-padding-start: Left padding if direction is left-to-right, and right padding if direction is right-to-left of an icon-only button of the `large` size
+ * @prop --ion-button-size-large-icon-only-icon-font-size: Font size of the icon in an icon-only button of the `large` size
+ * @prop --ion-button-size-large-spinner-size-xsmall-width: Width of an `xsmall` spinner in the `start`, `end` or `icon-only` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-size-xsmall-height: Height of an `xsmall` spinner in the `start`, `end` or `icon-only` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-size-small-width: Width of a `small` spinner in the `start`, `end` or `icon-only` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-size-small-height: Height of a `small` spinner in the `start`, `end` or `icon-only` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-size-medium-width: Width of a `medium` spinner in the `start`, `end` or `icon-only` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-size-medium-height: Height of a `medium` spinner in the `start`, `end` or `icon-only` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-size-large-width: Width of a `large` spinner in the `start`, `end` or `icon-only` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-size-large-height: Height of a `large` spinner in the `start`, `end` or `icon-only` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-size-xlarge-width: Width of an `xlarge` spinner in the `start`, `end` or `icon-only` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-size-xlarge-height: Height of an `xlarge` spinner in the `start`, `end` or `icon-only` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-leading-margin-top: Top margin of a spinner in the `start` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-leading-margin-end: Right margin if direction is left-to-right, and left margin if direction is right-to-left of a spinner in the `start` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-leading-margin-bottom: Bottom margin of a spinner in the `start` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-leading-margin-start: Left margin if direction is left-to-right, and right margin if direction is right-to-left of a spinner in the `start` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-trailing-margin-top: Top margin of a spinner in the `end` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-trailing-margin-end: Right margin if direction is left-to-right, and left margin if direction is right-to-left of a spinner in the `end` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-trailing-margin-bottom: Bottom margin of a spinner in the `end` slot of the `large` button size
+ * @prop --ion-button-size-large-spinner-trailing-margin-start: Left margin if direction is left-to-right, and right margin if direction is right-to-left of a spinner in the `end` slot of the `large` button size
+ * @prop --ion-button-shape-crisp-border-radius: Border radius of the `crisp` button shape
+ * @prop --ion-button-shape-soft-border-radius: Border radius of the `soft` button shape
+ * @prop --ion-button-shape-round-border-radius: Border radius of the `round` button shape
+ * @prop --ion-button-shape-rectangular-border-radius: Border radius of the `rectangular` button shape
+ * @prop --ion-button-state-focus-ring-width: Width of the focus ring
+ * @prop --ion-button-state-focus-ring-style: Style of the focus ring
+ * @prop --ion-button-state-focus-ring-color: Color of the focus ring
+ * @prop --ion-button-state-focus-ring-offset: Offset of the focus ring
+ * @prop --ion-button-hue-bold-outline-default-border-color: Border color of the `bold` hue and `outline` fill combination in the default state
+ * @prop --ion-button-hue-bold-outline-default-color: Text color of the `bold` hue and `outline` fill combination in the default state
+ * @prop --ion-button-hue-bold-clear-default-color: Text color of the `bold` hue and `clear` fill combination in the default state
+ * @prop --ion-button-hue-bold-solid-default-background: Background of the `bold` hue and `solid` fill combination in the default state
+ * @prop --ion-button-hue-bold-solid-default-color: Text color of the `bold` hue and `solid` fill combination in the default state
+ * @prop --ion-button-hue-bold-solid-default-border-width: Border width of the `bold` hue and `solid` fill combination in the default state
+ * @prop --ion-button-hue-bold-solid-default-border-style: Border style of the `bold` hue and `solid` fill combination in the default state
+ * @prop --ion-button-hue-bold-solid-default-border-color: Border color of the `bold` hue and `solid` fill combination in the default state
+ * @prop --ion-button-hue-bold-solid-default-box-shadow: Box shadow of the `bold` hue and `solid` fill combination in the default state
+ * @prop --ion-button-hue-bold-solid-ripple-effect-color: Ripple color of the `bold` hue and `solid` fill combination
+ * @prop --ion-button-hue-bold-solid-ripple-effect-opacity: Ripple opacity of the `bold` hue and `solid` fill combination
+ * @prop --ion-button-hue-bold-solid-semantic-default-border-color: Border color of the `bold` hue and `solid` fill combination in the default state when a semantic color is applied
+ * @prop --ion-button-hue-bold-solid-semantic-default-background: Background of the `bold` hue and `solid` fill combination in the default state when a semantic color is applied
+ * @prop --ion-button-hue-bold-solid-semantic-default-color: Text color of the `bold` hue and `solid` fill combination in the default state when a semantic color is applied
+ * @prop --ion-button-hue-bold-solid-semantic-ripple-effect-color: Ripple color of the `bold` hue and `solid` fill combination when a semantic color is applied
+ * @prop --ion-button-hue-bold-solid-semantic-ripple-effect-opacity: Ripple opacity of the `bold` hue and `solid` fill combination when a semantic color is applied
+ * @prop --ion-button-hue-bold-solid-focus-color: Text color of the `bold` hue and `solid` fill combination in the focus state
+ * @prop --ion-button-hue-bold-solid-focus-background: Background of the `bold` hue and `solid` fill combination in the focus state
+ * @prop --ion-button-hue-bold-solid-semantic-focus-background: Background of the `bold` hue and `solid` fill combination in the focus state when a semantic color is applied
+ * @prop --ion-button-hue-bold-solid-semantic-focus-color: Text color of the `bold` hue and `solid` fill combination in the focus state when a semantic color is applied
+ * @prop --ion-button-hue-bold-solid-hover-color: Text color of the `bold` hue and `solid` fill combination in the hover state
+ * @prop --ion-button-hue-bold-solid-hover-opacity: Opacity of the whole button of the `bold` hue and `solid` fill combination in the hover state
+ * @prop --ion-button-hue-bold-solid-hover-background: Background of the `bold` hue and `solid` fill combination in the hover state
+ * @prop --ion-button-hue-bold-solid-semantic-hover-background: Background of the `bold` hue and `solid` fill combination in the hover state when a semantic color is applied
+ * @prop --ion-button-hue-bold-solid-semantic-hover-color: Text color of the `bold` hue and `solid` fill combination in the hover state when a semantic color is applied
+ * @prop --ion-button-hue-bold-solid-activated-color: Text color of the `bold` hue and `solid` fill combination in the activated state
+ * @prop --ion-button-hue-bold-solid-activated-opacity: Opacity of the whole button of the `bold` hue and `solid` fill combination in the activated state
+ * @prop --ion-button-hue-bold-solid-activated-background: Background of the `bold` hue and `solid` fill combination in the activated state
+ * @prop --ion-button-hue-bold-solid-activated-box-shadow: Box shadow of the `bold` hue and `solid` fill combination in the activated state
+ * @prop --ion-button-hue-bold-solid-semantic-activated-background: Background of the `bold` hue and `solid` fill combination in the activated state when a semantic color is applied
+ * @prop --ion-button-hue-bold-solid-semantic-activated-color: Text color of the `bold` hue and `solid` fill combination in the activated state when a semantic color is applied
+ * @prop --ion-button-hue-bold-solid-disabled-background: Background of the `bold` hue and `solid` fill combination in the disabled state
+ * @prop --ion-button-hue-bold-solid-disabled-opacity: Opacity of the whole button of the `bold` hue and `solid` fill combination in the disabled state
+ * @prop --ion-button-hue-bold-solid-semantic-disabled-background: Background of the `bold` hue and `solid` fill combination in the disabled state when a semantic color is applied
+ * @prop --ion-button-hue-bold-outline-default-border-width: Border width of the `bold` hue and `outline` fill combination in the default state
+ * @prop --ion-button-hue-bold-outline-default-border-style: Border style of the `bold` hue and `outline` fill combination in the default state
+ * @prop --ion-button-hue-bold-outline-default-background: Background of the `bold` hue and `outline` fill combination in the default state
+ * @prop --ion-button-hue-bold-outline-default-box-shadow: Box shadow of the `bold` hue and `outline` fill combination in the default state
+ * @prop --ion-button-hue-bold-outline-ripple-effect-color: Ripple color of the `bold` hue and `outline` fill combination
+ * @prop --ion-button-hue-bold-outline-ripple-effect-opacity: Ripple opacity of the `bold` hue and `outline` fill combination
+ * @prop --ion-button-hue-bold-outline-semantic-default-border-color: Border color of the `bold` hue and `outline` fill combination in the default state when a semantic color is applied
+ * @prop --ion-button-hue-bold-outline-semantic-default-background: Background of the `bold` hue and `outline` fill combination in the default state when a semantic color is applied
+ * @prop --ion-button-hue-bold-outline-semantic-default-color: Text color of the `bold` hue and `outline` fill combination in the default state when a semantic color is applied
+ * @prop --ion-button-hue-bold-outline-semantic-ripple-effect-color: Ripple color of the `bold` hue and `outline` fill combination when a semantic color is applied
+ * @prop --ion-button-hue-bold-outline-semantic-ripple-effect-opacity: Ripple opacity of the `bold` hue and `outline` fill combination when a semantic color is applied
+ * @prop --ion-button-hue-bold-outline-focus-color: Text color of the `bold` hue and `outline` fill combination in the focus state
+ * @prop --ion-button-hue-bold-outline-focus-background: Background of the `bold` hue and `outline` fill combination in the focus state
+ * @prop --ion-button-hue-bold-outline-semantic-focus-background: Background of the `bold` hue and `outline` fill combination in the focus state when a semantic color is applied
+ * @prop --ion-button-hue-bold-outline-semantic-focus-color: Text color of the `bold` hue and `outline` fill combination in the focus state when a semantic color is applied
+ * @prop --ion-button-hue-bold-outline-hover-color: Text color of the `bold` hue and `outline` fill combination in the hover state
+ * @prop --ion-button-hue-bold-outline-hover-opacity: Opacity of the whole button of the `bold` hue and `outline` fill combination in the hover state
+ * @prop --ion-button-hue-bold-outline-hover-background: Background of the `bold` hue and `outline` fill combination in the hover state
+ * @prop --ion-button-hue-bold-outline-semantic-hover-background: Background of the `bold` hue and `outline` fill combination in the hover state when a semantic color is applied
+ * @prop --ion-button-hue-bold-outline-semantic-hover-color: Text color of the `bold` hue and `outline` fill combination in the hover state when a semantic color is applied
+ * @prop --ion-button-hue-bold-outline-activated-color: Text color of the `bold` hue and `outline` fill combination in the activated state
+ * @prop --ion-button-hue-bold-outline-activated-opacity: Opacity of the whole button of the `bold` hue and `outline` fill combination in the activated state
+ * @prop --ion-button-hue-bold-outline-activated-background: Background of the `bold` hue and `outline` fill combination in the activated state
+ * @prop --ion-button-hue-bold-outline-activated-box-shadow: Box shadow of the `bold` hue and `outline` fill combination in the activated state
+ * @prop --ion-button-hue-bold-outline-semantic-activated-background: Background of the `bold` hue and `outline` fill combination in the activated state when a semantic color is applied
+ * @prop --ion-button-hue-bold-outline-semantic-activated-color: Text color of the `bold` hue and `outline` fill combination in the activated state when a semantic color is applied
+ * @prop --ion-button-hue-bold-outline-disabled-background: Background of the `bold` hue and `outline` fill combination in the disabled state
+ * @prop --ion-button-hue-bold-outline-disabled-opacity: Opacity of the whole button of the `bold` hue and `outline` fill combination in the disabled state
+ * @prop --ion-button-hue-bold-outline-semantic-disabled-background: Background of the `bold` hue and `outline` fill combination in the disabled state when a semantic color is applied
+ * @prop --ion-button-hue-bold-clear-default-border-width: Border width of the `bold` hue and `clear` fill combination in the default state
+ * @prop --ion-button-hue-bold-clear-default-border-style: Border style of the `bold` hue and `clear` fill combination in the default state
+ * @prop --ion-button-hue-bold-clear-default-border-color: Border color of the `bold` hue and `clear` fill combination in the default state
+ * @prop --ion-button-hue-bold-clear-default-background: Background of the `bold` hue and `clear` fill combination in the default state
+ * @prop --ion-button-hue-bold-clear-default-box-shadow: Box shadow of the `bold` hue and `clear` fill combination in the default state
+ * @prop --ion-button-hue-bold-clear-ripple-effect-color: Ripple color of the `bold` hue and `clear` fill combination
+ * @prop --ion-button-hue-bold-clear-ripple-effect-opacity: Ripple opacity of the `bold` hue and `clear` fill combination
+ * @prop --ion-button-hue-bold-clear-semantic-default-border-color: Border color of the `bold` hue and `clear` fill combination in the default state when a semantic color is applied
+ * @prop --ion-button-hue-bold-clear-semantic-default-background: Background of the `bold` hue and `clear` fill combination in the default state when a semantic color is applied
+ * @prop --ion-button-hue-bold-clear-semantic-default-color: Text color of the `bold` hue and `clear` fill combination in the default state when a semantic color is applied
+ * @prop --ion-button-hue-bold-clear-semantic-ripple-effect-color: Ripple color of the `bold` hue and `clear` fill combination when a semantic color is applied
+ * @prop --ion-button-hue-bold-clear-semantic-ripple-effect-opacity: Ripple opacity of the `bold` hue and `clear` fill combination when a semantic color is applied
+ * @prop --ion-button-hue-bold-clear-focus-color: Text color of the `bold` hue and `clear` fill combination in the focus state
+ * @prop --ion-button-hue-bold-clear-focus-background: Background of the `bold` hue and `clear` fill combination in the focus state
+ * @prop --ion-button-hue-bold-clear-semantic-focus-background: Background of the `bold` hue and `clear` fill combination in the focus state when a semantic color is applied
+ * @prop --ion-button-hue-bold-clear-semantic-focus-color: Text color of the `bold` hue and `clear` fill combination in the focus state when a semantic color is applied
+ * @prop --ion-button-hue-bold-clear-hover-color: Text color of the `bold` hue and `clear` fill combination in the hover state
+ * @prop --ion-button-hue-bold-clear-hover-opacity: Opacity of the whole button of the `bold` hue and `clear` fill combination in the hover state
+ * @prop --ion-button-hue-bold-clear-hover-background: Background of the `bold` hue and `clear` fill combination in the hover state
+ * @prop --ion-button-hue-bold-clear-semantic-hover-background: Background of the `bold` hue and `clear` fill combination in the hover state when a semantic color is applied
+ * @prop --ion-button-hue-bold-clear-semantic-hover-color: Text color of the `bold` hue and `clear` fill combination in the hover state when a semantic color is applied
+ * @prop --ion-button-hue-bold-clear-activated-color: Text color of the `bold` hue and `clear` fill combination in the activated state
+ * @prop --ion-button-hue-bold-clear-activated-opacity: Opacity of the whole button of the `bold` hue and `clear` fill combination in the activated state
+ * @prop --ion-button-hue-bold-clear-activated-background: Background of the `bold` hue and `clear` fill combination in the activated state
+ * @prop --ion-button-hue-bold-clear-activated-box-shadow: Box shadow of the `bold` hue and `clear` fill combination in the activated state
+ * @prop --ion-button-hue-bold-clear-semantic-activated-background: Background of the `bold` hue and `clear` fill combination in the activated state when a semantic color is applied
+ * @prop --ion-button-hue-bold-clear-semantic-activated-color: Text color of the `bold` hue and `clear` fill combination in the activated state when a semantic color is applied
+ * @prop --ion-button-hue-bold-clear-disabled-background: Background of the `bold` hue and `clear` fill combination in the disabled state
+ * @prop --ion-button-hue-bold-clear-disabled-opacity: Opacity of the whole button of the `bold` hue and `clear` fill combination in the disabled state
+ * @prop --ion-button-hue-bold-clear-semantic-disabled-background: Background of the `bold` hue and `clear` fill combination in the disabled state when a semantic color is applied
+ */
diff --git a/core/src/components/button/button.common.scss b/core/src/components/button/button.common.scss
deleted file mode 100644
index cfbb699eb0e..00000000000
--- a/core/src/components/button/button.common.scss
+++ /dev/null
@@ -1,314 +0,0 @@
-@import "../../themes/mixins";
-@import "../../themes/functions.color";
-
-// Button
-// --------------------------------------------------
-
-:host {
- /**
- * @prop --background: Background of the button
- * @prop --background-activated: Background of the button when pressed. Note: setting this will interfere with the Material Design ripple.
- * @prop --background-activated-opacity: Opacity of the button when pressed
- * @prop --background-focused: Background of the button when focused with the tab key
- * @prop --background-focused-opacity: Opacity of the button when focused with the tab key
- * @prop --background-hover: Background of the button on hover
- * @prop --background-hover-opacity: Opacity of the background on hover
- *
- * @prop --color: Text color of the button
- * @prop --color-activated: Text color of the button when pressed
- * @prop --color-focused: Text color of the button when focused with the tab key
- * @prop --color-hover: Text color of the button when hover
- *
- * @prop --transition: Transition of the button
- *
- * @prop --border-radius: Border radius of the button
- * @prop --border-width: Border width of the button
- * @prop --border-style: Border style of the button
- * @prop --border-color: Border color of the button
- *
- * @prop --ripple-color: Color of the button ripple effect
- *
- * @prop --box-shadow: Box shadow of the button
- * @prop --opacity: Opacity of the button
- *
- * @prop --padding-top: Top padding of the button
- * @prop --padding-end: Right padding if direction is left-to-right, and left padding if direction is right-to-left of the button
- * @prop --padding-bottom: Bottom padding of the button
- * @prop --padding-start: Left padding if direction is left-to-right, and right padding if direction is right-to-left of the button
- */
- --overflow: hidden;
- --ripple-color: currentColor;
- --border-width: initial;
- --border-color: initial;
- --border-style: initial;
- --color-activated: var(--color);
- --color-focused: var(--color);
- --color-hover: var(--color);
- --box-shadow: none;
-
- display: inline-block;
-
- width: auto;
-
- color: var(--color);
-
- text-align: center;
- text-decoration: none;
-
- white-space: normal;
-
- user-select: none;
- vertical-align: top; // the better option for most scenarios
- vertical-align: -webkit-baseline-middle; // the best for those that support it
-
- font-kerning: none;
-}
-
-:host(.button-disabled) {
- cursor: default;
- opacity: 0.5;
- pointer-events: none;
-}
-
-// Outline Button
-// --------------------------------------------------
-
-// Default Outline Color
-:host(.button-outline) {
- --background: transparent;
-}
-
-// Clear Button
-// --------------------------------------------------
-
-// Default Clear Color
-:host(.button-clear) {
- --border-width: 0;
- --background: transparent;
-}
-
-// Block Button
-// --------------------------------------------------
-
-:host(.button-block) {
- display: block;
-}
-
-:host(.button-block) .button-native {
- @include margin-horizontal(0);
-
- width: 100%;
-
- clear: both;
-
- contain: content;
-}
-
-:host(.button-block) .button-native::after {
- clear: both;
-}
-
-// Full Button
-// --------------------------------------------------
-
-:host(.button-full) {
- display: block;
-}
-
-:host(.button-full) .button-native {
- @include margin-horizontal(0);
-
- width: 100%;
-
- contain: content;
-}
-
-:host(.button-full:not(.button-round)) .button-native {
- @include border-radius(0);
-
- border-right-width: 0;
- border-left-width: 0;
-}
-
-.button-native {
- @include border-radius(var(--border-radius));
- @include font-smoothing();
- @include margin(0);
- @include padding(var(--padding-top), var(--padding-end), var(--padding-bottom), var(--padding-start));
- @include text-inherit();
-
- display: flex;
-
- position: relative;
-
- align-items: center;
-
- width: 100%;
- height: 100%;
-
- min-height: inherit;
-
- transition: var(--transition);
-
- border-width: var(--border-width);
- border-style: var(--border-style);
- border-color: var(--border-color);
-
- outline: none;
-
- background: var(--background);
-
- line-height: 1;
-
- box-shadow: var(--box-shadow);
-
- contain: layout style;
- cursor: pointer;
-
- opacity: var(--opacity);
- overflow: var(--overflow);
-
- z-index: 0;
- box-sizing: border-box;
- appearance: none;
-}
-
-.button-native::-moz-focus-inner {
- border: 0;
-}
-
-.button-inner {
- display: flex;
- position: relative;
-
- flex-flow: row nowrap;
- flex-shrink: 0;
- align-items: center;
- justify-content: center;
-
- width: 100%;
- height: 100%;
-
- z-index: 1;
-}
-
-// Button Slots
-// --------------------------------------------------
-
-::slotted([slot="start"]),
-::slotted([slot="end"]) {
- flex-shrink: 0;
-}
-
-// Button Icons & Spinners
-// --------------------------------------------------
-
-::slotted(ion-icon),
-::slotted(ion-spinner) {
- pointer-events: none;
-}
-
-::slotted(ion-spinner) {
- color: currentColor;
-}
-
-// Button Ripple effect
-// --------------------------------------------------
-
-ion-ripple-effect {
- color: var(--ripple-color);
-}
-
-// Button: States
-// --------------------------------------------------
-
-.button-native::after {
- @include button-state();
-}
-
-// Button Focused
-:host(.ion-focused) {
- color: var(--color-focused);
-}
-
-:host(.ion-focused) .button-native::after {
- background: var(--background-focused);
-
- opacity: var(--background-focused-opacity);
-}
-
-// Button Hover
-@media (any-hover: hover) {
- :host(:hover) {
- color: var(--color-hover);
- }
-
- :host(:hover) .button-native::after {
- background: var(--background-hover);
-
- opacity: var(--background-hover-opacity);
- }
-}
-
-// Button Activated
-:host(.ion-activated) {
- color: var(--color-activated);
-}
-
-:host(.ion-activated) .button-native::after {
- background: var(--background-activated);
-
- opacity: var(--background-activated-opacity);
-}
-
-// Button Colors
-// --------------------------------------------------
-
-// Solid Button with Color
-:host(.button-solid.ion-color) .button-native {
- background: current-color(base);
- color: current-color(contrast);
-}
-
-// Outline Button with Color
-:host(.button-outline.ion-color) .button-native {
- border-color: current-color(base);
-
- background: transparent;
- color: current-color(base);
-}
-
-// Clear Button with Color
-:host(.button-clear.ion-color) .button-native {
- background: transparent;
- color: current-color(foreground);
-}
-
-// Button in Toolbar
-// --------------------------------------------------
-
-:host(.in-toolbar:not(.ion-color):not(.in-toolbar-color)) .button-native {
- color: #{var(--ion-toolbar-color, var(--color))};
-}
-
-:host(.button-outline.in-toolbar:not(.ion-color):not(.in-toolbar-color)) .button-native {
- border-color: #{var(--ion-toolbar-color, var(--color, var(--border-color)))};
-}
-
-:host(.button-solid.in-toolbar:not(.ion-color):not(.in-toolbar-color)) .button-native {
- background: #{var(--ion-toolbar-color, var(--background))};
- color: #{var(--ion-toolbar-background, var(--color))};
-}
-
-.button-native ion-ripple-effect,
-.button-native::after {
- @include border-radius(inherit);
-}
-
-// Button Slotted Elements
-// ---------------------------------------------
-
-// Anchored Badge
-:host(.button-has-badge) .button-native {
- --overflow: visible;
-}
diff --git a/core/src/components/button/button.interface.ts b/core/src/components/button/button.interface.ts
new file mode 100644
index 00000000000..1bf3788fffa
--- /dev/null
+++ b/core/src/components/button/button.interface.ts
@@ -0,0 +1,232 @@
+import type { Hue, IonMargin, IonPadding } from '../../themes/themes.interfaces';
+import type { SpinnerSize } from '../spinner/spinner.interfaces';
+
+export const ION_BUTTON_FILLS = ['clear', 'outline', 'solid'] as const;
+export type IonButtonFill = (typeof ION_BUTTON_FILLS)[number];
+
+export const ION_BUTTON_SHAPES = ['crisp', 'soft', 'round', 'rectangular'] as const;
+export type IonButtonShape = (typeof ION_BUTTON_SHAPES)[number];
+
+export const ION_BUTTON_SIZES = ['small', 'medium', 'large'] as const;
+export type IonButtonSize = (typeof ION_BUTTON_SIZES)[number];
+
+export const ION_BUTTON_EXPANDS = ['block', 'full'] as const;
+export type IonButtonExpand = (typeof ION_BUTTON_EXPANDS)[number];
+
+export type IonButtonRecipe = {
+ margin?: IonMargin;
+ transition?: string;
+
+ font?: {
+ family?: string;
+ };
+
+ letter?: {
+ spacing?: string | number;
+ };
+
+ text?: {
+ transform?: string;
+ };
+
+ // Hues with fills
+ hue?: {
+ [K in Hue]?: IonButtonFillDefinition;
+ };
+
+ // Sizes
+ size?: {
+ [K in IonButtonSize]?: IonButtonSizeDefinition;
+ };
+
+ // Shapes
+ shape?: {
+ [K in IonButtonShape]?: IonButtonShapeDefinition;
+ };
+
+ // Shared states
+ state?: {
+ focus?: {
+ ring?: {
+ color?: string;
+ offset?: string | number;
+ style?: string;
+ width?: string | number;
+ };
+ };
+ };
+};
+
+type IonButtonFillDefinition = {
+ [K in IonButtonFill]?: IonButtonStateDefinition & {
+ default?: {
+ font?: {
+ weight?: string | number;
+ };
+ };
+
+ /** A `strong` button */
+ strong?: {
+ font?: {
+ weight?: string | number;
+ };
+ };
+
+ rippleEffect?: IonButtonRippleEffectDefinition;
+
+ /** When the button has a `color` */
+ semantic?: IonButtonSemanticDefinition & {
+ rippleEffect?: IonButtonRippleEffectDefinition;
+ };
+ };
+};
+
+type IonButtonStateDefinition = {
+ default?: IonButtonColorDefinition & {
+ border?: {
+ color?: string;
+ style?: string;
+ width?: string | number;
+ };
+
+ box?: {
+ shadow?: string;
+ };
+ };
+
+ hover?: IonButtonColorDefinition & {
+ /** The whole button, for fills that fade instead of changing color */
+ opacity?: string | number;
+ };
+
+ focus?: IonButtonColorDefinition;
+
+ activated?: IonButtonColorDefinition & {
+ /** The whole button, for fills that fade instead of changing color */
+ opacity?: string | number;
+
+ box?: {
+ shadow?: string;
+ };
+ };
+
+ disabled?: {
+ background?: string;
+
+ /** The whole button */
+ opacity?: string | number;
+ };
+};
+
+/** The states of a button with a `color` */
+type IonButtonSemanticDefinition = {
+ default?: IonButtonColorDefinition & {
+ border?: {
+ color?: string;
+ };
+ };
+
+ hover?: IonButtonColorDefinition;
+
+ focus?: IonButtonColorDefinition;
+
+ activated?: IonButtonColorDefinition;
+
+ disabled?: {
+ background?: string;
+ };
+};
+
+/** The ripple shown while the button is pressed, which only renders in `md` mode */
+type IonButtonRippleEffectDefinition = {
+ color?: string;
+ opacity?: string | number;
+};
+
+type IonButtonColorDefinition = {
+ background?: string;
+ color?: string;
+};
+
+type IonButtonIconDefinition = {
+ font?: {
+ size?: string | number;
+ };
+
+ /** Icon in the `start` slot */
+ leading?: {
+ margin?: IonMargin;
+ };
+
+ /** Icon in the `end` slot */
+ trailing?: {
+ margin?: IonMargin;
+ };
+};
+
+/** A spinner in the `start`, `end` or `icon-only` slot */
+type IonButtonSpinnerDefinition = {
+ /** Unset sizes keep the spinner's own size */
+ size?: {
+ [K in SpinnerSize]?: {
+ height?: string | number;
+ width?: string | number;
+ };
+ };
+
+ /** Spinner in the `start` slot */
+ leading?: {
+ margin?: IonMargin;
+ };
+
+ /** Spinner in the `end` slot */
+ trailing?: {
+ margin?: IonMargin;
+ };
+};
+
+/** A button whose only content is an icon in the `icon-only` slot */
+type IonButtonIconOnlyDefinition = {
+ padding?: IonPadding;
+
+ icon?: {
+ font?: {
+ size?: string | number;
+ };
+ };
+};
+
+type IonButtonSizeDefinition = {
+ font?: {
+ size?: string | number;
+ };
+
+ line?: {
+ height?: string | number;
+ };
+
+ min?: {
+ /** Also the width and height of an icon-only button, so it's a square as tall as a text button */
+ height?: string | number;
+ width?: string | number;
+ };
+
+ padding?: IonPadding;
+
+ icon?: IonButtonIconDefinition;
+ iconOnly?: IonButtonIconOnlyDefinition;
+ spinner?: IonButtonSpinnerDefinition;
+};
+
+type IonButtonShapeDefinition = {
+ border?: {
+ radius?: string | number;
+ };
+};
+
+export type IonButtonConfig = {
+ fill?: IonButtonFill;
+ hue?: Hue;
+ shape?: IonButtonShape;
+ size?: IonButtonSize;
+};
diff --git a/core/src/components/button/button.ionic.scss b/core/src/components/button/button.ionic.scss
deleted file mode 100644
index c1bf4e83728..00000000000
--- a/core/src/components/button/button.ionic.scss
+++ /dev/null
@@ -1,309 +0,0 @@
-@use "../../themes/ionic/ionic.globals.scss" as globals;
-@use "./button.common";
-
-// Ionic Button
-// -------------------------------------------------------------------------------
-:host {
- --padding-top: #{globals.$ion-space-0};
- --padding-end: #{globals.$ion-space-0};
- --padding-bottom: var(--padding-top);
- --padding-start: var(--padding-end);
- --focus-ring-color: #{globals.$ion-border-focus-default};
- --focus-ring-width: #{globals.$ion-border-size-050};
-
- position: relative;
-
- // Target area
- &::after {
- @include globals.position(50%, 0, null, 0);
- position: absolute;
-
- height: 100%;
- min-height: inherit;
-
- transform: translateY(-50%);
-
- content: "";
-
- cursor: pointer;
-
- z-index: 1;
- }
-}
-
-// Button Fills
-// -------------------------------------------------------------------------------
-
-// Default Clear Color
-:host(.button-clear) {
- --color: #{globals.ion-color(primary, foreground)};
-}
-
-// Solid Button
-// --------------------------------------------------
-
-:host(.button-solid) {
- --background-activated: #{globals.ion-color(primary, shade)};
- --background-hover: #{globals.ion-color(primary, shade)};
- --background-focused: transparent;
- --background-hover-opacity: 1;
- --background: #{globals.ion-color(primary, base)};
- --color: #{globals.ion-color(primary, contrast)};
- --ripple-color: var(--background-activated);
-}
-
-// Outline Button
-// --------------------------------------------------
-
-:host(.button-outline) {
- --border-width: #{globals.$ion-border-size-025};
- --border-style: solid;
- --background-activated: #{globals.ion-color(primary, shade, $subtle: true)};
- --background-focused: transparent;
- --background-hover: #{globals.ion-color(primary, shade, $subtle: true)};
- --background-hover-opacity: 1;
- --border-color: #{globals.ion-color(primary, base)};
- --color: #{globals.ion-color(primary, base)};
- --ripple-color: var(--background-activated);
-}
-
-// Warning Outline Button - use foreground color for text and border
-:host(.button-outline.ion-color-warning) .button-native {
- border-color: globals.ion-color(warning, foreground);
-
- color: globals.ion-color(warning, foreground);
-}
-
-// Clear Button
-// --------------------------------------------------
-
-:host(.button-clear) {
- --background-activated: #{globals.ion-color(primary, shade, $subtle: true)};
- --background-focused: transparent;
- --background-hover: #{globals.ion-color(primary, shade, $subtle: true)};
- --background-hover-opacity: 1;
- --color: #{globals.ion-color(primary, foreground)};
- --ripple-color: var(--background-activated);
-}
-
-// Ripple Effect
-// -------------------------------------------------------------------------------
-
-// Set via the custom property (not `opacity` directly) because the ripple's
-// opacity is animated in @keyframes, which would override a direct value.
-:host(.button-solid) ion-ripple-effect,
-:host(.button-outline) ion-ripple-effect,
-:host(.button-clear) ion-ripple-effect {
- --ion-ripple-effect-opacity: var(--background-activated-opacity, 1);
-}
-
-:host(.button-solid.ion-color) ion-ripple-effect {
- color: globals.current-color(shade);
-}
-
-:host(.button-outline.ion-color) ion-ripple-effect,
-:host(.button-clear.ion-color) ion-ripple-effect {
- color: globals.current-color(shade, $subtle: true);
-}
-
-// Button Sizes
-// -------------------------------------------------------------------------------
-
-/* Small Button */
-:host(.button-small) {
- --padding-end: #{globals.$ion-space-400};
-
- @include globals.typography(globals.$ion-body-action-sm);
- min-width: globals.$ion-scale-1600;
-
- min-height: #{globals.$ion-scale-1000};
-}
-
-/* Medium Button */
-:host(.button-medium) {
- --padding-end: #{globals.$ion-space-500};
-
- @include globals.typography(globals.$ion-body-action-md);
- min-width: globals.$ion-scale-1800;
-
- min-height: #{globals.$ion-scale-1200};
-}
-
-/* Large Button */
-:host(.button-large) {
- --padding-end: #{globals.$ion-space-700};
-
- @include globals.typography(globals.$ion-body-action-lg);
- min-width: globals.$ion-scale-2000;
-
- min-height: #{globals.$ion-scale-1400};
-}
-
-// Button with Icons
-// -------------------------------------------------------------------------------
-
-/* Button containing only an icon */
-:host(.button-small),
-:host(.button-medium) {
- ::slotted(ion-icon[slot="start"]),
- ::slotted(ion-icon[slot="end"]),
- ::slotted(ion-icon[slot="icon-only"]) {
- font-size: globals.$ion-font-size-500;
- }
-}
-
-:host(.button-large) {
- ::slotted(ion-icon[slot="start"]),
- ::slotted(ion-icon[slot="end"]),
- ::slotted(ion-icon[slot="icon-only"]) {
- font-size: globals.$ion-font-size-600;
- }
-}
-
-:host(.button-has-icon-only) {
- --padding-end: var(--padding-top);
- min-width: unset;
-
- aspect-ratio: 1 / 1;
-}
-
-// Button with Spinner
-// -------------------------------------------------------------------------------
-
-/* Button containing only a spinner */
-::slotted(ion-spinner[slot="start"]),
-::slotted(ion-spinner[slot="end"]),
-::slotted(ion-spinner[slot="icon-only"]) {
- width: globals.$ion-scale-500;
- height: globals.$ion-scale-500;
-}
-
-// Button Shapes
-// -------------------------------------------------------------------------------
-
-// Soft Button
-// --------------------------------------------------
-
-:host(.button-soft) {
- --border-radius: #{globals.$ion-shape-soft-xs};
-}
-
-// Round Button
-// --------------------------------------------------
-
-:host(.button-round) {
- --border-radius: #{globals.$ion-shape-round-xs};
-}
-
-// Rectangular Button
-// --------------------------------------------------
-
-:host(.button-rectangular) {
- --border-radius: #{globals.$ion-shape-rectangular-xs};
-}
-
-// Button: Focus
-// -------------------------------------------------------------------------------
-
-// Only show the focus ring when the button is focused
-:host(.ion-focused) .button-native {
- outline: var(--focus-ring-width) solid var(--focus-ring-color);
- outline-offset: globals.$ion-border-size-050;
-}
-
-// Button: Activated
-// --------------------------------------------------
-
-:host(.button-solid.ion-color.ion-activated) .button-native::after {
- background: globals.current-color(shade);
-}
-
-:host(.button-outline.ion-color.ion-activated) .button-native::after,
-:host(.button-clear.ion-color.ion-activated) .button-native::after {
- background: globals.current-color(shade, $subtle: true);
-}
-
-:host(.ion-activated) .button-native:has(ion-ripple-effect)::after,
-:host(.button-solid.ion-color.ion-activated) .button-native:has(ion-ripple-effect)::after,
-:host(.button-outline.ion-color.ion-activated) .button-native:has(ion-ripple-effect)::after,
-:host(.button-clear.ion-color.ion-activated) .button-native:has(ion-ripple-effect)::after {
- background: transparent;
-}
-
-// Button: Hover
-// --------------------------------------------------
-
-@media (any-hover: hover) {
- :host(.button-solid.ion-color:hover) .button-native::after {
- background: globals.current-color(shade);
- }
-
- :host(.button-outline.ion-color:hover) .button-native::after,
- :host(.button-clear.ion-color:hover) .button-native::after {
- background: globals.current-color(shade, $subtle: true);
- }
-}
-
-// Button: Disabled
-// --------------------------------------------------
-
-:host(.button-disabled) .button-native::after {
- @include globals.disabled-state();
-
- width: inherit;
- height: inherit;
-}
-
-// Button Icons
-// --------------------------------------------------
-
-::slotted(ion-icon) {
- font-size: globals.$ion-font-size-500;
-}
-
-:host(.button-small) ::slotted(ion-icon[slot="start"]),
-:host(.button-small) ::slotted(ion-spinner[slot="start"]) {
- @include globals.margin-horizontal(null, globals.$ion-space-200);
-}
-
-::slotted(ion-icon[slot="start"]),
-::slotted(ion-spinner[slot="start"]) {
- @include globals.margin-horizontal(null, globals.$ion-space-250);
-}
-
-:host(.button-large) ::slotted(ion-icon[slot="start"]),
-:host(.button-large) ::slotted(ion-spinner[slot="start"]) {
- @include globals.margin-horizontal(null, globals.$ion-space-300);
-}
-
-:host(.button-small) ::slotted(ion-icon[slot="end"]),
-:host(.button-small) ::slotted(ion-spinner[slot="end"]) {
- @include globals.margin-horizontal(globals.$ion-space-200, null);
-}
-
-::slotted(ion-icon[slot="end"]),
-::slotted(ion-spinner[slot="end"]) {
- @include globals.margin-horizontal(globals.$ion-space-250, null);
-}
-
-:host(.button-large) ::slotted(ion-icon[slot="end"]),
-:host(.button-large) ::slotted(ion-spinner[slot="end"]) {
- @include globals.margin-horizontal(globals.$ion-space-300, null);
-}
-
-// Button with Badge
-// --------------------------------------------------
-
-:host(.button-has-badge) {
- --padding-top: #{globals.$ion-space-0};
- --padding-bottom: #{globals.$ion-space-0};
-}
-
-// Button in Datetime
-// --------------------------------------------------
-
-:host(.in-datetime) {
- @include globals.typography(globals.$ion-body-action-md);
-
- min-height: globals.$ion-space-1200;
-}
diff --git a/core/src/components/button/button.ios.scss b/core/src/components/button/button.ios.scss
deleted file mode 100644
index 8ff37beca70..00000000000
--- a/core/src/components/button/button.ios.scss
+++ /dev/null
@@ -1,308 +0,0 @@
-@import "./button.native";
-@import "./button.ios.vars";
-@import "../toolbar/toolbar.ios.vars";
-
-// iOS Button
-// --------------------------------------------------
-
-:host {
- --padding-top: #{$button-ios-padding-top};
- --padding-bottom: #{$button-ios-padding-bottom};
- --padding-start: #{$button-ios-padding-start};
- --padding-end: #{$button-ios-padding-end};
- --transition: background-color, opacity 100ms linear;
-
- @include margin($button-ios-margin-top, $button-ios-margin-end, $button-ios-margin-bottom, $button-ios-margin-start);
-
- min-height: #{$button-ios-min-height};
-
- font-size: #{$button-ios-font-size};
- font-weight: #{$button-ios-font-weight};
-
- letter-spacing: #{$button-ios-letter-spacing};
-}
-
-// Solid Button
-// --------------------------------------------------
-
-:host(.button-solid) {
- --background-activated: #{ion-color(primary, shade)};
- --background-focused: #{ion-color(primary, shade)};
- --background-hover: #{ion-color(primary, tint)};
- --background-activated-opacity: 1;
- --background-focused-opacity: 1;
- --background-hover-opacity: 1;
-}
-
-// Outline Button
-// --------------------------------------------------
-
-:host(.button-outline) {
- --border-width: #{$button-ios-outline-border-width};
- --border-style: #{$button-ios-outline-border-style};
- --background-activated: #{ion-color(primary, base)};
- --background-focused: #{ion-color(primary, base)};
- --background-hover: transparent;
- --background-focused-opacity: 0.1;
- --color-activated: #{ion-color(primary, contrast)};
-}
-
-// Clear Button
-// --------------------------------------------------
-
-:host(.button-clear) {
- --background-activated: transparent;
- --background-activated-opacity: 0;
- --background-focused: #{ion-color(primary, base)};
- --background-hover: transparent;
- --background-focused-opacity: 0.1;
-
- font-size: #{$button-ios-clear-font-size};
- font-weight: #{$button-ios-clear-font-weight};
-}
-
-// Toolbar Buttons
-// --------------------------------------------------
-
-/**
- * The default buttons in a toolbar
- * have a different font size/weight
- * than buttons outside of a toolbar on iOS.
- * However, we still want the "size"/"strong"
- * properties to be usable in a toolbar, so we add
- * the .in-buttons selector such that we
- * can add the different font size/weight in a toolbar
- * but still let "size"/"strong" override it.
- */
-:host(.in-buttons) {
- font-size: #{$toolbar-ios-button-font-size};
- font-weight: 400;
-}
-
-// Button Sizes
-// --------------------------------------------------
-
-:host(.button-large) {
- --padding-top: #{$button-ios-large-padding-top};
- --padding-start: #{$button-ios-large-padding-start};
- --padding-end: #{$button-ios-large-padding-end};
- --padding-bottom: #{$button-ios-large-padding-bottom};
-
- min-height: #{$button-ios-large-min-height};
-
- font-size: #{$button-ios-large-font-size};
-}
-
-:host(.button-small) {
- --padding-top: #{$button-ios-small-padding-top};
- --padding-start: #{$button-ios-small-padding-start};
- --padding-end: #{$button-ios-small-padding-end};
- --padding-bottom: #{$button-ios-small-padding-bottom};
-
- min-height: #{$button-ios-small-min-height};
-
- font-size: #{$button-ios-small-font-size};
-}
-
-// Button Shapes
-// --------------------------------------------------
-
-:host(.button-soft) {
- --border-radius: 6px;
-}
-
-:host(.button-soft.button-large) {
- --border-radius: 8px;
-}
-
-:host(.button-soft.button-small) {
- --border-radius: 4px;
-}
-
-:host(.button-round) {
- --border-radius: 999px;
-}
-
-:host(.button-rectangular) {
- --border-radius: 0px;
-}
-
-// Strong Button
-// --------------------------------------------------
-
-:host(.button-strong) {
- font-weight: #{$button-ios-strong-font-weight};
-}
-
-// Icon Only Button
-// --------------------------------------------------
-
-:host(.button-has-icon-only) {
- --padding-top: 0;
- --padding-bottom: var(--padding-top);
- --padding-end: var(--padding-top);
- --padding-start: var(--padding-end);
- // TODO(FW-6053): replace em value with the min-height variable.
- min-width: clamp(30px, 2.125em, 60px);
-
- // TODO(FW-6053): replace em value with the min-height variable.
- min-height: clamp(30px, 2.125em, 60px);
-}
-
-::slotted(ion-icon[slot="icon-only"]) {
- /**
- * The values were provided through a native iOS app.
- * min font size: 15px, default font size: 18px, max font size: 43px
- *
- * Since the `ion-button` uses `rem` for the font size, we can't
- * just pass the desired icon font size in `em` to the `
- * dynamic-font-clamp`. Instead, we need to adjust the base size
- * to account for the ion-button` font size.
- *
- * For example, if the default font size of `ion-button` is 16px
- * (derived from rem), then the base size can use the default font
- * size of the icon.
- */
- font-size: dynamic-font-clamp(0.84, 18px, 2.39, 1em);
-}
-
-:host(.button-small.button-has-icon-only) {
- // TODO(FW-6053): replace em value with the min-height variable.
- min-width: clamp(23px, 2.16em, 54px);
- // TODO(FW-6053): replace em value with the min-height variable.
- min-height: clamp(23px, 2.16em, 54px);
-}
-
-:host(.button-small) ::slotted(ion-icon[slot="icon-only"]) {
- /**
- * The values were provided through a native iOS app.
- * min font size: 12px, default font size: 17px, max font size: 40px
- *
- * Since the `ion-button` uses `rem` for the font size, we can't
- * just pass the desired icon font size in `em` to the `
- * dynamic-font-clamp`. Instead, we need to adjust the base size
- * to account for the ion-button` font size.
- *
- * For example, if the default font size of `ion-button` is 13px
- * (derived from rem) and the default font size of the icon is
- * 17px, then the base size would need to be increased.
- */
- font-size: dynamic-font-clamp(0.58, 20.93px, 1.92, 1em);
-}
-
-:host(.button-large.button-has-icon-only) {
- // TODO(FW-6053): replace em value with the min-height variable.
- min-width: clamp(46px, 2.5em, 78px);
- // TODO(FW-6053): replace em value with the min-height variable.
- min-height: clamp(46px, 2.5em, 78px);
-}
-
-:host(.button-large) ::slotted(ion-icon[slot="icon-only"]) {
- /**
- * The values were provided through a native iOS app.
- * min font size: 15px, default font size: 18px, max font size: 43px
- *
- * Since the `ion-button` uses `rem` for the font size, we can't
- * just pass the desired icon font size in `em` to the `
- * dynamic-font-clamp`. Instead, we need to adjust the base size
- * to account for the ion-button` font size.
- *
- * For example, if the default font size of `ion-button` is 20px
- * (derived from rem) and the default font size of the icon is
- * 18px, then the base size would need to be decreased.
- */
- font-size: dynamic-font-clamp(1.05, 14.4px, 2.99, 1em);
-}
-
-// iOS Button Focused
-// --------------------------------------------------
-
-:host(.button-outline.ion-focused.ion-color) .button-native,
-:host(.button-clear.ion-focused.ion-color) .button-native {
- color: current-color(base);
-
- &::after {
- background: current-color(base);
- }
-}
-
-:host(.button-solid.ion-color.ion-focused) .button-native::after {
- background: #{current-color(shade)};
-}
-
-// iOS Button Hover
-// --------------------------------------------------
-
-@media (any-hover: hover) {
- // Clear and outline buttons use opacity so set
- // background to transparent, but this shouldn't
- // apply on top of activated
- :host(.button-clear:not(.ion-activated):hover),
- :host(.button-outline:not(.ion-activated):hover) {
- opacity: #{$button-ios-clear-opacity-hover};
- }
-
- :host(.button-clear.ion-color:hover) .button-native,
- :host(.button-outline.ion-color:hover) .button-native {
- color: #{current-color(base)};
-
- &::after {
- background: transparent;
- }
- }
-
- // Solid buttons use the tint background
- :host(.button-solid.ion-color:hover) .button-native::after {
- background: #{current-color(tint)};
- }
-
- // Solid buttons inside of a toolbar should use a tint of the current
- // background so use white to tint it, but this should not apply
- // when activated
- :host(:hover.button-solid.in-toolbar:not(.ion-color):not(.in-toolbar-color):not(.ion-activated))
- .button-native::after {
- background: #fff;
-
- opacity: 0.1;
- }
-}
-
-// iOS Button Activated
-// --------------------------------------------------
-
-:host(.button-clear.ion-activated) {
- opacity: #{$button-ios-clear-opacity-activated};
-}
-
-:host(.button-outline.ion-activated.ion-color) .button-native {
- color: current-color(contrast);
-
- &::after {
- background: current-color(base);
- }
-}
-
-:host(.button-solid.ion-color.ion-activated) .button-native::after {
- background: #{current-color(shade)};
-}
-
-// Activated Button in Toolbar
-// --------------------------------------------------
-
-:host(.button-outline.ion-activated.in-toolbar:not(.ion-color):not(.in-toolbar-color)) .button-native {
- background: var(--ion-toolbar-color, var(--color));
- color: #{var(--ion-toolbar-background, var(--background), ion-color(primary, contrast))};
-}
-
-// Button in Datetime
-// --------------------------------------------------
-
-:host(.in-datetime) {
- --padding-top: 3px;
- --padding-bottom: 3px;
- --padding-start: 5px;
- --padding-end: 5px;
-
- font-size: dynamic-font-clamp(1, 17px, 1.24);
- font-weight: 400;
-}
diff --git a/core/src/components/button/button.ios.vars.scss b/core/src/components/button/button.ios.vars.scss
deleted file mode 100644
index ff0911a634d..00000000000
--- a/core/src/components/button/button.ios.vars.scss
+++ /dev/null
@@ -1,120 +0,0 @@
-@import "../../themes/native/native.globals.ios";
-
-// iOS Button
-// --------------------------------------------------
-
-/// @prop - Margin top of the button
-$button-ios-margin-top: 4px;
-
-/// @prop - Margin end of the button
-$button-ios-margin-end: 2px;
-
-/// @prop - Margin bottom of the button
-$button-ios-margin-bottom: 4px;
-
-/// @prop - Margin start of the button
-$button-ios-margin-start: 2px;
-
-/// @prop - Padding top of the button
-$button-ios-padding-top: 13px;
-
-/// @prop - Padding end of the button
-$button-ios-padding-end: 1em;
-
-/// @prop - Padding bottom of the button
-$button-ios-padding-bottom: $button-ios-padding-top;
-
-/// @prop - Padding start of the button
-$button-ios-padding-start: $button-ios-padding-end;
-
-/// @prop - Minimum height of the button
-$button-ios-min-height: 3.1em;
-
-/// @prop - Font size of the button text
-/// The maximum font size is calculated by taking the default font size
-/// and multiplying it by 3, since 310% of the default is the maximum
-$button-ios-font-size: dynamic-font-max(16px, 3);
-
-/// @prop - Font weight of the button text
-$button-ios-font-weight: 500;
-
-// iOS Large Button
-// --------------------------------------------------
-
-/// @prop - Padding top of the large button
-$button-ios-large-padding-top: 17px;
-
-/// @prop - Padding end of the large button
-$button-ios-large-padding-end: 1em;
-
-/// @prop - Padding bottom of the large button
-$button-ios-large-padding-bottom: $button-ios-large-padding-top;
-
-/// @prop - Padding start of the large button
-$button-ios-large-padding-start: $button-ios-large-padding-end;
-
-/// @prop - Minimum height of the large button
-$button-ios-large-min-height: 3.1em;
-
-/// @prop - Font size of the large button
-/// The maximum font size is calculated by taking the default font size
-/// and multiplying it by 3, since 310% of the default is the maximum
-$button-ios-large-font-size: dynamic-font-max(20px, 3);
-
-// iOS Small Button
-// --------------------------------------------------
-
-/// @prop - Padding top of the small button
-$button-ios-small-padding-top: 4px;
-
-/// @prop - Padding end of the small button
-$button-ios-small-padding-end: 0.9em;
-
-/// @prop - Padding bottom of the small button
-$button-ios-small-padding-bottom: $button-ios-small-padding-top;
-
-/// @prop - Padding start of the small button
-$button-ios-small-padding-start: $button-ios-small-padding-end;
-
-/// @prop - Minimum height of the small button
-$button-ios-small-min-height: 2.1em;
-
-/// @prop - Font size of the small button
-/// The maximum font size is calculated by taking the default font size
-/// and multiplying it by 3, since 310% of the default is the maximum
-$button-ios-small-font-size: dynamic-font-max(13px, 3);
-
-// iOS Outline Button
-// --------------------------------------------------
-
-/// @prop - Border width of the outline button
-$button-ios-outline-border-width: 1px;
-
-/// @prop - Border style of the outline button
-$button-ios-outline-border-style: solid;
-
-// iOS Clear Button
-// --------------------------------------------------
-
-/// @prop - Font size of the clear button
-/// The maximum font size is calculated by taking the default font size
-/// and multiplying it by 3, since 310% of the default is the maximum
-$button-ios-clear-font-size: dynamic-font-max(17px, 3);
-
-/// @prop - Font weight of the clear button
-$button-ios-clear-font-weight: normal;
-
-/// @prop - Letter spacing of the button
-$button-ios-letter-spacing: 0;
-
-/// @prop - Opacity of the activated clear button
-$button-ios-clear-opacity-activated: 0.4;
-
-/// @prop - Opacity of the clear button on hover
-$button-ios-clear-opacity-hover: 0.6;
-
-// iOS Decorator Button
-// --------------------------------------------------
-
-/// @prop - Font weight of the strong button
-$button-ios-strong-font-weight: 600;
diff --git a/core/src/components/button/button.md.scss b/core/src/components/button/button.md.scss
deleted file mode 100644
index 35fd00dbce1..00000000000
--- a/core/src/components/button/button.md.scss
+++ /dev/null
@@ -1,262 +0,0 @@
-@import "./button.native";
-@import "./button.md.vars";
-
-// Material Design Button
-// --------------------------------------------------
-
-:host {
- --padding-top: #{$button-md-padding-top};
- --padding-bottom: #{$button-md-padding-bottom};
- --padding-start: #{$button-md-padding-start};
- --padding-end: #{$button-md-padding-end};
- --transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1), background-color 15ms linear, color 15ms linear;
-
- @include margin($button-md-margin-top, $button-md-margin-end, $button-md-margin-bottom, $button-md-margin-start);
-
- min-height: #{$button-md-min-height};
-
- font-size: #{$button-md-font-size};
- font-weight: #{$button-md-font-weight};
-
- letter-spacing: #{$button-md-letter-spacing};
-
- text-transform: #{$button-md-text-transform};
-}
-
-// Solid Button
-// --------------------------------------------------
-
-:host(.button-solid) {
- --background-activated: transparent;
- --background-hover: #{ion-color(primary, contrast)};
- --background-focused: #{ion-color(primary, contrast)};
- --background-activated-opacity: 0;
- --background-focused-opacity: 0.24;
- --background-hover-opacity: 0.08;
- --box-shadow: #{$button-md-box-shadow};
-}
-
-:host(.button-solid.ion-activated) {
- --box-shadow: #{$button-md-box-shadow-activated};
-}
-
-// Outline Button
-// --------------------------------------------------
-
-:host(.button-outline) {
- --border-width: 2px;
- --border-style: solid;
- --box-shadow: none;
- --background-activated: transparent;
- --background-focused: #{ion-color(primary, base)};
- --background-hover: #{ion-color(primary, base)};
- --background-activated-opacity: 0;
- --background-focused-opacity: 0.12;
- --background-hover-opacity: 0.04;
-}
-
-:host(.button-outline.ion-activated.ion-color) .button-native {
- background: transparent;
-}
-
-// Clear Button
-// --------------------------------------------------
-
-:host(.button-clear) {
- --background-activated: transparent;
- --background-focused: #{ion-color(primary, base)};
- --background-hover: #{ion-color(primary, base)};
- --background-activated-opacity: 0;
- --background-focused-opacity: 0.12;
- --background-hover-opacity: 0.04;
-}
-
-// Button Shapes
-// -------------------------------------------------------------------------------
-
-:host(.button-soft) {
- --border-radius: 4px;
-}
-
-:host(.button-round) {
- --border-radius: 999px;
-}
-
-:host(.button-rectangular) {
- --border-radius: 0px;
-}
-
-// Button Sizes
-// --------------------------------------------------
-
-:host(.button-large) {
- --padding-top: #{$button-md-large-padding-top};
- --padding-start: #{$button-md-large-padding-start};
- --padding-end: #{$button-md-large-padding-end};
- --padding-bottom: #{$button-md-large-padding-bottom};
-
- min-height: #{$button-md-large-min-height};
-
- font-size: #{$button-md-large-font-size};
-}
-
-:host(.button-small) {
- --padding-top: #{$button-md-small-padding-top};
- --padding-start: #{$button-md-small-padding-start};
- --padding-end: #{$button-md-small-padding-end};
- --padding-bottom: #{$button-md-small-padding-bottom};
-
- min-height: #{$button-md-small-min-height};
-
- font-size: #{$button-md-small-font-size};
-}
-
-// Strong Button
-// --------------------------------------------------
-
-:host(.button-strong) {
- font-weight: #{$button-md-strong-font-weight};
-}
-
-// Icon Only Button
-//
-// MD does not specify a small size, these
-// styles are based on the iOS small size.
-//
-// MD does not specify a large size, these
-// styles are based on the iOS large size.
-// --------------------------------------------------
-
-:host(.button-has-icon-only) {
- --padding-top: 0;
- --padding-bottom: var(--padding-top);
- --padding-end: var(--padding-top);
- --padding-start: var(--padding-end);
- // TODO(FW-6053): replace em value with the min-height variable.
- min-width: clamp(30px, 2.86em, 60px);
-
- // TODO(FW-6053): replace em value with the min-height variable.
- min-height: clamp(30px, 2.86em, 60px);
-}
-
-::slotted(ion-icon[slot="icon-only"]) {
- /**
- * The values were provided through MD design,
- * large and small are based on the iOS sizes.
- * min font size: 15px, default font size: 22.4px, max font size: 43px
- *
- * Since the `ion-button` uses `rem` for the font size, we can't
- * just pass the desired icon font size in `em` to the `
- * dynamic-font-clamp`. Instead, we need to adjust the base size
- * to account for the ion-button` font size.
- *
- * For example, if the default font size of `ion-button` is 14px
- * (derived from rem) and the default font size of the icon is
- * 22.4px, then the base size would need to be increased.
- */
- font-size: dynamic-font-clamp(0.59, 25.6px, 1.68, 1em);
-}
-
-:host(.button-small.button-has-icon-only) {
- // TODO(FW-6053): replace em value with the min-height variable.
- min-width: clamp(23px, 2.16em, 54px);
- // TODO(FW-6053): replace em value with the min-height variable.
- min-height: clamp(23px, 2.16em, 54px);
-}
-
-:host(.button-small) ::slotted(ion-icon[slot="icon-only"]) {
- /**
- * The values were provided through MD design,
- * large and small are based on the iOS sizes.
- * min font size: 12px, default font size: 16px, max font size: 40px
- *
- * Since the `ion-button` uses `rem` for the font size, we can't
- * just pass the desired icon font size in `em` to the `
- * dynamic-font-clamp`. Instead, we need to adjust the base size
- * to account for the ion-button` font size.
- *
- * For example, if the default font size of `ion-button` is 13px
- * (derived from rem) and the default font size of the icon is
- * 16px, then the base size would need to be increased.
- */
- font-size: dynamic-font-clamp(0.66, 19.7px, 2.05, 1em);
-}
-
-:host(.button-large.button-has-icon-only) {
- // TODO(FW-6053): replace em value with the min-height variable.
- min-width: clamp(46px, 2.5em, 78px);
- // TODO(FW-6053): replace em value with the min-height variable.
- min-height: clamp(46px, 2.5em, 78px);
-}
-
-:host(.button-large) ::slotted(ion-icon[slot="icon-only"]) {
- /**
- * The values were provided through MD design,
- * large and small are based on the iOS sizes.
- * min font size: 15px, default font size: 28px, max font size: 43px
- *
- * Since the `ion-button` uses `rem` for the font size, we can't
- * just pass the desired icon font size in `em` to the `
- * dynamic-font-clamp`. Instead, we need to adjust the base size
- * to account for the ion-button` font size.
- *
- * For example, if the default font size of `ion-button` is 20px
- * (derived from rem) and the default font size of the icon is
- * 28px, then the base size would need to be increased.
- */
- font-size: dynamic-font-clamp(0.67, 22.4px, 1.92, 1em);
-}
-
-// Button: Hover
-// --------------------------------------------------
-
-/**
- * Only allow overriding of opacity here
- * as developers should not be overriding
- * colors when using the color prop.
- */
-
-:host(.button-solid.ion-color.ion-focused) .button-native::after {
- background: #{current-color(contrast)};
-}
-
-:host(.button-clear.ion-color.ion-focused) .button-native::after,
-:host(.button-outline.ion-color.ion-focused) .button-native::after {
- background: #{current-color(base)};
-}
-
-@media (any-hover: hover) {
- :host(.button-solid.ion-color:hover) .button-native::after {
- background: #{current-color(contrast)};
- }
-
- :host(.button-clear.ion-color:hover) .button-native::after,
- :host(.button-outline.ion-color:hover) .button-native::after {
- background: #{current-color(base)};
- }
-}
-
-// Activated Button in Toolbar
-// --------------------------------------------------
-
-:host(.button-outline.ion-activated.in-toolbar:not(.ion-color):not(.in-toolbar-color)) .button-native {
- background: var(--ion-toolbar-background, var(--color));
- color: #{var(--ion-toolbar-color, var(--background), ion-color(primary, contrast))};
-}
-
-// Button in Datetime
-// --------------------------------------------------
-
-:host(.in-datetime) {
- --padding-top: 3px;
- --padding-bottom: 3px;
- --padding-start: 8px;
- --padding-end: 8px;
- --box-shadow: none;
-}
-
-:host(.in-datetime.button-clear) {
- --background-activated: transparent;
- --background-focused: currentColor;
- --background-hover: currentColor;
-}
diff --git a/core/src/components/button/button.md.vars.scss b/core/src/components/button/button.md.vars.scss
deleted file mode 100644
index dd68ef0ebb4..00000000000
--- a/core/src/components/button/button.md.vars.scss
+++ /dev/null
@@ -1,98 +0,0 @@
-@import "../../themes/native/native.globals.md";
-
-// Material Design Button
-// --------------------------------------------------
-
-/// @prop - Margin top of the button
-$button-md-margin-top: 4px;
-
-/// @prop - Margin end of the button
-$button-md-margin-end: 2px;
-
-/// @prop - Margin bottom of the button
-$button-md-margin-bottom: 4px;
-
-/// @prop - Margin start of the button
-$button-md-margin-start: 2px;
-
-/// @prop - Padding top of the button
-$button-md-padding-top: 8px;
-
-/// @prop - Padding end of the button
-$button-md-padding-end: 1.1em;
-
-/// @prop - Padding bottom of the button
-$button-md-padding-bottom: $button-md-padding-top;
-
-/// @prop - Padding start of the button
-$button-md-padding-start: 1.1em;
-
-/// @prop - Minimum height of the button
-$button-md-min-height: 36px;
-
-/// @prop - Font size of the button text
-$button-md-font-size: dynamic-font(14px);
-
-/// @prop - Font weight of the button text
-$button-md-font-weight: 500;
-
-/// @prop - Capitalization of the button text
-$button-md-text-transform: uppercase;
-
-$button-md-letter-spacing: 0.06em;
-
-/// @prop - Box shadow of the button
-$button-md-box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),
- 0 1px 5px 0 rgba(0, 0, 0, 0.12);
-
-/// @prop - Box shadow of the activated button
-$button-md-box-shadow-activated: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14),
- 0 3px 14px 2px rgba(0, 0, 0, 0.12);
-
-// Material Design Large Button
-// --------------------------------------------------
-
-/// @prop - Padding top of the large button
-$button-md-large-padding-top: 14px;
-
-/// @prop - Padding end of the large button
-$button-md-large-padding-end: 1em;
-
-/// @prop - Padding bottom of the large button
-$button-md-large-padding-bottom: $button-md-large-padding-top;
-
-/// @prop - Padding start of the large button
-$button-md-large-padding-start: $button-md-large-padding-end;
-
-/// @prop - Minimum height of the large button
-$button-md-large-min-height: 2.8em;
-
-/// @prop - Font size of the large button
-$button-md-large-font-size: dynamic-font(20px);
-
-// Material Design Small Button
-// --------------------------------------------------
-
-/// @prop - Padding top of the small button
-$button-md-small-padding-top: 4px;
-
-/// @prop - Padding end of the small button
-$button-md-small-padding-end: 0.9em;
-
-/// @prop - Padding bottom of the small button
-$button-md-small-padding-bottom: $button-md-small-padding-top;
-
-/// @prop - Padding start of the small button
-$button-md-small-padding-start: $button-md-small-padding-end;
-
-/// @prop - Minimum height of the small button
-$button-md-small-min-height: 2.1em;
-
-/// @prop - Font size of the small button
-$button-md-small-font-size: dynamic-font(13px);
-
-// Material Design Decorator Button
-// --------------------------------------------------
-
-/// @prop - Font weight of the strong button
-$button-md-strong-font-weight: bold;
diff --git a/core/src/components/button/button.native.scss b/core/src/components/button/button.native.scss
deleted file mode 100644
index 07a32238f20..00000000000
--- a/core/src/components/button/button.native.scss
+++ /dev/null
@@ -1,59 +0,0 @@
-@use "../../themes/native/native.globals" as globals;
-@use "./button.common";
-
-// Button - iOS and Material Design
-// --------------------------------------------------
-
-:host {
- font-family: globals.$font-family-base;
-}
-
-// Solid Button
-// --------------------------------------------------
-
-// Default Solid Color
-:host(.button-solid) {
- --background: #{globals.ion-color(primary, base)};
- --color: #{globals.ion-color(primary, contrast)};
-}
-
-// Outline Button
-// --------------------------------------------------
-
-// Default Outline Color
-:host(.button-outline) {
- --border-color: #{globals.ion-color(primary, base)};
- --color: #{globals.ion-color(primary, base)};
-}
-
-// Clear Button
-// --------------------------------------------------
-
-// Default Clear Color
-:host(.button-clear) {
- --color: #{globals.ion-color(primary, foreground)};
-}
-
-// Button Icons
-// --------------------------------------------------
-
-::slotted(ion-icon) {
- font-size: 1.35em;
-}
-
-::slotted(ion-icon[slot="start"]) {
- @include globals.margin(0, 0.3em, 0, -0.3em);
-}
-
-::slotted(ion-icon[slot="end"]) {
- @include globals.margin(0, -0.2em, 0, 0.3em);
-}
-
-// Button in Datetime
-// --------------------------------------------------
-
-:host(.in-datetime) {
- @include globals.margin(0px, 2px, 0px, 2px);
-
- min-height: 32px;
-}
diff --git a/core/src/components/button/button.scss b/core/src/components/button/button.scss
new file mode 100644
index 00000000000..ff68a70b6b4
--- /dev/null
+++ b/core/src/components/button/button.scss
@@ -0,0 +1,472 @@
+@use "../../themes/mixins" as mixins;
+@use "./button.docs";
+
+// Button
+// --------------------------------------------------
+
+$fills: solid, outline, clear;
+$sizes: small, medium, large;
+$shapes: crisp, soft, round, rectangular;
+$spinner-sizes: xsmall, small, medium, large, xlarge;
+
+:host {
+ /**
+ * The undocumented padding hooks still work for the `ion-padding` classes set on
+ * the button itself. Reset them so the button never inherits them from an ancestor.
+ *
+ * TODO(FW-6838): Parents such as ion-buttons, ion-item and ion-input still set these
+ * hooks on buttons. Move them to nested tokens, such as `IonItem.IonButton.size.small.padding`.
+ */
+ --padding-top: initial;
+ --padding-end: initial;
+ --padding-bottom: initial;
+ --padding-start: initial;
+
+ @include mixins.margin(
+ var(--ion-button-margin-top),
+ var(--ion-button-margin-end),
+ var(--ion-button-margin-bottom),
+ var(--ion-button-margin-start)
+ );
+
+ display: inline-block;
+
+ width: auto;
+
+ font-family: var(--ion-button-font-family, inherit);
+
+ letter-spacing: var(--ion-button-letter-spacing);
+
+ text-align: center;
+ text-decoration: none;
+ text-transform: var(--ion-button-text-transform);
+
+ white-space: normal;
+
+ user-select: none;
+
+ // Firefox doesn't support the value below, so it drops that declaration and keeps this one
+ vertical-align: top;
+
+ /**
+ * Non-standard, supported by Chromium and Safari. It centers the button on the
+ * text baseline, so a button inline with text lines up with it.
+ */
+ vertical-align: -webkit-baseline-middle;
+
+ font-kerning: none;
+}
+
+// Button: Native
+// --------------------------------------------------
+
+.button-native {
+ @include mixins.font-smoothing();
+ @include mixins.margin(0);
+ @include mixins.text-inherit();
+
+ display: flex;
+
+ position: relative;
+
+ align-items: center;
+
+ width: 100%;
+ height: 100%;
+
+ min-height: inherit;
+
+ transition: var(--ion-button-transition);
+
+ outline: none;
+
+ line-height: 1;
+
+ contain: layout style;
+ cursor: pointer;
+
+ overflow: hidden;
+
+ z-index: 0;
+ box-sizing: border-box;
+ appearance: none;
+}
+
+.button-native::-moz-focus-inner {
+ border: 0;
+}
+
+.button-inner {
+ display: flex;
+ position: relative;
+
+ flex-flow: row nowrap;
+ flex-shrink: 0;
+ align-items: center;
+ justify-content: center;
+
+ width: 100%;
+ height: 100%;
+
+ z-index: 1;
+}
+
+// Button: Sizes
+// --------------------------------------------------
+
+@each $size in $sizes {
+ :host(.button-size-#{$size}) {
+ min-width: var(--ion-button-size-#{$size}-min-width);
+ min-height: var(--ion-button-size-#{$size}-min-height);
+
+ font-size: var(--ion-button-size-#{$size}-font-size);
+
+ line-height: var(--ion-button-size-#{$size}-line-height);
+ }
+
+ :host(.button-size-#{$size}) .button-native {
+ @include mixins.padding(
+ var(--padding-top, var(--ion-button-size-#{$size}-padding-top)),
+ var(--padding-end, var(--ion-button-size-#{$size}-padding-end)),
+ var(--padding-bottom, var(--ion-button-size-#{$size}-padding-bottom)),
+ var(--padding-start, var(--ion-button-size-#{$size}-padding-start))
+ );
+ }
+}
+
+// Button: Fill Typography
+// --------------------------------------------------
+
+@each $fill in $fills {
+ :host(.button-hue-bold.button-fill-#{$fill}) {
+ font-weight: var(--ion-button-hue-bold-#{$fill}-default-font-weight);
+ }
+}
+
+@each $fill in $fills {
+ :host(.button-hue-bold.button-fill-#{$fill}.button-strong) {
+ font-weight: var(--ion-button-hue-bold-#{$fill}-strong-font-weight);
+ }
+}
+
+// Button: Shapes
+// --------------------------------------------------
+
+@each $shape in $shapes {
+ :host(.button-shape-#{$shape}) .button-native {
+ @include mixins.border-radius(var(--ion-button-shape-#{$shape}-border-radius));
+ }
+}
+
+.button-native ion-ripple-effect {
+ @include mixins.border-radius(inherit);
+}
+
+// Button: Icon Only
+// --------------------------------------------------
+
+@each $size in $sizes {
+ // A square as tall as a text button of the same size. Not `aspect-ratio`,
+ // which needs a newer Firefox than Ionic supports.
+ :host(.button-size-#{$size}.button-has-icon-only) {
+ min-width: var(--ion-button-size-#{$size}-min-height);
+ min-height: var(--ion-button-size-#{$size}-min-height);
+ }
+
+ :host(.button-size-#{$size}.button-has-icon-only) .button-native {
+ @include mixins.padding(
+ var(--padding-top, var(--ion-button-size-#{$size}-icon-only-padding-top)),
+ var(--padding-end, var(--ion-button-size-#{$size}-icon-only-padding-end)),
+ var(--padding-bottom, var(--ion-button-size-#{$size}-icon-only-padding-bottom)),
+ var(--padding-start, var(--ion-button-size-#{$size}-icon-only-padding-start))
+ );
+ }
+}
+
+// Button: Slotted Elements
+// --------------------------------------------------
+
+::slotted([slot="start"]),
+::slotted([slot="end"]) {
+ flex-shrink: 0;
+}
+
+::slotted(ion-icon),
+::slotted(ion-spinner) {
+ pointer-events: none;
+}
+
+::slotted(ion-spinner) {
+ color: currentColor;
+}
+
+/**
+ * Only the ionic theme sizes and spaces a slotted spinner. The other
+ * themes fall back to the spinner's own size and no margin.
+ */
+@each $size in $sizes {
+ @each $spinner-size in $spinner-sizes {
+ $spinner: "ion-spinner.spinner-size-#{$spinner-size}";
+
+ :host(.button-size-#{$size}) ::slotted(#{$spinner}[slot="start"]),
+ :host(.button-size-#{$size}) ::slotted(#{$spinner}[slot="end"]),
+ :host(.button-size-#{$size}) ::slotted(#{$spinner}[slot="icon-only"]) {
+ $token: --ion-button-size-#{$size}-spinner-size-#{$spinner-size};
+
+ width: var(#{$token}-width, var(--ion-spinner-size-#{$spinner-size}-width));
+ height: var(#{$token}-height, var(--ion-spinner-size-#{$spinner-size}-height));
+ }
+ }
+}
+
+@each $size in $sizes {
+ :host(.button-size-#{$size}) ::slotted(ion-icon) {
+ font-size: var(--ion-button-size-#{$size}-icon-font-size);
+ }
+
+ :host(.button-size-#{$size}) ::slotted(ion-icon[slot="icon-only"]) {
+ font-size: var(--ion-button-size-#{$size}-icon-only-icon-font-size);
+ }
+}
+
+@each $size in $sizes {
+ :host(.button-size-#{$size}) ::slotted(ion-icon[slot="start"]) {
+ @include mixins.margin(
+ var(--ion-button-size-#{$size}-icon-leading-margin-top),
+ var(--ion-button-size-#{$size}-icon-leading-margin-end),
+ var(--ion-button-size-#{$size}-icon-leading-margin-bottom),
+ var(--ion-button-size-#{$size}-icon-leading-margin-start)
+ );
+ }
+
+ :host(.button-size-#{$size}) ::slotted(ion-icon[slot="end"]) {
+ @include mixins.margin(
+ var(--ion-button-size-#{$size}-icon-trailing-margin-top),
+ var(--ion-button-size-#{$size}-icon-trailing-margin-end),
+ var(--ion-button-size-#{$size}-icon-trailing-margin-bottom),
+ var(--ion-button-size-#{$size}-icon-trailing-margin-start)
+ );
+ }
+
+ :host(.button-size-#{$size}) ::slotted(ion-spinner[slot="start"]) {
+ @include mixins.margin(
+ var(--ion-button-size-#{$size}-spinner-leading-margin-top),
+ var(--ion-button-size-#{$size}-spinner-leading-margin-end),
+ var(--ion-button-size-#{$size}-spinner-leading-margin-bottom),
+ var(--ion-button-size-#{$size}-spinner-leading-margin-start)
+ );
+ }
+
+ :host(.button-size-#{$size}) ::slotted(ion-spinner[slot="end"]) {
+ @include mixins.margin(
+ var(--ion-button-size-#{$size}-spinner-trailing-margin-top),
+ var(--ion-button-size-#{$size}-spinner-trailing-margin-end),
+ var(--ion-button-size-#{$size}-spinner-trailing-margin-bottom),
+ var(--ion-button-size-#{$size}-spinner-trailing-margin-start)
+ );
+ }
+}
+
+// Button: Hues and Fills
+// --------------------------------------------------
+
+/**
+ * Each fill has a resting look and one for each state. Without a color,
+ * the button reads the plain tokens. With a color, it reads the `semantic`
+ * tokens, which use the color's base, contrast and so on.
+ */
+@each $fill in $fills {
+ $token: --ion-button-hue-bold-#{$fill};
+
+ :host(.button-hue-bold.button-fill-#{$fill}) {
+ color: var(#{$token}-default-color);
+ }
+
+ :host(.button-hue-bold.button-fill-#{$fill}) .button-native {
+ border-width: var(#{$token}-default-border-width);
+ border-style: var(#{$token}-default-border-style);
+ border-color: var(#{$token}-default-border-color);
+
+ background: var(#{$token}-default-background);
+
+ box-shadow: var(#{$token}-default-box-shadow);
+ }
+
+ // The ripple sits in this shadow root, out of reach of the global token CSS
+ :host(.button-hue-bold.button-fill-#{$fill}) ion-ripple-effect {
+ // A variable, because the ripple animates its opacity in a keyframe
+ --ion-ripple-effect-opacity: var(#{$token}-ripple-effect-opacity);
+
+ color: var(#{$token}-ripple-effect-color);
+ }
+
+ :host(.button-hue-bold.button-fill-#{$fill}.ion-color) .button-native {
+ border-color: var(#{$token}-semantic-default-border-color);
+
+ background: var(#{$token}-semantic-default-background);
+ color: var(#{$token}-semantic-default-color);
+ }
+
+ :host(.button-hue-bold.button-fill-#{$fill}.ion-color) ion-ripple-effect {
+ --ion-ripple-effect-opacity: var(#{$token}-semantic-ripple-effect-opacity);
+
+ color: var(#{$token}-semantic-ripple-effect-color);
+ }
+}
+
+/**
+ * The states are written in this order: focus -> hover -> activated -> disabled.
+ * Their rules share a specificity, so a later state overrides an earlier
+ * one: disabled overrides all, and activated overrides hover and focus.
+ */
+
+// Focused
+@each $fill in $fills {
+ $token: --ion-button-hue-bold-#{$fill};
+
+ :host(.button-hue-bold.button-fill-#{$fill}.ion-focused) {
+ color: var(#{$token}-focus-color);
+ }
+
+ :host(.button-hue-bold.button-fill-#{$fill}.ion-focused) .button-native {
+ background: var(#{$token}-focus-background);
+ }
+
+ :host(.button-hue-bold.button-fill-#{$fill}.ion-color.ion-focused) .button-native {
+ background: var(#{$token}-semantic-focus-background);
+ color: var(#{$token}-semantic-focus-color);
+ }
+}
+
+// Hover
+@media (any-hover: hover) {
+ @each $fill in $fills {
+ $token: --ion-button-hue-bold-#{$fill};
+
+ :host(.button-hue-bold.button-fill-#{$fill}:hover) {
+ color: var(#{$token}-hover-color);
+ }
+
+ // Disabled keeps its own opacity
+ :host(.button-hue-bold.button-fill-#{$fill}:not(.button-disabled):hover) {
+ opacity: var(#{$token}-hover-opacity);
+ }
+
+ :host(.button-hue-bold.button-fill-#{$fill}:hover) .button-native {
+ background: var(#{$token}-hover-background);
+ }
+
+ :host(.button-hue-bold.button-fill-#{$fill}.ion-color:hover) .button-native {
+ background: var(#{$token}-semantic-hover-background);
+ color: var(#{$token}-semantic-hover-color);
+ }
+ }
+}
+
+// Activated
+@each $fill in $fills {
+ $token: --ion-button-hue-bold-#{$fill};
+
+ :host(.button-hue-bold.button-fill-#{$fill}.ion-activated) {
+ color: var(#{$token}-activated-color);
+ }
+
+ // Disabled keeps its own opacity
+ :host(.button-hue-bold.button-fill-#{$fill}.ion-activated:not(.button-disabled)) {
+ opacity: var(#{$token}-activated-opacity);
+ }
+
+ :host(.button-hue-bold.button-fill-#{$fill}.ion-activated) .button-native {
+ background: var(#{$token}-activated-background);
+
+ box-shadow: var(#{$token}-activated-box-shadow);
+ }
+
+ :host(.button-hue-bold.button-fill-#{$fill}.ion-color.ion-activated) .button-native {
+ background: var(#{$token}-semantic-activated-background);
+ color: var(#{$token}-semantic-activated-color);
+ }
+
+ /**
+ * Only `md` mode renders a ripple. When it does, the ripple shows the press,
+ * so the button keeps its default background instead of the activated one.
+ */
+ :host(.button-hue-bold.button-fill-#{$fill}.ion-activated) .button-native:has(ion-ripple-effect) {
+ background: var(#{$token}-default-background);
+ }
+
+ :host(.button-hue-bold.button-fill-#{$fill}.ion-color.ion-activated) .button-native:has(ion-ripple-effect) {
+ background: var(#{$token}-semantic-default-background);
+ }
+}
+
+// Disabled
+@each $fill in $fills {
+ $token: --ion-button-hue-bold-#{$fill};
+
+ :host(.button-hue-bold.button-fill-#{$fill}.button-disabled) {
+ opacity: var(#{$token}-disabled-opacity);
+ }
+
+ :host(.button-hue-bold.button-fill-#{$fill}.button-disabled) .button-native {
+ background: var(#{$token}-disabled-background);
+ }
+
+ :host(.button-hue-bold.button-fill-#{$fill}.ion-color.button-disabled) .button-native {
+ background: var(#{$token}-semantic-disabled-background);
+ }
+}
+
+// Button: Disabled
+// --------------------------------------------------
+
+:host(.button-disabled) {
+ cursor: default;
+ pointer-events: none;
+}
+
+// Button: Focus Ring
+// --------------------------------------------------
+
+:host(.ion-focused) .button-native {
+ outline-color: var(--ion-button-state-focus-ring-color);
+ outline-offset: var(--ion-button-state-focus-ring-offset);
+ outline-style: var(--ion-button-state-focus-ring-style);
+ outline-width: var(--ion-button-state-focus-ring-width);
+}
+
+// Button: Expand
+// --------------------------------------------------
+
+// After the fills, so a full button drops the side borders they set
+:host(.button-expand-block),
+:host(.button-expand-full) {
+ display: block;
+}
+
+:host(.button-expand-block) .button-native,
+:host(.button-expand-full) .button-native {
+ @include mixins.margin-horizontal(0);
+
+ width: 100%;
+
+ contain: content;
+}
+
+:host(.button-expand-block) .button-native {
+ clear: both;
+}
+
+:host(.button-expand-full:not(.button-shape-round)) .button-native {
+ @include mixins.border-radius(0);
+
+ border-right-width: 0;
+ border-left-width: 0;
+}
+
+// Button: With a Badge
+// --------------------------------------------------
+
+:host(.button-has-badge) .button-native {
+ overflow: visible;
+}
diff --git a/core/src/components/button/button.tsx b/core/src/components/button/button.tsx
index 7b584e205b4..e3f1b33aac8 100644
--- a/core/src/components/button/button.tsx
+++ b/core/src/components/button/button.tsx
@@ -8,13 +8,16 @@ import { hasShadowDom, openURL } from '@utils/helpers';
import { printIonWarning } from '@utils/logging';
import { createColorClasses, hostContext } from '@utils/theme';
-import { getIonTheme, getIonMode } from '../../global/ionic-global';
+import { config } from '../../global/config';
+import { getIonMode } from '../../global/ionic-global';
import type { AnimationBuilder, Color } from '../../interface';
+import type { Hue } from '../../themes/themes.interfaces';
import type { RouterDirection } from '../router/utils/interface';
+import type { IonButtonExpand, IonButtonFill, IonButtonShape, IonButtonSize } from './button.interface';
+
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
- * @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*
* @slot - Content is placed between the named slots if provided without a slot.
* @slot icon-only - Should be used on an icon in a button that has no text.
@@ -25,17 +28,14 @@ import type { RouterDirection } from '../router/utils/interface';
*/
@Component({
tag: 'ion-button',
- styleUrls: {
- ios: 'button.ios.scss',
- md: 'button.md.scss',
- ionic: 'button.ionic.scss',
- },
+ styleUrl: 'button.scss',
shadow: true,
})
export class Button implements ComponentInterface, AnchorInterface, ButtonInterface {
private hasLoaded = false;
private inDatetime = false;
private inItem = false;
+ private hasWarnedSizeDefault = false;
private inListHeader = false;
private inButtons = false;
private formButtonEl: HTMLButtonElement | null = null;
@@ -83,15 +83,17 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
* Set to `"block"` for a full-width button or to `"full"` for a full-width button
* with square corners and no left or right borders.
*/
- @Prop({ reflect: true }) expand?: 'full' | 'block';
+ @Prop({ reflect: true }) expand?: IonButtonExpand;
/**
- * Set to `"clear"` for a transparent button that resembles a flat button, to `"outline"`
- * for a transparent button with a border, or to `"solid"` for a button with a filled background.
- * The default fill is `"solid"` except when inside of a buttons or datetime component, where
- * the default fill is `"clear"`.
+ * Set to `"clear"` for a transparent button that resembles a flat button,
+ * `"outline"` for a transparent button with a border,
+ * or `"solid"` for a button with a filled background.
+ *
+ * Defaults to `"solid"` if both the fill property and theme config are unset,
+ * or `"clear"` inside of buttons, datetime, or list header.
*/
- @Prop({ reflect: true, mutable: true }) fill?: 'clear' | 'outline' | 'solid' | 'default';
+ @Prop({ reflect: true, mutable: true }) fill?: IonButtonFill | 'default';
/**
* When using a router, it specifies the transition direction when navigating to
@@ -126,20 +128,26 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
@Prop() rel: string | undefined;
/**
- * Set to `"soft"` for a button with slightly rounded corners, `"round"` for a button with fully
- * rounded corners, or `"rectangular"` for a button without rounded corners.
- * Defaults to `"soft"` for the `"ios"` theme and `"round"` for all other themes.
+ * Set to `"crisp"` for a button with even slightly rounded corners,
+ * `"soft"` for a button with slightly rounded corners,
+ * `"round"` for a button with fully rounded corners,
+ * or `"rectangular"` for a button without rounded corners.
+ *
+ * Defaults to `"round"` if both the shape property and theme config are unset.
*/
- @Prop({ reflect: true }) shape?: 'soft' | 'round' | 'rectangular';
+ @Prop({ reflect: true }) shape?: IonButtonShape;
/**
- * Set to `"small"` for a button with less height and padding, to `"medium"`
- * for a button with the medium height and padding, or to `"large"` for a button
- * with more height and padding. By default the size is unset, unless the button
- * is inside of an item, where the size is `"small"` by default. Set the size to
- * `"default"` inside of an item to make it a standard size button.
+ * Set to `"small"` for a button with less height and padding,
+ * `"medium"` for a button with the standard height and padding,
+ * or `"large"` for a button with more height and padding.
+ *
+ * Defaults to `"medium"` if both the size property and theme config are unset,
+ * or `"small"` inside of an item.
+ *
+ * `"default"` is deprecated and renders the same as `"medium"`.
*/
- @Prop({ reflect: true }) size?: 'small' | 'default' | 'medium' | 'large';
+ @Prop({ reflect: true }) size?: IonButtonSize | 'default';
/**
* If `true`, activates a button with a heavier font weight.
@@ -254,10 +262,10 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
}
private get rippleType() {
- const hasClearFill = this.fill === undefined || this.fill === 'clear';
+ const hasClearFill = this.fillValue === 'clear';
// Use the unbounded "circular" ripple effect if it:
- // - Has a clear fill (the default)
+ // - Has a clear fill (the default in buttons and datetime)
// - Only has an icon and
// - Is inside of buttons (used in a toolbar) or a datetime
if (hasClearFill && this.hasIconOnly && (this.inButtons || this.inDatetime)) {
@@ -268,28 +276,65 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
}
/**
- * Set the shape based on the theme
+ * Gets the button fill. Uses the `fill` property if set, otherwise `clear` inside of
+ * buttons, datetime or list header, then the theme config. Defaults to `solid` if none apply.
*/
- private getShape(): string {
- const theme = getIonTheme(this);
- const { shape } = this;
+ get fillValue(): IonButtonFill | 'default' {
+ const { fill } = this;
+
+ if (fill !== undefined) {
+ return fill;
+ }
- if (shape === undefined) {
- return theme === 'ios' ? 'soft' : 'round';
+ if (this.inDatetime || this.inButtons || this.inListHeader) {
+ return 'clear';
}
- return shape;
+ return config.getObjectValue('IonButton.fill', 'solid') as IonButtonFill;
+ }
+
+ /**
+ * Gets the button hue from the theme config. Defaults to `bold` if it is unset.
+ */
+ get hueValue(): Hue {
+ return config.getObjectValue('IonButton.hue', 'bold') as Hue;
+ }
+
+ /**
+ * Gets the button shape. Uses the `shape` property if set, otherwise
+ * checks the theme config. Defaults to `round` if neither is set.
+ */
+ get shapeValue(): IonButtonShape {
+ const shapeConfig = config.getObjectValue('IonButton.shape', 'round') as IonButtonShape;
+
+ return this.shape ?? shapeConfig;
}
/**
- * Get the default size. If size is unset and the button is inside an item,
- * the default size is "small". Otherwise, it uses the value of size.
+ * Gets the button size. Uses the `size` property if set, otherwise `small`
+ * inside of an item, then the theme config. Defaults to `medium` if none apply.
*/
- private getSize(): string | undefined {
+ get sizeValue(): IonButtonSize {
const { size } = this;
if (size === undefined) {
- return this.inItem ? 'small' : 'medium';
+ if (this.inItem) {
+ return 'small';
+ }
+
+ return config.getObjectValue('IonButton.size', 'medium') as IonButtonSize;
+ }
+
+ if (size === 'default') {
+ if (!this.hasWarnedSizeDefault) {
+ this.hasWarnedSizeDefault = true;
+ printIonWarning(
+ '[ion-button] - The "default" size is deprecated. Use "medium" instead.\nExample: ',
+ this.el
+ );
+ }
+
+ return 'medium';
}
return size;
@@ -398,12 +443,24 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
};
render() {
- const { buttonType, type, disabled, rel, target, href, color, expand, hasIconOnly, hasBadge, strong } = this;
-
- const theme = getIonTheme(this);
+ const {
+ buttonType,
+ type,
+ disabled,
+ rel,
+ target,
+ href,
+ color,
+ expand,
+ hasIconOnly,
+ hasBadge,
+ fillValue,
+ hueValue,
+ shapeValue,
+ sizeValue,
+ strong,
+ } = this;
const mode = getIonMode(this);
- const size = this.getSize();
- const shape = this.getShape();
const inheritedAttributes = this.ariaController?.attributes ?? {};
const TagType = href === undefined ? 'button' : ('a' as any);
const attrs =
@@ -415,10 +472,6 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
rel,
target,
};
- let fill = this.fill;
- if (fill === undefined) {
- fill = this.inDatetime || this.inButtons || this.inListHeader ? 'clear' : 'solid';
- }
/**
* We call renderHiddenButton in the render function to account
@@ -436,12 +489,13 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
onClick={this.handleClick}
aria-disabled={disabled ? 'true' : null}
class={createColorClasses(color, {
- [theme]: true,
[buttonType]: true,
- [`${buttonType}-${expand}`]: expand !== undefined,
- [`${buttonType}-${size}`]: size !== undefined,
- [`${buttonType}-${shape}`]: true,
- [`${buttonType}-${fill}`]: true,
+ [`${buttonType}-expand-${expand}`]: expand !== undefined,
+ [`${buttonType}-size-${sizeValue}`]: true,
+ [`${buttonType}-shape-${shapeValue}`]: true,
+ [`${buttonType}-fill-${fillValue}`]: true,
+ // TODO(FW-6838): read the hue prop first in the hue PR
+ [`${buttonType}-hue-${hueValue}`]: true,
[`${buttonType}-strong`]: strong,
'in-datetime': this.inDatetime,
'in-toolbar': hostContext('ion-toolbar', this.el),
diff --git a/core/src/components/button/test/basic/button.e2e.ts b/core/src/components/button/test/basic/button.e2e.ts
index 500bee8a3ad..f2c3f836388 100644
--- a/core/src/components/button/test/basic/button.e2e.ts
+++ b/core/src/components/button/test/basic/button.e2e.ts
@@ -28,12 +28,12 @@ configs({ directions: ['ltr'], modes: ['md'] }).forEach(({ config, title }) => {
);
const button = page.locator('ion-button');
- await expect(button).toHaveClass(/button-outline/);
+ await expect(button).toHaveClass(/button-fill-outline/);
await button.evaluate((el: HTMLIonButtonElement) => (el.fill = undefined));
await page.waitForChanges();
- await expect(button).toHaveClass(/button-solid/);
+ await expect(button).toHaveClass(/button-fill-solid/);
});
});
});
diff --git a/core/src/components/button/test/basic/index.html b/core/src/components/button/test/basic/index.html
index 19efe474cea..9e56c946988 100644
--- a/core/src/components/button/test/basic/index.html
+++ b/core/src/components/button/test/basic/index.html
@@ -84,13 +84,13 @@