Skip to content

Comments

feat(range): add classes and expose parts to allow individual styling of dual knobs#30941

Open
brandyscarney wants to merge 26 commits intofeature-8.8from
FW-6582
Open

feat(range): add classes and expose parts to allow individual styling of dual knobs#30941
brandyscarney wants to merge 26 commits intofeature-8.8from
FW-6582

Conversation

@brandyscarney
Copy link
Member

@brandyscarney brandyscarney commented Jan 29, 2026

Issue number: resolves #29862


What is the current behavior?

Range exposes a single part for both knobs & pins. This makes it impossible to style the knobs/pins differently when dual knobs is enabled.

What is the new behavior?

  • Fixes a bug where the knobs would swap A & B when they cross over each other
  • Fixes the focus behavior so that dual knobs act the same as a single knob range when focusing a knob
  • Adds the following classes to the host element when dualKnobs is enabled:
    • range-dual-knobs
    • range-pressed-a when the knob with name A is pressed
    • range-pressed-b when the knob with name B is pressed
    • range-pressed-lower when the lower knob is pressed
    • range-pressed-upper when the upper knob is pressed
  • Adds parts for the following:
    • knob-handle-a - The container element for the first knob. Only available when dualKnobs is true.
    • knob-handle-b - The container element for the second knob. Only available when dualKnobs is true.
    • knob-handle-lower - The container element for the lower knob. Only available when dualKnobs is true.
    • knob-handle-upper - The container element for the upper knob. Only available when dualKnobs is true.
    • pin-a - The counter that appears above the first knob. Only available when dualKnobs is true.
    • pin-b - The counter that appears above the second knob. Only available when dualKnobs is true.
    • pin-lower - The counter that appears above the lower knob. Only available when dualKnobs is true.
    • pin-upper - The counter that appears above the upper knob. Only available when dualKnobs is true.
    • knob-a - The visual knob element for the first knob. Only available when dualKnobs is true.
    • knob-b - The visual knob element for the second knob. Only available when dualKnobs is true.
    • knob-lower - The visual knob element for the lower knob. Only available when dualKnobs is true.
    • knob-upper - The visual knob element for the upper knob. Only available when dualKnobs is true.
    • pressed - Added to the knob-handle, knob, and pin that is currently being pressed to drag. Only one set has this part at a time.
    • focused - Added to the knob-handle, knob, and pin that currently has focus. Only one set has this part at a time.
    • hover - Added to the knob-handle, knob, and pin when the knob has hover. Only one set has this part at a time.
    • activated - Added to the knob-handle, knob, and pin when the knob is activated. Only one set has this part at a time.
  • Adds e2e tests for the following:
    • customizing label part
    • customizing bar parts
    • customizing pin parts
    • customizing tick parts
    • customizing knob parts
    • customizing dual knob a & b parts
    • customizing dual knob lower & upper parts
    • verifies that a & b parts stay on the original elements but lower & upper parts swap when the values swap
  • Adds spec tests for the following:
    • css classes
      • value state classes
      • boolean property classes
      • pressed state classes
    • shadow parts
      • static shadow parts
        • verifies the shadow parts exist based on the existence of certain range properties
      • state shadow parts
        • verifies the shadow parts exist based on the state of the range knob (pressed, focused, activated, hover)

Does this introduce a breaking change?

  • Yes
  • No

Other information

Dev build: 8.7.17-dev.11771865171.14f4c2cf

@vercel
Copy link

vercel bot commented Jan 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ionic-framework Ready Ready Preview, Comment Feb 24, 2026 4:49pm

Request Review

@github-actions github-actions bot added the package: core @ionic/core package label Jan 29, 2026
Copy link
Member Author

Choose a reason for hiding this comment

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

This change is required otherwise it won't match knob when it has knob knob-a.

Copy link
Member Author

Choose a reason for hiding this comment

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

I renamed the classes assigned to knob-handle from range-knob-a to range-knob-handle-a to match what they are actually applied to.

configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('range: customization'), () => {
test('should be customizable', async ({ page }) => {
await page.goto(`/src/components/range/test/custom`, config);
Copy link
Member Author

Choose a reason for hiding this comment

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

I removed the screenshots here in favor of checking that the styles are applied to the right element when the part is styled.

@brandyscarney brandyscarney changed the title feat(range): add class and expose parts for dual knobs for easier styling feat(range): add class and expose parts for dual knobs for custom styling Jan 30, 2026
@brandyscarney brandyscarney changed the title feat(range): add class and expose parts for dual knobs for custom styling feat(range): add classes and expose parts for dual knobs for custom styling Feb 20, 2026
Comment on lines +53 to +56
* @part activated - Added to the knob-handle, knob, and pin when the knob is activated (has the `ion-activated` class). Only one set has this part at a time when `dualKnobs` is `true`.
* @part focused - Added to the knob-handle, knob, and pin that currently has focus. Only one set has this part at a time when `dualKnobs` is `true`.
* @part hover - Added to the knob-handle, knob, and pin when the knob has hover. Only one set has this part at a time when `dualKnobs` is `true`.
* @part pressed - Added to the knob-handle, knob, and pin that is currently being pressed to drag. Only one set has this part at a time when `dualKnobs` is `true`.
Copy link
Member Author

@brandyscarney brandyscarney Feb 24, 2026

Choose a reason for hiding this comment

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

In other components we add this as the part it works with like this:

* @part wheel-item active - The currently selected wheel-item.
* @part time-button active - The time picker button when the picker is open.

but it seemed like a lot to add all of these:

Details
/**
 * @part knob-handle - The container element that wraps the knob and handles drag interactions.
 * @part knob-handle activated - The activated knob-handle. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-handle focused - The focused knob-handle. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-handle hover - The hovered knob-handle. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-handle pressed - The pressed knob-handle. Only one set has this part at a time when `dualKnobs` is `true`.
 * 
 * @part knob-handle-a - The container element for the first knob. Only available when `dualKnobs` is `true`.
 * @part knob-handle-a activated - The activated knob-handle-a. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-handle-a focused - The focused knob-handle-a. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-handle-a hover - The hovered knob-handle-a. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-handle-a pressed - The pressed knob-handle-a. Only one set has this part at a time when `dualKnobs` is `true`.
 * 
 * @part knob-handle-b - The container element for the second knob. Only available when `dualKnobs` is `true`.
 * @part knob-handle-b activated - The activated knob-handle-b. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-handle-b focused - The focused knob-handle-b. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-handle-b hover - The hovered knob-handle-b. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-handle-b pressed - The pressed knob-handle-b. Only one set has this part at a time when `dualKnobs` is `true`.
 * 
 * @part knob-handle-lower - The container element for the lower knob. Only available when `dualKnobs` is `true`.
 * @part knob-handle-lower activated - The activated knob-handle-lower. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-handle-lower focused - The focused knob-handle-lower. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-handle-lower hover - The hovered knob-handle-lower. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-handle-lower pressed - The pressed knob-handle-lower. Only one set has this part at a time when `dualKnobs` is `true`.
 * 
 * @part knob-handle-upper - The container element for the upper knob. Only available when `dualKnobs` is `true`.
 * @part knob-handle-upper activated - The activated knob-handle-upper. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-handle-upper focused - The focused knob-handle-upper. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-handle-upper hover - The hovered knob-handle-upper. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-handle-upper pressed - The pressed knob-handle-upper. Only one set has this part at a time when `dualKnobs` is `true`.
 * 
 * @part pin - The counter that appears above a knob.
 * @part pin activated - The activated pin. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part pin focused - The focused pin. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part pin hover - The hovered pin. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part pin pressed - The pressed pin. Only one set has this part at a time when `dualKnobs` is `true`.
 * 
 * @part pin-a - The counter that appears above the first knob. Only available when `dualKnobs` is `true`.
 * @part pin-a activated - The activated pin-a. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part pin-a focused - The focused pin-a. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part pin-a hover - The hovered pin-a. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part pin-a pressed - The pressed pin-a. Only one set has this part at a time when `dualKnobs` is `true`.
 * 
 * @part pin-b - The counter that appears above the second knob. Only available when `dualKnobs` is `true`.
 * @part pin-b activated - The activated pin-b. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part pin-b focused - The focused pin-b. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part pin-b hover - The hovered pin-b. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part pin-b pressed - The pressed pin-b. Only one set has this part at a time when `dualKnobs` is `true`.
 * 
 * @part pin-lower - The counter that appears above the lower knob. Only available when `dualKnobs` is `true`.
 * @part pin-lower activated - The activated pin-lower. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part pin-lower focused - The focused pin-lower. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part pin-lower hover - The hovered pin-lower. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part pin-lower pressed - The pressed pin-lower. Only one set has this part at a time when `dualKnobs` is `true`.
 * 
 * @part pin-upper - The counter that appears above the upper knob. Only available when `dualKnobs` is `true`.
 * @part pin-upper activated - The activated pin-upper. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part pin-upper focused - The focused pin-upper. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part pin-upper hover - The hovered pin-upper. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part pin-upper pressed - The pressed pin-upper. Only one set has this part at a time when `dualKnobs` is `true`.
 * 
 * @part knob - The visual knob element that appears on the range track.
 * @part knob activated - The activated knob. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob focused - The focused knob. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob hover - The hovered knob. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob pressed - The pressed knob. Only one set has this part at a time when `dualKnobs` is `true`.
 * 
 * @part knob-a - The visual knob element for the first knob. Only available when `dualKnobs` is `true`.
 * @part knob-a activated - The activated knob-a. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-a focused - The focused knob-a. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-a hover - The hovered knob-a. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-a pressed - The pressed knob-a. Only one set has this part at a time when `dualKnobs` is `true`.
 * 
 * @part knob-b - The visual knob element for the second knob. Only available when `dualKnobs` is `true`.
 * @part knob-b activated - The activated knob-b. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-b focused - The focused knob-b. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-b hover - The hovered knob-b. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-b pressed - The pressed knob-b. Only one set has this part at a time when `dualKnobs` is `true`.
 * 
 * @part knob-lower - The visual knob element for the lower knob. Only available when `dualKnobs` is `true`.
 * @part knob-lower activated - The activated knob-lower. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-lower focused - The focused knob-lower. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-lower hover - The hovered knob-lower. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-lower pressed - The pressed knob-lower. Only one set has this part at a time when `dualKnobs` is `true`.
 * 
 * @part knob-upper - The visual knob element for the upper knob. Only available when `dualKnobs` is `true`.
 * @part knob-upper activated - The activated knob-upper. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-upper focused - The focused knob-upper. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-upper hover - The hovered knob-upper. Only one set has this part at a time when `dualKnobs` is `true`.
 * @part knob-upper pressed - The pressed knob-upper. Only one set has this part at a time when `dualKnobs` is `true`.
 */

@brandyscarney brandyscarney changed the title feat(range): add classes and expose parts for dual knobs for custom styling feat(range): add classes and expose parts to allow individual styling of dual knobs Feb 24, 2026
@brandyscarney brandyscarney marked this pull request as ready for review February 24, 2026 17:02
@brandyscarney brandyscarney requested a review from a team as a code owner February 24, 2026 17:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

package: core @ionic/core package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant