From bdc3ad13c6dad474dff20b94ee0078a3d47793a5 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Sun, 8 Feb 2026 20:22:56 +0100 Subject: [PATCH 01/34] feat: add dropdown minWidth and maxWidth props --- .../__tests__/dropdown-fit-handler.test.ts | 65 +++++++++++++++++-- .../dropdown/dropdown-fit-handler.ts | 56 +++++++++------- src/internal/components/dropdown/index.tsx | 63 ++++++++++++------ .../components/dropdown/interfaces.ts | 31 +++++++-- 4 files changed, 163 insertions(+), 52 deletions(-) diff --git a/src/internal/components/dropdown/__tests__/dropdown-fit-handler.test.ts b/src/internal/components/dropdown/__tests__/dropdown-fit-handler.test.ts index 8b0424d197..6676ad6240 100644 --- a/src/internal/components/dropdown/__tests__/dropdown-fit-handler.test.ts +++ b/src/internal/components/dropdown/__tests__/dropdown-fit-handler.test.ts @@ -183,7 +183,7 @@ describe('getDropdownPosition', () => { }); }); - describe('with stretchBeyondTriggerWidth=true', () => { + describe('with maxWidth undefined (can stretch beyond trigger)', () => { test('can expand beyond trigger width', () => { const triggerElement = getSizedElement(100, 50, 300, 15); const dropdownElement = getSizedElement(200, 300); @@ -193,7 +193,7 @@ describe('getDropdownPosition', () => { triggerElement, dropdownElement, overflowParents: [windowSize], - stretchBeyondTriggerWidth: true, + maxWidth: undefined, }) ).toEqual({ ...defaults, @@ -210,7 +210,7 @@ describe('getDropdownPosition', () => { triggerElement, dropdownElement, overflowParents: [windowSize], - stretchBeyondTriggerWidth: true, + maxWidth: undefined, }) ).toEqual({ ...defaults, @@ -227,7 +227,7 @@ describe('getDropdownPosition', () => { triggerElement, dropdownElement, overflowParents: [windowSize], - stretchBeyondTriggerWidth: true, + maxWidth: undefined, }) ).toEqual({ ...defaults, @@ -235,4 +235,61 @@ describe('getDropdownPosition', () => { }); }); }); + + describe('with maxWidth="trigger" (constrained to trigger)', () => { + test('cannot expand beyond trigger width', () => { + const triggerElement = getSizedElement(100, 50, 300, 15); + const dropdownElement = getSizedElement(200, 300); + + expect( + getDropdownPosition({ + triggerElement, + dropdownElement, + overflowParents: [windowSize], + maxWidth: 'trigger', + }) + ).toEqual({ + ...defaults, + inlineSize: '100px', + }); + }); + }); + + describe('with minWidth=number', () => { + test('respects explicit minWidth pixel value', () => { + const triggerElement = getSizedElement(100, 50, 300, 15); + const dropdownElement = getSizedElement(50, 300); + + expect( + getDropdownPosition({ + triggerElement, + dropdownElement, + overflowParents: [windowSize], + minWidth: 80, + }) + ).toEqual({ + ...defaults, + inlineSize: '80px', + }); + }); + }); + + describe('with maxWidth=number', () => { + test('respects explicit maxWidth pixel value', () => { + const triggerElement = getSizedElement(100, 50, 300, 15); + const dropdownElement = getSizedElement(500, 300); + + expect( + getDropdownPosition({ + triggerElement, + dropdownElement, + overflowParents: [windowSize], + maxWidth: 300, + }) + ).toEqual({ + ...defaults, + inlineSize: '300px', + }); + }); + }); }); diff --git a/src/internal/components/dropdown/dropdown-fit-handler.ts b/src/internal/components/dropdown/dropdown-fit-handler.ts index ffb1af613e..fd4c617ce7 100644 --- a/src/internal/components/dropdown/dropdown-fit-handler.ts +++ b/src/internal/components/dropdown/dropdown-fit-handler.ts @@ -5,6 +5,7 @@ import { getLogicalBoundingClientRect } from '@cloudscape-design/component-toolk import { getBreakpointValue } from '../../breakpoints'; import { BoundingBox, getOverflowParentDimensions, getOverflowParents } from '../../utils/scrollable-containers'; import { LogicalDOMRect } from './dropdown-position'; +import { DropdownWidthConstraint } from './interfaces'; import styles from './styles.css.js'; @@ -162,23 +163,28 @@ const getInteriorAvailableSpace = ({ const getWidths = ({ triggerElement, dropdownElement, - desiredMinWidth, - stretchBeyondTriggerWidth = false, + minWidthConstraint, + maxWidthConstraint, }: { triggerElement: HTMLElement; dropdownElement: HTMLElement; - desiredMinWidth?: number; - stretchBeyondTriggerWidth?: boolean; + minWidthConstraint?: DropdownWidthConstraint; + maxWidthConstraint?: DropdownWidthConstraint; }) => { - // Determine the width of the trigger const { inlineSize: triggerInlineSize } = getLogicalBoundingClientRect(triggerElement); - // Minimum width is determined by either an explicit number (desiredMinWidth) or the trigger width - const minWidth = desiredMinWidth ? Math.min(triggerInlineSize, desiredMinWidth) : triggerInlineSize; - // If stretchBeyondTriggerWidth is true, the maximum width is the XS breakpoint (465px) or the trigger width (if bigger). - const maxWidth = stretchBeyondTriggerWidth ? Math.max(defaultMaxDropdownWidth, triggerInlineSize) : Number.MAX_VALUE; - // Determine the actual dropdown width, the size that it "wants" to be const { inlineSize: requiredWidth } = getLogicalBoundingClientRect(dropdownElement); - // Try to achieve the required/desired width within the given parameters + + // Calculate effective min/max widths + const minWidth = + minWidthConstraint === 'trigger' || minWidthConstraint === undefined ? triggerInlineSize : minWidthConstraint; + + const maxWidth = + maxWidthConstraint === 'trigger' + ? triggerInlineSize + : typeof maxWidthConstraint === 'number' + ? maxWidthConstraint + : Math.max(defaultMaxDropdownWidth, triggerInlineSize); + const idealWidth = Math.min(Math.max(requiredWidth, minWidth), maxWidth); return { idealWidth, minWidth, triggerInlineSize }; }; @@ -186,7 +192,8 @@ const getWidths = ({ export const hasEnoughSpaceToStretchBeyondTriggerWidth = ({ triggerElement, dropdownElement, - desiredMinWidth, + minWidthConstraint, + maxWidthConstraint, expandToViewport, stretchWidth, stretchHeight, @@ -194,7 +201,8 @@ export const hasEnoughSpaceToStretchBeyondTriggerWidth = ({ }: { triggerElement: HTMLElement; dropdownElement: HTMLElement; - desiredMinWidth?: number; + minWidthConstraint?: DropdownWidthConstraint; + maxWidthConstraint?: DropdownWidthConstraint; expandToViewport: boolean; stretchWidth: boolean; stretchHeight: boolean; @@ -209,8 +217,8 @@ export const hasEnoughSpaceToStretchBeyondTriggerWidth = ({ const { idealWidth } = getWidths({ triggerElement: triggerElement, dropdownElement, - desiredMinWidth, - stretchBeyondTriggerWidth: true, + minWidthConstraint, + maxWidthConstraint, }); const availableSpace = getAvailableSpace({ trigger: triggerElement, @@ -226,22 +234,22 @@ export const getDropdownPosition = ({ triggerElement, dropdownElement, overflowParents, - minWidth: desiredMinWidth, + minWidth: minWidthConstraint, + maxWidth: maxWidthConstraint, preferCenter = false, stretchWidth = false, stretchHeight = false, isMobile = false, - stretchBeyondTriggerWidth = false, }: { triggerElement: HTMLElement; dropdownElement: HTMLElement; overflowParents: ReadonlyArray; - minWidth?: number; + minWidth?: DropdownWidthConstraint; + maxWidth?: DropdownWidthConstraint; preferCenter?: boolean; stretchWidth?: boolean; stretchHeight?: boolean; isMobile?: boolean; - stretchBeyondTriggerWidth?: boolean; }): DropdownPosition => { // Determine the space available around the dropdown that it can grow in const availableSpace = getAvailableSpace({ @@ -254,8 +262,8 @@ export const getDropdownPosition = ({ const { idealWidth, minWidth, triggerInlineSize } = getWidths({ triggerElement, dropdownElement, - desiredMinWidth, - stretchBeyondTriggerWidth, + minWidthConstraint, + maxWidthConstraint, }); let dropInlineStart: boolean; @@ -360,8 +368,8 @@ export const calculatePosition = ( stretchWidth: boolean, stretchHeight: boolean, isMobile: boolean, - minWidth?: number, - stretchBeyondTriggerWidth?: boolean + minWidth?: DropdownWidthConstraint, + maxWidth?: DropdownWidthConstraint ): [DropdownPosition, LogicalDOMRect] => { // cleaning previously assigned values, // so that they are not reused in case of screen resize and similar events @@ -388,11 +396,11 @@ export const calculatePosition = ( dropdownElement, overflowParents, minWidth, + maxWidth, preferCenter, stretchWidth, stretchHeight, isMobile, - stretchBeyondTriggerWidth, }); const triggerBox = getLogicalBoundingClientRect(triggerElement); return [position, triggerBox]; diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index 95beece345..337a33b17e 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -71,7 +71,8 @@ interface TransitionContentProps { dropdownRef: React.RefObject; verticalContainerRef: React.RefObject; expandToViewport?: boolean; - stretchBeyondTriggerWidth?: boolean; + canStretchBeyondTrigger?: boolean; + useDefaultMaxWidth?: boolean; header?: React.ReactNode; content?: React.ReactNode; footer?: React.ReactNode; @@ -94,7 +95,8 @@ const TransitionContent = ({ dropdownRef, verticalContainerRef, expandToViewport, - stretchBeyondTriggerWidth, + canStretchBeyondTrigger, + useDefaultMaxWidth, header, content, footer, @@ -116,7 +118,7 @@ const TransitionContent = ({ [styles.interior]: interior, [styles.refresh]: isRefresh, [styles['use-portal']]: expandToViewport && !interior, - [styles['stretch-beyond-trigger-width']]: stretchBeyondTriggerWidth, + [styles['stretch-beyond-trigger-width']]: canStretchBeyondTrigger, })} ref={contentRef} id={id} @@ -126,9 +128,7 @@ const TransitionContent = ({ data-open={open} data-animating={state !== 'exited'} aria-hidden={!open} - style={ - stretchBeyondTriggerWidth ? { [customCssProps.dropdownDefaultMaxWidth]: `${defaultMaxDropdownWidth}px` } : {} - } + style={useDefaultMaxWidth ? { [customCssProps.dropdownDefaultMaxWidth]: `${defaultMaxDropdownWidth}px` } : {}} onMouseDown={onMouseDown} >
{ const classNameToRemove = styles['stretch-beyond-trigger-width']; + // Only applies when maxWidth is not set to 'trigger' (meaning it can grow) + const canStretchBeyond = maxWidth !== 'trigger'; if ( open && - stretchBeyondTriggerWidth && + canStretchBeyond && dropdownRef.current && triggerRef.current && dropdownRef.current.classList.contains(classNameToRemove) && !hasEnoughSpaceToStretchBeyondTriggerWidth({ triggerElement: triggerRef.current, dropdownElement: dropdownRef.current, - desiredMinWidth: minWidth, + minWidthConstraint: minWidth, + maxWidthConstraint: maxWidth, expandToViewport, stretchWidth, stretchHeight, @@ -312,10 +329,10 @@ const Dropdown = ({ useLayoutEffect(() => { const onDropdownOpen = () => { if (open && dropdownRef.current && triggerRef.current && verticalContainerRef.current) { - // calculate scroll width only for dropdowns that has a scrollbar and ignore it for date picker components if (scrollable) { dropdownRef.current.classList.add(styles.nowrap); } + setDropdownPosition( ...calculatePosition( dropdownRef.current, @@ -328,11 +345,12 @@ const Dropdown = ({ stretchHeight, isMobile, minWidth, - stretchBeyondTriggerWidth + maxWidth ), dropdownRef.current, verticalContainerRef.current ); + if (scrollable) { dropdownRef.current.classList.remove(styles.nowrap); } @@ -406,6 +424,10 @@ const Dropdown = ({ const referrerId = useUniqueId(); + // Don't apply stretch-beyond-trigger-width class when stretchWidth is true + const canStretchBeyondTrigger = maxWidth !== 'trigger' && !stretchWidth; + const useDefaultMaxWidth = maxWidth === undefined && !stretchWidth; + return (
Date: Sun, 8 Feb 2026 22:45:01 +0100 Subject: [PATCH 02/34] refactor: change default value for minWidth to undefined --- .../month-calendar-permutations.page.tsx | 3 +-- .../year-calendar-permutations.page.tsx | 3 +-- src/date-range-picker/index.tsx | 3 +-- .../dropdown/dropdown-fit-handler.ts | 5 ++-- src/internal/components/dropdown/index.tsx | 27 ++++++++++--------- .../components/dropdown/interfaces.ts | 6 ++--- 6 files changed, 22 insertions(+), 25 deletions(-) diff --git a/pages/date-range-picker/month-calendar-permutations.page.tsx b/pages/date-range-picker/month-calendar-permutations.page.tsx index 2bafba648a..e4a874b24c 100644 --- a/pages/date-range-picker/month-calendar-permutations.page.tsx +++ b/pages/date-range-picker/month-calendar-permutations.page.tsx @@ -94,9 +94,8 @@ export default function DateRangePickerCalendarPage() { return (
{}} onMouseDown={() => {}} diff --git a/pages/date-range-picker/year-calendar-permutations.page.tsx b/pages/date-range-picker/year-calendar-permutations.page.tsx index 4e53aee23e..ea3e6a9923 100644 --- a/pages/date-range-picker/year-calendar-permutations.page.tsx +++ b/pages/date-range-picker/year-calendar-permutations.page.tsx @@ -74,9 +74,8 @@ export default function DateRangePickerCalendarPage() { return (
{}} onMouseDown={() => {}} diff --git a/src/date-range-picker/index.tsx b/src/date-range-picker/index.tsx index 0ac402e1c7..dd66c3a3d1 100644 --- a/src/date-range-picker/index.tsx +++ b/src/date-range-picker/index.tsx @@ -312,12 +312,11 @@ const DateRangePicker = React.forwardRef( onKeyDown={onWrapperKeyDownHandler} > closeDropdown()} trigger={trigger} - stretchToTriggerWidth={false} expandToViewport={expandToViewport} dropdownId={dropdownId} content={ diff --git a/src/internal/components/dropdown/dropdown-fit-handler.ts b/src/internal/components/dropdown/dropdown-fit-handler.ts index fd4c617ce7..5aa3161a91 100644 --- a/src/internal/components/dropdown/dropdown-fit-handler.ts +++ b/src/internal/components/dropdown/dropdown-fit-handler.ts @@ -175,15 +175,14 @@ const getWidths = ({ const { inlineSize: requiredWidth } = getLogicalBoundingClientRect(dropdownElement); // Calculate effective min/max widths - const minWidth = - minWidthConstraint === 'trigger' || minWidthConstraint === undefined ? triggerInlineSize : minWidthConstraint; + const minWidth = minWidthConstraint === 'trigger' ? triggerInlineSize : (minWidthConstraint ?? 0); const maxWidth = maxWidthConstraint === 'trigger' ? triggerInlineSize : typeof maxWidthConstraint === 'number' ? maxWidthConstraint - : Math.max(defaultMaxDropdownWidth, triggerInlineSize); + : Number.MAX_VALUE; const idealWidth = Math.min(Math.max(requiredWidth, minWidth), maxWidth); return { idealWidth, minWidth, triggerInlineSize }; diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index 337a33b17e..64bc2f65df 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -162,7 +162,7 @@ const Dropdown = ({ stretchTriggerHeight = false, stretchWidth = true, stretchHeight = false, - minWidth = 'trigger', + minWidth, maxWidth, // eslint-disable-next-line @typescript-eslint/no-unused-vars stretchToTriggerWidth, @@ -214,15 +214,17 @@ const Dropdown = ({ // When stretchWidth is true and not using portal, occupy entire width target.classList.add(styles['occupy-entire-width']); } else { - // Only set explicit inline-size when using 'trigger' constraints (calculated in JS) - // When using numeric constraints, CSS min/max handle sizing automatically - const usesCSSConstraints = typeof minWidth === 'number' || typeof maxWidth === 'number'; - if (usesCSSConstraints) { + // Determine width setting strategy + const hasNumericConstraints = typeof minWidth === 'number' || typeof maxWidth === 'number'; + // const hasTriggerConstraints = minWidth === 'trigger' || maxWidth === 'trigger'; + + if (hasNumericConstraints) { + // Numeric constraints: use CSS min/max target.style.inlineSize = ''; target.style.minInlineSize = typeof minWidth === 'number' ? `${minWidth}px` : ''; target.style.maxInlineSize = typeof maxWidth === 'number' ? `${maxWidth}px` : ''; } else { - // Use JS-calculated width for 'trigger' constraints + // No numeric constraints: use JS-calculated width (handles both undefined and 'trigger') target.style.inlineSize = position.inlineSize; target.style.minInlineSize = ''; target.style.maxInlineSize = ''; @@ -301,11 +303,10 @@ const Dropdown = ({ // If not, remove the class that allows stretching beyond trigger width const fixStretching = () => { const classNameToRemove = styles['stretch-beyond-trigger-width']; - // Only applies when maxWidth is not set to 'trigger' (meaning it can grow) - const canStretchBeyond = maxWidth !== 'trigger'; if ( open && - canStretchBeyond && + maxWidth === undefined && + !stretchWidth && dropdownRef.current && triggerRef.current && dropdownRef.current.classList.contains(classNameToRemove) && @@ -424,9 +425,11 @@ const Dropdown = ({ const referrerId = useUniqueId(); - // Don't apply stretch-beyond-trigger-width class when stretchWidth is true - const canStretchBeyondTrigger = maxWidth !== 'trigger' && !stretchWidth; - const useDefaultMaxWidth = maxWidth === undefined && !stretchWidth; + // Only apply stretch-beyond-trigger-width when we have at least one constraint defined + // This prevents the 100% fallback from affecting natural content sizing + const hasAnyConstraint = minWidth !== undefined || maxWidth !== undefined; + const canStretchBeyondTrigger = hasAnyConstraint && maxWidth !== 'trigger' && !stretchWidth; + const useDefaultMaxWidth = maxWidth === undefined && minWidth !== undefined && !stretchWidth; return (
Date: Mon, 9 Feb 2026 11:17:30 +0100 Subject: [PATCH 03/34] fix: dont stretch content when width provided --- src/button-dropdown/internal.tsx | 2 +- src/date-range-picker/index.tsx | 1 - src/internal/components/dropdown/index.tsx | 15 ++++++++------- src/internal/components/dropdown/interfaces.ts | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/button-dropdown/internal.tsx b/src/button-dropdown/internal.tsx index 486a6a7707..a9895978a5 100644 --- a/src/button-dropdown/internal.tsx +++ b/src/button-dropdown/internal.tsx @@ -359,7 +359,7 @@ const InternalButtonDropdown = React.forwardRef( > closeDropdown()} diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index 64bc2f65df..05cf9e40d7 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -210,8 +210,10 @@ const Dropdown = ({ verticalContainer.style.maxBlockSize = position.blockSize; } - if (entireWidth && !expandToViewport) { - // When stretchWidth is true and not using portal, occupy entire width + // Only apply occupy-entire-width when stretchWidth is true AND no width constraints are set + // If width constraints exist, they should take precedence + const hasWidthConstraints = minWidth !== undefined || maxWidth !== undefined; + if (entireWidth && !expandToViewport && !hasWidthConstraints) { target.classList.add(styles['occupy-entire-width']); } else { // Determine width setting strategy @@ -425,11 +427,10 @@ const Dropdown = ({ const referrerId = useUniqueId(); - // Only apply stretch-beyond-trigger-width when we have at least one constraint defined - // This prevents the 100% fallback from affecting natural content sizing - const hasAnyConstraint = minWidth !== undefined || maxWidth !== undefined; - const canStretchBeyondTrigger = hasAnyConstraint && maxWidth !== 'trigger' && !stretchWidth; - const useDefaultMaxWidth = maxWidth === undefined && minWidth !== undefined && !stretchWidth; + // The 465px default should only apply when using the old default behavior (trigger constraints) + // Not when user explicitly sets their own constraints or wants natural sizing + const canStretchBeyondTrigger = maxWidth !== 'trigger' && !stretchWidth; + const useDefaultMaxWidth = false; // Don't apply 465px default with new API return (
Date: Mon, 9 Feb 2026 19:37:07 +0100 Subject: [PATCH 04/34] refactor: replace stretchWidth prop with minWidth and maxWidth Also moves maxWidth behavior if expandToViewport=true to the respective components, as this is a "feature" we want to keep for backward compatibility but it's not intended to be a part of the dropdown component. --- build-tools/utils/custom-css-properties.js | 1 + pages/calendar/simple.page.tsx | 3 +- .../month-calendar-permutations.page.tsx | 1 - .../year-calendar-permutations.page.tsx | 1 - pages/dropdown/interior-fitting.page.tsx | 16 +-- .../dropdown/interior-stretch-height.page.tsx | 7 +- .../dropdown/interior-with-wrapping.page.tsx | 8 +- pages/dropdown/min-width.page.tsx | 4 +- pages/dropdown/positioning.page.tsx | 10 +- pages/dropdown/prefer-center.page.tsx | 6 +- .../expandable-category-element.tsx | 1 - src/date-picker/index.tsx | 3 +- .../components/autosuggest-input/index.tsx | 6 +- .../dropdown/dropdown-fit-handler.ts | 30 +++-- src/internal/components/dropdown/index.tsx | 108 ++++++++++-------- .../components/dropdown/interfaces.ts | 8 +- src/internal/components/dropdown/styles.scss | 5 +- src/multiselect/internal.tsx | 4 +- src/select/internal.tsx | 4 +- 19 files changed, 119 insertions(+), 107 deletions(-) diff --git a/build-tools/utils/custom-css-properties.js b/build-tools/utils/custom-css-properties.js index 5f4048efa2..79ccc7fd66 100644 --- a/build-tools/utils/custom-css-properties.js +++ b/build-tools/utils/custom-css-properties.js @@ -50,6 +50,7 @@ const customCssPropertiesList = [ 'stackedNotificationsDefaultBottomMargin', // Dropdown Custom Properties 'dropdownDefaultMaxWidth', + 'dropdownDefaultMinWidth', // Spinner Custom Properties 'spinnerRotatorFrom', 'spinnerRotatorTo', diff --git a/pages/calendar/simple.page.tsx b/pages/calendar/simple.page.tsx index d82d64299a..6d031bc545 100644 --- a/pages/calendar/simple.page.tsx +++ b/pages/calendar/simple.page.tsx @@ -12,7 +12,8 @@ export default function CalendarPage() {

Calendar page for a11y tests

{}} diff --git a/pages/date-range-picker/month-calendar-permutations.page.tsx b/pages/date-range-picker/month-calendar-permutations.page.tsx index e4a874b24c..2bfd656afe 100644 --- a/pages/date-range-picker/month-calendar-permutations.page.tsx +++ b/pages/date-range-picker/month-calendar-permutations.page.tsx @@ -94,7 +94,6 @@ export default function DateRangePickerCalendarPage() { return (
{}} diff --git a/pages/date-range-picker/year-calendar-permutations.page.tsx b/pages/date-range-picker/year-calendar-permutations.page.tsx index ea3e6a9923..cfe903794b 100644 --- a/pages/date-range-picker/year-calendar-permutations.page.tsx +++ b/pages/date-range-picker/year-calendar-permutations.page.tsx @@ -74,7 +74,6 @@ export default function DateRangePickerCalendarPage() { return (
{}} diff --git a/pages/dropdown/interior-fitting.page.tsx b/pages/dropdown/interior-fitting.page.tsx index 9d46e16993..87cc078a62 100644 --- a/pages/dropdown/interior-fitting.page.tsx +++ b/pages/dropdown/interior-fitting.page.tsx @@ -33,7 +33,7 @@ export default function DropdownScenario() {
setOpenParent1(!openParent1)}> Scenario 1 @@ -46,7 +46,7 @@ export default function DropdownScenario() {
  • setOpenChild1(!openChild1)}> Expandable trigger @@ -65,7 +65,7 @@ export default function DropdownScenario() {
    setOpenParent2(!openParent2)}> Scenario 2 @@ -78,7 +78,7 @@ export default function DropdownScenario() {
  • setOpenChild2(!openChild2)}> Expandable trigger @@ -97,7 +97,7 @@ export default function DropdownScenario() {
    setOpenParent3(!openParent3)}> Scenario 3 @@ -110,7 +110,7 @@ export default function DropdownScenario() {
  • setOpenChild3(!openChild3)}> Expandable trigger @@ -133,7 +133,7 @@ export default function DropdownScenario() { style={{ insetInlineStart: '270px', insetBlockStart: '170px' }} > setOpenParent4(!openParent4)}> Scenario 4 @@ -146,7 +146,7 @@ export default function DropdownScenario() {
  • setOpenChild4(!openChild4)}> Expandable trigger diff --git a/pages/dropdown/interior-stretch-height.page.tsx b/pages/dropdown/interior-stretch-height.page.tsx index d415635ec2..ed5ef7aea9 100644 --- a/pages/dropdown/interior-stretch-height.page.tsx +++ b/pages/dropdown/interior-stretch-height.page.tsx @@ -33,7 +33,7 @@ export default function DropdownScenario() { style={{ insetInlineStart: '100px', blockSize: '800px' }} > setOpenParent1(!openParent1)}> @@ -52,7 +52,7 @@ export default function DropdownScenario() { >
  • setOpenChild5(!openChild5)}> Expandable trigger @@ -66,7 +66,7 @@ export default function DropdownScenario() { style={{ insetBlockStart: '170px', insetInlineStart: '190px' }} > setOpenParent6(!openParent6)}> Scenario 6 @@ -79,7 +79,7 @@ export default function DropdownScenario() {
  • setOpenChild6(!openChild6)}> Expandable trigger diff --git a/pages/dropdown/min-width.page.tsx b/pages/dropdown/min-width.page.tsx index e389f08488..ded52c01b4 100644 --- a/pages/dropdown/min-width.page.tsx +++ b/pages/dropdown/min-width.page.tsx @@ -20,8 +20,7 @@ export default function DropdownScenario() { Dropdown should have the width equal to the trigger width, if it is is larger than the minWidth
  • - stretchWidth property takes precedence over minWidth. The dropdown grows greedily, - if stretchWidth is set to true (the default value) + Use minWidth=trigger and maxWidth=trigger to match trigger width exactly.
  • @@ -38,7 +37,6 @@ export default function DropdownScenario() { open={open} onDropdownClose={() => setOpen(false)} minWidth={800} - stretchWidth={false} content={} />
    diff --git a/pages/dropdown/positioning.page.tsx b/pages/dropdown/positioning.page.tsx index 642e360920..f4b28544b7 100644 --- a/pages/dropdown/positioning.page.tsx +++ b/pages/dropdown/positioning.page.tsx @@ -36,7 +36,7 @@ export default function DropdownScenario() {
    setOpen1(!open1)}> Scenario 1 @@ -51,7 +51,7 @@ export default function DropdownScenario() {
    setOpen2(!open2)}> Scenario 2 @@ -66,7 +66,7 @@ export default function DropdownScenario() {
    setOpen3(!open3)}> Scenario 3 @@ -81,7 +81,7 @@ export default function DropdownScenario() {
    setOpen4(!open4)}> Scenario 4 @@ -100,7 +100,7 @@ export default function DropdownScenario() { style={{ insetInlineStart: '80px', insetBlockStart: '170px' }} > setOpen5(!open5)}> Scenario 5 diff --git a/pages/dropdown/prefer-center.page.tsx b/pages/dropdown/prefer-center.page.tsx index 6b22030edf..589c18f40a 100644 --- a/pages/dropdown/prefer-center.page.tsx +++ b/pages/dropdown/prefer-center.page.tsx @@ -27,7 +27,7 @@ export default function DropdownScenario() {
    setOpen1(!open1)}> @@ -43,7 +43,7 @@ export default function DropdownScenario() {
    setOpen2(!open2)}> @@ -59,7 +59,7 @@ export default function DropdownScenario() {
    setOpen3(!open3)}> diff --git a/src/button-dropdown/category-elements/expandable-category-element.tsx b/src/button-dropdown/category-elements/expandable-category-element.tsx index bb80eccf5e..cdf4038102 100644 --- a/src/button-dropdown/category-elements/expandable-category-element.tsx +++ b/src/button-dropdown/category-elements/expandable-category-element.tsx @@ -140,7 +140,6 @@ const ExpandableCategoryElement = ({ content = ( { return parents.shift(); }; -// By default, most dropdowns should expand their content as necessary, but to a maximum of 465px (the XXS breakpoint). -// This value was determined by UX but may be subject to change in the future, depending on the feedback. -export const defaultMaxDropdownWidth = getBreakpointValue('xxs'); - const getAvailableSpace = ({ trigger, overflowParents, @@ -175,26 +170,31 @@ const getWidths = ({ const { inlineSize: requiredWidth } = getLogicalBoundingClientRect(dropdownElement); // Calculate effective min/max widths - const minWidth = minWidthConstraint === 'trigger' ? triggerInlineSize : (minWidthConstraint ?? 0); + // undefined = no min constraint (0) + const minWidth = + minWidthConstraint === 'trigger' + ? triggerInlineSize + : typeof minWidthConstraint === 'number' + ? minWidthConstraint + : 0; const maxWidth = maxWidthConstraint === 'trigger' ? triggerInlineSize : typeof maxWidthConstraint === 'number' ? maxWidthConstraint - : Number.MAX_VALUE; + : Number.MAX_VALUE; // undefined = no max constraint const idealWidth = Math.min(Math.max(requiredWidth, minWidth), maxWidth); return { idealWidth, minWidth, triggerInlineSize }; }; -export const hasEnoughSpaceToStretchBeyondTriggerWidth = ({ +export const hasEnoughSpaceForFlexibleWidth = ({ triggerElement, dropdownElement, minWidthConstraint, maxWidthConstraint, expandToViewport, - stretchWidth, stretchHeight, isMobile, }: { @@ -203,7 +203,6 @@ export const hasEnoughSpaceToStretchBeyondTriggerWidth = ({ minWidthConstraint?: DropdownWidthConstraint; maxWidthConstraint?: DropdownWidthConstraint; expandToViewport: boolean; - stretchWidth: boolean; stretchHeight: boolean; isMobile: boolean; }) => { @@ -222,7 +221,6 @@ export const hasEnoughSpaceToStretchBeyondTriggerWidth = ({ const availableSpace = getAvailableSpace({ trigger: triggerElement, overflowParents, - stretchWidth, stretchHeight, isMobile, }); @@ -236,7 +234,7 @@ export const getDropdownPosition = ({ minWidth: minWidthConstraint, maxWidth: maxWidthConstraint, preferCenter = false, - stretchWidth = false, + matchTriggerWidth = false, stretchHeight = false, isMobile = false, }: { @@ -246,7 +244,7 @@ export const getDropdownPosition = ({ minWidth?: DropdownWidthConstraint; maxWidth?: DropdownWidthConstraint; preferCenter?: boolean; - stretchWidth?: boolean; + matchTriggerWidth?: boolean; stretchHeight?: boolean; isMobile?: boolean; }): DropdownPosition => { @@ -254,7 +252,7 @@ export const getDropdownPosition = ({ const availableSpace = getAvailableSpace({ trigger: triggerElement, overflowParents, - stretchWidth, + stretchWidth: matchTriggerWidth, stretchHeight, isMobile, }); @@ -364,7 +362,7 @@ export const calculatePosition = ( interior: boolean, expandToViewport: boolean, preferCenter: boolean, - stretchWidth: boolean, + matchTriggerWidth: boolean, stretchHeight: boolean, isMobile: boolean, minWidth?: DropdownWidthConstraint, @@ -397,7 +395,7 @@ export const calculatePosition = ( minWidth, maxWidth, preferCenter, - stretchWidth, + matchTriggerWidth, stretchHeight, isMobile, }); diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index 05cf9e40d7..896cb39f78 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -19,9 +19,8 @@ import { Transition, TransitionStatus } from '../transition'; import { DropdownContextProvider, DropdownContextProviderProps } from './context'; import { calculatePosition, - defaultMaxDropdownWidth, DropdownPosition, - hasEnoughSpaceToStretchBeyondTriggerWidth, + hasEnoughSpaceForFlexibleWidth, InteriorDropdownPosition, } from './dropdown-fit-handler'; import { applyDropdownPositionRelativeToViewport, LogicalDOMRect } from './dropdown-position'; @@ -65,14 +64,15 @@ interface TransitionContentProps { state: TransitionStatus; transitionRef: React.MutableRefObject; dropdownClasses: string; - stretchWidth: boolean; + matchTriggerWidth: boolean; interior: boolean; isRefresh: boolean; dropdownRef: React.RefObject; verticalContainerRef: React.RefObject; expandToViewport?: boolean; - canStretchBeyondTrigger?: boolean; - useDefaultMaxWidth?: boolean; + useFlexibleWidth?: boolean; + minWidth?: string; + maxWidth?: string; header?: React.ReactNode; content?: React.ReactNode; footer?: React.ReactNode; @@ -89,14 +89,15 @@ const TransitionContent = ({ state, transitionRef, dropdownClasses, - stretchWidth, + matchTriggerWidth, interior, isRefresh, dropdownRef, verticalContainerRef, expandToViewport, - canStretchBeyondTrigger, - useDefaultMaxWidth, + useFlexibleWidth, + minWidth, + maxWidth, header, content, footer, @@ -109,16 +110,23 @@ const TransitionContent = ({ ariaDescribedby, }: TransitionContentProps) => { const contentRef = useMergeRefs(dropdownRef, transitionRef); + const dropdownStyles: Record = {}; + if (minWidth) { + dropdownStyles[customCssProps.dropdownDefaultMinWidth] = minWidth; + } + if (maxWidth) { + dropdownStyles[customCssProps.dropdownDefaultMaxWidth] = maxWidth; + } return (
    { - const entireWidth = !interior && stretchWidth; - if (!stretchWidth) { + if (!matchTriggerWidth) { // 1px offset for dropdowns where the dropdown itself needs a border, rather than on the items verticalContainer.style.maxBlockSize = `${parseInt(position.blockSize) + 1}px`; } else { verticalContainer.style.maxBlockSize = position.blockSize; } - // Only apply occupy-entire-width when stretchWidth is true AND no width constraints are set - // If width constraints exist, they should take precedence - const hasWidthConstraints = minWidth !== undefined || maxWidth !== undefined; - if (entireWidth && !expandToViewport && !hasWidthConstraints) { + // Only apply occupy-entire-width when matching trigger width exactly and not in portal mode + if (!interior && matchTriggerWidth && !expandToViewport) { target.classList.add(styles['occupy-entire-width']); + } else if (!target.classList.contains(styles['use-flexible-width'])) { + // Only set inline-size if not using CSS variables via use-flexible-width + target.style.inlineSize = position.inlineSize; + target.style.minInlineSize = ''; + target.style.maxInlineSize = ''; } else { - // Determine width setting strategy - const hasNumericConstraints = typeof minWidth === 'number' || typeof maxWidth === 'number'; - // const hasTriggerConstraints = minWidth === 'trigger' || maxWidth === 'trigger'; - - if (hasNumericConstraints) { - // Numeric constraints: use CSS min/max - target.style.inlineSize = ''; - target.style.minInlineSize = typeof minWidth === 'number' ? `${minWidth}px` : ''; - target.style.maxInlineSize = typeof maxWidth === 'number' ? `${maxWidth}px` : ''; - } else { - // No numeric constraints: use JS-calculated width (handles both undefined and 'trigger') - target.style.inlineSize = position.inlineSize; - target.style.minInlineSize = ''; - target.style.maxInlineSize = ''; + // When using use-flexible-width with minWidth='trigger', set min-inline-size + // to ensure the dropdown is at least as wide as the trigger (needed for virtualScroll) + if (minWidth === 'trigger') { + target.style.minInlineSize = `${triggerBox.inlineSize}px`; } } @@ -302,23 +305,22 @@ const Dropdown = ({ }; // Check if the dropdown has enough space to fit with its desired width constraints - // If not, remove the class that allows stretching beyond trigger width + // If not, remove the class that allows flexible width sizing const fixStretching = () => { - const classNameToRemove = styles['stretch-beyond-trigger-width']; + const classNameToRemove = styles['use-flexible-width']; if ( open && maxWidth === undefined && - !stretchWidth && + !matchTriggerWidth && dropdownRef.current && triggerRef.current && dropdownRef.current.classList.contains(classNameToRemove) && - !hasEnoughSpaceToStretchBeyondTriggerWidth({ + !hasEnoughSpaceForFlexibleWidth({ triggerElement: triggerRef.current, dropdownElement: dropdownRef.current, minWidthConstraint: minWidth, maxWidthConstraint: maxWidth, expandToViewport, - stretchWidth, stretchHeight, isMobile, }) @@ -344,7 +346,7 @@ const Dropdown = ({ interior, expandToViewport, preferCenter, - stretchWidth, + matchTriggerWidth, stretchHeight, isMobile, minWidth, @@ -377,7 +379,7 @@ const Dropdown = ({ } // See AWSUI-13040 // eslint-disable-next-line react-hooks/exhaustive-deps - }, [open, dropdownRef, triggerRef, verticalContainerRef, interior, stretchWidth, isMobile, contentKey]); + }, [open, dropdownRef, triggerRef, verticalContainerRef, interior, matchTriggerWidth, isMobile, contentKey]); // subscribe to outside click useEffect(() => { @@ -427,10 +429,21 @@ const Dropdown = ({ const referrerId = useUniqueId(); - // The 465px default should only apply when using the old default behavior (trigger constraints) - // Not when user explicitly sets their own constraints or wants natural sizing - const canStretchBeyondTrigger = maxWidth !== 'trigger' && !stretchWidth; - const useDefaultMaxWidth = false; // Don't apply 465px default with new API + // Use flexible width sizing when not constrained to trigger width + const useFlexibleWidth = maxWidth !== 'trigger' && !matchTriggerWidth; + + // Compute CSS variable values for min/max width + // These will be used by the use-flexible-width CSS class + const getMinWidthCssValue = (): string | undefined => { + return typeof minWidth === 'number' ? `${minWidth}px` : undefined; + }; + + const getMaxWidthCssValue = (): string | undefined => { + if (typeof maxWidth === 'number') { + return `${maxWidth}px`; + } + return undefined; + }; return (
    .dropdown-content-wrapper { margin-block-start: -1px; diff --git a/src/multiselect/internal.tsx b/src/multiselect/internal.tsx index 0c6f47d225..0803a8a7a2 100644 --- a/src/multiselect/internal.tsx +++ b/src/multiselect/internal.tsx @@ -7,6 +7,7 @@ import { useUniqueId } from '@cloudscape-design/component-toolkit/internal'; import { useInternalI18n } from '../i18n/context'; import { getBaseProps } from '../internal/base-component'; +import { getBreakpointValue } from '../internal/breakpoints'; import Dropdown from '../internal/components/dropdown'; import DropdownFooter from '../internal/components/dropdown-footer/index.js'; import ScreenreaderOnly from '../internal/components/screenreader-only'; @@ -167,6 +168,8 @@ const InternalMultiselect = React.forwardRef( dropdownProps.dropdownContentRole ? (dropdownStatus.content ? footerId : undefined) : undefined } open={multiselectProps.isOpen} + minWidth="trigger" + maxWidth={expandToViewport ? getBreakpointValue('xxs') : undefined} trigger={trigger} header={filter} footer={ @@ -175,7 +178,6 @@ const InternalMultiselect = React.forwardRef( ) : null } expandToViewport={expandToViewport} - stretchBeyondTriggerWidth={true} // Forces dropdown position recalculation when new options are loaded contentKey={hasOptions.current.toString()} content={ diff --git a/src/select/internal.tsx b/src/select/internal.tsx index 2e0961e9e6..c963d17b09 100644 --- a/src/select/internal.tsx +++ b/src/select/internal.tsx @@ -7,6 +7,7 @@ import { useMergeRefs, useUniqueId, warnOnce } from '@cloudscape-design/componen import { useInternalI18n } from '../i18n/context.js'; import { getBaseProps } from '../internal/base-component'; +import { getBreakpointValue } from '../internal/breakpoints'; import Dropdown from '../internal/components/dropdown'; import DropdownFooter from '../internal/components/dropdown-footer'; import { useDropdownStatus } from '../internal/components/dropdown-status'; @@ -255,7 +256,8 @@ const InternalSelect = React.forwardRef( } open={isOpen} stretchTriggerHeight={!!__inFilteringToken} - stretchBeyondTriggerWidth={true} + minWidth="trigger" + maxWidth={expandToViewport ? getBreakpointValue('xxs') : undefined} trigger={trigger} header={filter} onMouseDown={handleMouseDown} From 959351ea570f27103cb89cca4c71e2e5122d710e Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Tue, 10 Feb 2026 10:39:37 +0100 Subject: [PATCH 05/34] fix: dont set width when dropdown is nested --- src/internal/components/dropdown/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index 896cb39f78..35546d4e36 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -126,7 +126,7 @@ const TransitionContent = ({ [styles.interior]: interior, [styles.refresh]: isRefresh, [styles['use-portal']]: expandToViewport && !interior, - [styles['use-flexible-width']]: useFlexibleWidth, + [styles['use-flexible-width']]: useFlexibleWidth && !interior, })} ref={contentRef} id={id} From eae1787d96e78e215380352dc2092deba2efa099 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Tue, 10 Feb 2026 16:00:53 +0100 Subject: [PATCH 06/34] feat: introduce max-content type --- .../components/autosuggest-input/index.tsx | 4 +-- .../dropdown/dropdown-fit-handler.ts | 10 ++++--- src/internal/components/dropdown/index.tsx | 27 +++++++++++++++---- .../components/dropdown/interfaces.ts | 4 +-- src/internal/components/dropdown/styles.scss | 6 ++--- src/multiselect/internal.tsx | 4 +-- src/select/internal.tsx | 4 +-- 7 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/internal/components/autosuggest-input/index.tsx b/src/internal/components/autosuggest-input/index.tsx index 474c219df2..2f6b70d89b 100644 --- a/src/internal/components/autosuggest-input/index.tsx +++ b/src/internal/components/autosuggest-input/index.tsx @@ -295,8 +295,8 @@ const AutosuggestInput = React.forwardRef( return (
    { - return typeof minWidth === 'number' ? `${minWidth}px` : undefined; + if (typeof minWidth === 'number') { + return `${minWidth}px`; + } + if (minWidth === 'max-content') { + return 'max-content'; + } + if (minWidth === 'trigger') { + return '100%'; + } + return undefined; }; const getMaxWidthCssValue = (): string | undefined => { if (typeof maxWidth === 'number') { return `${maxWidth}px`; } + if (maxWidth === 'max-content') { + return 'max-content'; + } + // When maxWidth is undefined, allow dropdown to grow to content size + // The CSS fallback of 100% would constrain it to trigger width + if (maxWidth === undefined) { + return 'none'; + } return undefined; }; diff --git a/src/internal/components/dropdown/interfaces.ts b/src/internal/components/dropdown/interfaces.ts index 324dca0fd3..46107fe332 100644 --- a/src/internal/components/dropdown/interfaces.ts +++ b/src/internal/components/dropdown/interfaces.ts @@ -7,9 +7,9 @@ import { NonCancelableEventHandler } from '../../events'; export type OptionsFilteringType = 'none' | 'auto' | 'manual'; /** - * Width constraint that can be a pixel value or reference the trigger width + * Width constraint that can be a pixel value, reference the trigger width, or fit content */ -export type DropdownWidthConstraint = number | 'trigger'; +export type DropdownWidthConstraint = number | 'trigger' | 'max-content'; export interface OptionsLoadItemsDetail { filteringText: string; diff --git a/src/internal/components/dropdown/styles.scss b/src/internal/components/dropdown/styles.scss index efed20ae23..f0a7a5b059 100644 --- a/src/internal/components/dropdown/styles.scss +++ b/src/internal/components/dropdown/styles.scss @@ -75,8 +75,8 @@ } &.use-flexible-width { inline-size: max-content; - min-inline-size: var(#{custom-props.$dropdownDefaultMinWidth}, 0); max-inline-size: var(#{custom-props.$dropdownDefaultMaxWidth}, none); + min-inline-size: var(#{custom-props.$dropdownDefaultMinWidth}, auto); } &.interior > .dropdown-content-wrapper { margin-block-start: -1px; @@ -94,10 +94,10 @@ display: block; &:not(.interior).refresh[data-animating='true'] { - transform: translateY(4px); + transform: translateY(5px); &.dropdown-drop-up { - transform: translateY(-4px); + transform: translateY(-5px); } } &.nowrap { diff --git a/src/multiselect/internal.tsx b/src/multiselect/internal.tsx index 0803a8a7a2..94ef36c125 100644 --- a/src/multiselect/internal.tsx +++ b/src/multiselect/internal.tsx @@ -168,8 +168,8 @@ const InternalMultiselect = React.forwardRef( dropdownProps.dropdownContentRole ? (dropdownStatus.content ? footerId : undefined) : undefined } open={multiselectProps.isOpen} - minWidth="trigger" - maxWidth={expandToViewport ? getBreakpointValue('xxs') : undefined} + minWidth={expandToViewport ? undefined : 'trigger'} + maxWidth={getBreakpointValue('xxs')} trigger={trigger} header={filter} footer={ diff --git a/src/select/internal.tsx b/src/select/internal.tsx index c963d17b09..bba6397756 100644 --- a/src/select/internal.tsx +++ b/src/select/internal.tsx @@ -256,8 +256,8 @@ const InternalSelect = React.forwardRef( } open={isOpen} stretchTriggerHeight={!!__inFilteringToken} - minWidth="trigger" - maxWidth={expandToViewport ? getBreakpointValue('xxs') : undefined} + minWidth={expandToViewport ? undefined : 'trigger'} + maxWidth={getBreakpointValue('xxs')} trigger={trigger} header={filter} onMouseDown={handleMouseDown} From 7837a7b5099ff54100a556d8701039c3c7d31668 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Tue, 10 Feb 2026 17:15:49 +0100 Subject: [PATCH 07/34] fix: hide block border on flexible width --- src/internal/components/dropdown/index.tsx | 2 +- src/internal/components/dropdown/styles.scss | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index 2cab92d232..caa424c15c 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -122,7 +122,7 @@ const TransitionContent = ({ className={clsx(styles.dropdown, dropdownClasses, { [styles.open]: open, [styles['with-limited-width']]: !matchTriggerWidth, - [styles['hide-block-border']]: matchTriggerWidth, + [styles['hide-block-border']]: useFlexibleWidth && !interior, [styles.interior]: interior, [styles.refresh]: isRefresh, [styles['use-portal']]: expandToViewport && !interior, diff --git a/src/internal/components/dropdown/styles.scss b/src/internal/components/dropdown/styles.scss index f0a7a5b059..f65a88b5d4 100644 --- a/src/internal/components/dropdown/styles.scss +++ b/src/internal/components/dropdown/styles.scss @@ -94,10 +94,10 @@ display: block; &:not(.interior).refresh[data-animating='true'] { - transform: translateY(5px); + transform: translateY(4px); &.dropdown-drop-up { - transform: translateY(-5px); + transform: translateY(-4px); } } &.nowrap { From 16e8f6cccf16f997ea8390647358a850d93be402 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Tue, 10 Feb 2026 17:35:29 +0100 Subject: [PATCH 08/34] fix: replicate hide block border behaviour --- src/internal/components/dropdown/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index caa424c15c..7b83dd2d13 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -122,7 +122,7 @@ const TransitionContent = ({ className={clsx(styles.dropdown, dropdownClasses, { [styles.open]: open, [styles['with-limited-width']]: !matchTriggerWidth, - [styles['hide-block-border']]: useFlexibleWidth && !interior, + [styles['hide-block-border']]: maxWidth !== undefined && maxWidth !== 'none' && !interior, [styles.interior]: interior, [styles.refresh]: isRefresh, [styles['use-portal']]: expandToViewport && !interior, From 93b7edce861438dbc5cbfce3c4e2ee80ba311a38 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Tue, 10 Feb 2026 17:47:03 +0100 Subject: [PATCH 09/34] fix: autosuggest sizing --- src/internal/components/autosuggest-input/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/components/autosuggest-input/index.tsx b/src/internal/components/autosuggest-input/index.tsx index 2f6b70d89b..273dd294cc 100644 --- a/src/internal/components/autosuggest-input/index.tsx +++ b/src/internal/components/autosuggest-input/index.tsx @@ -295,7 +295,7 @@ const AutosuggestInput = React.forwardRef( return (
    Date: Tue, 10 Feb 2026 21:00:31 +0100 Subject: [PATCH 10/34] fix: adapt content on resize --- src/internal/components/dropdown/index.tsx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index 7b83dd2d13..96ddfc8450 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -224,16 +224,8 @@ const Dropdown = ({ if (!interior && matchTriggerWidth && !expandToViewport) { target.classList.add(styles['occupy-entire-width']); } else if (!target.classList.contains(styles['use-flexible-width'])) { - // Only set inline-size if not using CSS variables via use-flexible-width + // Only set inline-size if not using CSS class for flexible width target.style.inlineSize = position.inlineSize; - target.style.minInlineSize = ''; - target.style.maxInlineSize = ''; - } else { - // When using use-flexible-width with minWidth='trigger', set min-inline-size - // to ensure the dropdown is at least as wide as the trigger (needed for virtualScroll) - if (minWidth === 'trigger') { - target.style.minInlineSize = `${triggerBox.inlineSize}px`; - } } // Using styles for main dropdown to adjust its position as preferred alternative From 0624fe16068d382dc441088cfcef8c1372064bf9 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Tue, 10 Feb 2026 21:21:46 +0100 Subject: [PATCH 11/34] refactor: simplify logic for hiding border --- src/internal/components/dropdown/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index 96ddfc8450..2f5798ba56 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -122,7 +122,7 @@ const TransitionContent = ({ className={clsx(styles.dropdown, dropdownClasses, { [styles.open]: open, [styles['with-limited-width']]: !matchTriggerWidth, - [styles['hide-block-border']]: maxWidth !== undefined && maxWidth !== 'none' && !interior, + [styles['hide-block-border']]: matchTriggerWidth, [styles.interior]: interior, [styles.refresh]: isRefresh, [styles['use-portal']]: expandToViewport && !interior, From 5bfb8f89b9913b84dabd0dc3f9b91ef95e1cbc11 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Tue, 10 Feb 2026 21:37:59 +0100 Subject: [PATCH 12/34] fix: dont remove class if minWidth provided --- pages/dropdown/fixed-container.page.tsx | 1 + src/internal/components/dropdown/index.tsx | 2 ++ 2 files changed, 3 insertions(+) diff --git a/pages/dropdown/fixed-container.page.tsx b/pages/dropdown/fixed-container.page.tsx index 7c0db57913..a8ec130287 100644 --- a/pages/dropdown/fixed-container.page.tsx +++ b/pages/dropdown/fixed-container.page.tsx @@ -34,6 +34,7 @@ export default function () { open={open} onDropdownClose={() => setOpen(false)} content={} + minWidth={'trigger'} />
    An extra element to enable page scroll
    diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index 2f5798ba56..2006fe2ca4 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -298,10 +298,12 @@ const Dropdown = ({ // Check if the dropdown has enough space to fit with its desired width constraints // If not, remove the class that allows flexible width sizing + // Only applies when no explicit width constraints are set (default behavior) const fixStretching = () => { const classNameToRemove = styles['use-flexible-width']; if ( open && + minWidth === undefined && maxWidth === undefined && !matchTriggerWidth && dropdownRef.current && From 8c2b8fa90bd1ad297252b51ec6f7801fcef6cd9c Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Wed, 11 Feb 2026 10:25:56 +0100 Subject: [PATCH 13/34] fix: restrict max width when expandToViewport=true --- src/button-dropdown/internal.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/button-dropdown/internal.tsx b/src/button-dropdown/internal.tsx index a9895978a5..5e53a0fb3a 100644 --- a/src/button-dropdown/internal.tsx +++ b/src/button-dropdown/internal.tsx @@ -11,6 +11,7 @@ import { ButtonProps } from '../button/interfaces'; import { InternalButton, InternalButtonProps } from '../button/internal'; import { useFunnel } from '../internal/analytics/hooks/use-funnel.js'; import { getBaseProps } from '../internal/base-component'; +import { getBreakpointValue } from '../internal/breakpoints'; import Dropdown from '../internal/components/dropdown'; import OptionsList from '../internal/components/options-list'; import { useMobile } from '../internal/hooks/use-mobile'; @@ -359,7 +360,8 @@ const InternalButtonDropdown = React.forwardRef( > Date: Wed, 11 Feb 2026 10:37:42 +0100 Subject: [PATCH 14/34] fix: remove width constraints in button dropdown --- src/button-dropdown/internal.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/button-dropdown/internal.tsx b/src/button-dropdown/internal.tsx index 5e53a0fb3a..0bf242e022 100644 --- a/src/button-dropdown/internal.tsx +++ b/src/button-dropdown/internal.tsx @@ -11,7 +11,6 @@ import { ButtonProps } from '../button/interfaces'; import { InternalButton, InternalButtonProps } from '../button/internal'; import { useFunnel } from '../internal/analytics/hooks/use-funnel.js'; import { getBaseProps } from '../internal/base-component'; -import { getBreakpointValue } from '../internal/breakpoints'; import Dropdown from '../internal/components/dropdown'; import OptionsList from '../internal/components/options-list'; import { useMobile } from '../internal/hooks/use-mobile'; @@ -360,8 +359,6 @@ const InternalButtonDropdown = React.forwardRef( > Date: Wed, 11 Feb 2026 11:22:45 +0100 Subject: [PATCH 15/34] chore: update dropdown tests --- .../__snapshots__/styles.test.tsx.snap | 144 +++++++++--------- .../__tests__/dropdown-fit-handler.test.ts | 14 +- .../__snapshots__/styles.test.tsx.snap | 66 ++++---- .../__snapshots__/styles.test.tsx.snap | 42 ++--- .../__snapshots__/styles.test.tsx.snap | 40 ++--- .../__snapshots__/styles.test.tsx.snap | 144 +++++++++--------- 6 files changed, 225 insertions(+), 225 deletions(-) diff --git a/src/input/__tests__/__snapshots__/styles.test.tsx.snap b/src/input/__tests__/__snapshots__/styles.test.tsx.snap index 5137108c04..49f1043328 100644 --- a/src/input/__tests__/__snapshots__/styles.test.tsx.snap +++ b/src/input/__tests__/__snapshots__/styles.test.tsx.snap @@ -2,30 +2,30 @@ exports[`getInputStyles handles all possible style configurations 1`] = ` { - "--awsui-style-background-default-4hh3rt": undefined, - "--awsui-style-background-disabled-4hh3rt": undefined, - "--awsui-style-background-focus-4hh3rt": undefined, - "--awsui-style-background-hover-4hh3rt": undefined, - "--awsui-style-background-readonly-4hh3rt": undefined, - "--awsui-style-border-color-default-4hh3rt": undefined, - "--awsui-style-border-color-disabled-4hh3rt": undefined, - "--awsui-style-border-color-focus-4hh3rt": undefined, - "--awsui-style-border-color-hover-4hh3rt": undefined, - "--awsui-style-border-color-readonly-4hh3rt": undefined, - "--awsui-style-box-shadow-default-4hh3rt": undefined, - "--awsui-style-box-shadow-disabled-4hh3rt": undefined, - "--awsui-style-box-shadow-focus-4hh3rt": undefined, - "--awsui-style-box-shadow-hover-4hh3rt": undefined, - "--awsui-style-box-shadow-readonly-4hh3rt": undefined, - "--awsui-style-color-default-4hh3rt": undefined, - "--awsui-style-color-disabled-4hh3rt": undefined, - "--awsui-style-color-focus-4hh3rt": undefined, - "--awsui-style-color-hover-4hh3rt": undefined, - "--awsui-style-color-readonly-4hh3rt": undefined, - "--awsui-style-placeholder-color-4hh3rt": undefined, - "--awsui-style-placeholder-font-size-4hh3rt": undefined, - "--awsui-style-placeholder-font-style-4hh3rt": undefined, - "--awsui-style-placeholder-font-weight-4hh3rt": undefined, + "--awsui-style-background-default-c5ek4l": undefined, + "--awsui-style-background-disabled-c5ek4l": undefined, + "--awsui-style-background-focus-c5ek4l": undefined, + "--awsui-style-background-hover-c5ek4l": undefined, + "--awsui-style-background-readonly-c5ek4l": undefined, + "--awsui-style-border-color-default-c5ek4l": undefined, + "--awsui-style-border-color-disabled-c5ek4l": undefined, + "--awsui-style-border-color-focus-c5ek4l": undefined, + "--awsui-style-border-color-hover-c5ek4l": undefined, + "--awsui-style-border-color-readonly-c5ek4l": undefined, + "--awsui-style-box-shadow-default-c5ek4l": undefined, + "--awsui-style-box-shadow-disabled-c5ek4l": undefined, + "--awsui-style-box-shadow-focus-c5ek4l": undefined, + "--awsui-style-box-shadow-hover-c5ek4l": undefined, + "--awsui-style-box-shadow-readonly-c5ek4l": undefined, + "--awsui-style-color-default-c5ek4l": undefined, + "--awsui-style-color-disabled-c5ek4l": undefined, + "--awsui-style-color-focus-c5ek4l": undefined, + "--awsui-style-color-hover-c5ek4l": undefined, + "--awsui-style-color-readonly-c5ek4l": undefined, + "--awsui-style-placeholder-color-c5ek4l": undefined, + "--awsui-style-placeholder-font-size-c5ek4l": undefined, + "--awsui-style-placeholder-font-style-c5ek4l": undefined, + "--awsui-style-placeholder-font-weight-c5ek4l": undefined, "borderRadius": undefined, "borderWidth": undefined, "fontSize": undefined, @@ -37,30 +37,30 @@ exports[`getInputStyles handles all possible style configurations 1`] = ` exports[`getInputStyles handles all possible style configurations 2`] = ` { - "--awsui-style-background-default-4hh3rt": undefined, - "--awsui-style-background-disabled-4hh3rt": undefined, - "--awsui-style-background-focus-4hh3rt": undefined, - "--awsui-style-background-hover-4hh3rt": undefined, - "--awsui-style-background-readonly-4hh3rt": undefined, - "--awsui-style-border-color-default-4hh3rt": undefined, - "--awsui-style-border-color-disabled-4hh3rt": undefined, - "--awsui-style-border-color-focus-4hh3rt": undefined, - "--awsui-style-border-color-hover-4hh3rt": undefined, - "--awsui-style-border-color-readonly-4hh3rt": undefined, - "--awsui-style-box-shadow-default-4hh3rt": undefined, - "--awsui-style-box-shadow-disabled-4hh3rt": undefined, - "--awsui-style-box-shadow-focus-4hh3rt": undefined, - "--awsui-style-box-shadow-hover-4hh3rt": undefined, - "--awsui-style-box-shadow-readonly-4hh3rt": undefined, - "--awsui-style-color-default-4hh3rt": undefined, - "--awsui-style-color-disabled-4hh3rt": undefined, - "--awsui-style-color-focus-4hh3rt": undefined, - "--awsui-style-color-hover-4hh3rt": undefined, - "--awsui-style-color-readonly-4hh3rt": undefined, - "--awsui-style-placeholder-color-4hh3rt": undefined, - "--awsui-style-placeholder-font-size-4hh3rt": undefined, - "--awsui-style-placeholder-font-style-4hh3rt": undefined, - "--awsui-style-placeholder-font-weight-4hh3rt": undefined, + "--awsui-style-background-default-c5ek4l": undefined, + "--awsui-style-background-disabled-c5ek4l": undefined, + "--awsui-style-background-focus-c5ek4l": undefined, + "--awsui-style-background-hover-c5ek4l": undefined, + "--awsui-style-background-readonly-c5ek4l": undefined, + "--awsui-style-border-color-default-c5ek4l": undefined, + "--awsui-style-border-color-disabled-c5ek4l": undefined, + "--awsui-style-border-color-focus-c5ek4l": undefined, + "--awsui-style-border-color-hover-c5ek4l": undefined, + "--awsui-style-border-color-readonly-c5ek4l": undefined, + "--awsui-style-box-shadow-default-c5ek4l": undefined, + "--awsui-style-box-shadow-disabled-c5ek4l": undefined, + "--awsui-style-box-shadow-focus-c5ek4l": undefined, + "--awsui-style-box-shadow-hover-c5ek4l": undefined, + "--awsui-style-box-shadow-readonly-c5ek4l": undefined, + "--awsui-style-color-default-c5ek4l": undefined, + "--awsui-style-color-disabled-c5ek4l": undefined, + "--awsui-style-color-focus-c5ek4l": undefined, + "--awsui-style-color-hover-c5ek4l": undefined, + "--awsui-style-color-readonly-c5ek4l": undefined, + "--awsui-style-placeholder-color-c5ek4l": undefined, + "--awsui-style-placeholder-font-size-c5ek4l": undefined, + "--awsui-style-placeholder-font-style-c5ek4l": undefined, + "--awsui-style-placeholder-font-weight-c5ek4l": undefined, "borderRadius": undefined, "borderWidth": undefined, "fontSize": undefined, @@ -72,30 +72,30 @@ exports[`getInputStyles handles all possible style configurations 2`] = ` exports[`getInputStyles handles all possible style configurations 3`] = ` { - "--awsui-style-background-default-4hh3rt": "#ffffff", - "--awsui-style-background-disabled-4hh3rt": "#f0f0f0", - "--awsui-style-background-focus-4hh3rt": "#ffffff", - "--awsui-style-background-hover-4hh3rt": "#fafafa", - "--awsui-style-background-readonly-4hh3rt": "#ffffff", - "--awsui-style-border-color-default-4hh3rt": "#cccccc", - "--awsui-style-border-color-disabled-4hh3rt": "#e0e0e0", - "--awsui-style-border-color-focus-4hh3rt": "#0073bb", - "--awsui-style-border-color-hover-4hh3rt": "#999999", - "--awsui-style-border-color-readonly-4hh3rt": "#e0e0e0", - "--awsui-style-box-shadow-default-4hh3rt": "none", - "--awsui-style-box-shadow-disabled-4hh3rt": "none", - "--awsui-style-box-shadow-focus-4hh3rt": "0 0 0 2px #0073bb", - "--awsui-style-box-shadow-hover-4hh3rt": "0 1px 2px rgba(0,0,0,0.1)", - "--awsui-style-box-shadow-readonly-4hh3rt": "none", - "--awsui-style-color-default-4hh3rt": "#000000", - "--awsui-style-color-disabled-4hh3rt": "#999999", - "--awsui-style-color-focus-4hh3rt": "#000000", - "--awsui-style-color-hover-4hh3rt": "#000000", - "--awsui-style-color-readonly-4hh3rt": "#000000", - "--awsui-style-placeholder-color-4hh3rt": "#999999", - "--awsui-style-placeholder-font-size-4hh3rt": "14px", - "--awsui-style-placeholder-font-style-4hh3rt": "italic", - "--awsui-style-placeholder-font-weight-4hh3rt": "400", + "--awsui-style-background-default-c5ek4l": "#ffffff", + "--awsui-style-background-disabled-c5ek4l": "#f0f0f0", + "--awsui-style-background-focus-c5ek4l": "#ffffff", + "--awsui-style-background-hover-c5ek4l": "#fafafa", + "--awsui-style-background-readonly-c5ek4l": "#ffffff", + "--awsui-style-border-color-default-c5ek4l": "#cccccc", + "--awsui-style-border-color-disabled-c5ek4l": "#e0e0e0", + "--awsui-style-border-color-focus-c5ek4l": "#0073bb", + "--awsui-style-border-color-hover-c5ek4l": "#999999", + "--awsui-style-border-color-readonly-c5ek4l": "#e0e0e0", + "--awsui-style-box-shadow-default-c5ek4l": "none", + "--awsui-style-box-shadow-disabled-c5ek4l": "none", + "--awsui-style-box-shadow-focus-c5ek4l": "0 0 0 2px #0073bb", + "--awsui-style-box-shadow-hover-c5ek4l": "0 1px 2px rgba(0,0,0,0.1)", + "--awsui-style-box-shadow-readonly-c5ek4l": "none", + "--awsui-style-color-default-c5ek4l": "#000000", + "--awsui-style-color-disabled-c5ek4l": "#999999", + "--awsui-style-color-focus-c5ek4l": "#000000", + "--awsui-style-color-hover-c5ek4l": "#000000", + "--awsui-style-color-readonly-c5ek4l": "#000000", + "--awsui-style-placeholder-color-c5ek4l": "#999999", + "--awsui-style-placeholder-font-size-c5ek4l": "14px", + "--awsui-style-placeholder-font-style-c5ek4l": "italic", + "--awsui-style-placeholder-font-weight-c5ek4l": "400", "borderRadius": "4px", "borderWidth": "1px", "fontSize": "14px", diff --git a/src/internal/components/dropdown/__tests__/dropdown-fit-handler.test.ts b/src/internal/components/dropdown/__tests__/dropdown-fit-handler.test.ts index 6676ad6240..edee16e265 100644 --- a/src/internal/components/dropdown/__tests__/dropdown-fit-handler.test.ts +++ b/src/internal/components/dropdown/__tests__/dropdown-fit-handler.test.ts @@ -102,7 +102,7 @@ describe('getDropdownPosition', () => { }); }); - test('minWidth cannot be more than trigger width', () => { + test('minWidth is respected even when larger than trigger width', () => { const trigger = getSizedElement(200, 50, 300, 100); const dropdown = getSizedElement(100, 400); expect( @@ -114,7 +114,7 @@ describe('getDropdownPosition', () => { }) ).toEqual({ ...defaults, - inlineSize: '200px', + inlineSize: '300px', }); }); @@ -183,7 +183,7 @@ describe('getDropdownPosition', () => { }); }); - describe('with maxWidth undefined (can stretch beyond trigger)', () => { + describe('with maxWidth undefined (no max constraint)', () => { test('can expand beyond trigger width', () => { const triggerElement = getSizedElement(100, 50, 300, 15); const dropdownElement = getSizedElement(200, 300); @@ -201,7 +201,7 @@ describe('getDropdownPosition', () => { }); }); - test('cannot expand beyond the XXS breakpoint', () => { + test('can expand to content width', () => { const triggerElement = getSizedElement(100, 50, 300, 15); const dropdownElement = getSizedElement(1000, 300); @@ -214,11 +214,11 @@ describe('getDropdownPosition', () => { }) ).toEqual({ ...defaults, - inlineSize: '465px', + inlineSize: '935px', }); }); - test('will always grow to the width of the trigger if possible', () => { + test('will always grow to the width of the content if possible', () => { const triggerElement = getSizedElement(700, 50, 300, 15); const dropdownElement = getSizedElement(400, 300); @@ -231,7 +231,7 @@ describe('getDropdownPosition', () => { }) ).toEqual({ ...defaults, - inlineSize: '700px', + inlineSize: '400px', }); }); }); diff --git a/src/segmented-control/__tests__/__snapshots__/styles.test.tsx.snap b/src/segmented-control/__tests__/__snapshots__/styles.test.tsx.snap index 42d7b5a174..510003a717 100644 --- a/src/segmented-control/__tests__/__snapshots__/styles.test.tsx.snap +++ b/src/segmented-control/__tests__/__snapshots__/styles.test.tsx.snap @@ -20,17 +20,17 @@ exports[`getSegmentedControlRootStyles handles all possible style configurations exports[`getSegmentedControlSegmentStyles handles all possible style configurations 1`] = ` { - "--awsui-style-background-active-4hh3rt": undefined, - "--awsui-style-background-default-4hh3rt": undefined, - "--awsui-style-background-disabled-4hh3rt": undefined, - "--awsui-style-background-hover-4hh3rt": undefined, - "--awsui-style-color-active-4hh3rt": undefined, - "--awsui-style-color-default-4hh3rt": undefined, - "--awsui-style-color-disabled-4hh3rt": undefined, - "--awsui-style-color-hover-4hh3rt": undefined, - "--awsui-style-focus-ring-border-color-4hh3rt": undefined, - "--awsui-style-focus-ring-border-radius-4hh3rt": undefined, - "--awsui-style-focus-ring-border-width-4hh3rt": undefined, + "--awsui-style-background-active-c5ek4l": undefined, + "--awsui-style-background-default-c5ek4l": undefined, + "--awsui-style-background-disabled-c5ek4l": undefined, + "--awsui-style-background-hover-c5ek4l": undefined, + "--awsui-style-color-active-c5ek4l": undefined, + "--awsui-style-color-default-c5ek4l": undefined, + "--awsui-style-color-disabled-c5ek4l": undefined, + "--awsui-style-color-hover-c5ek4l": undefined, + "--awsui-style-focus-ring-border-color-c5ek4l": undefined, + "--awsui-style-focus-ring-border-radius-c5ek4l": undefined, + "--awsui-style-focus-ring-border-width-c5ek4l": undefined, "borderRadius": undefined, "fontSize": undefined, "paddingBlock": undefined, @@ -40,17 +40,17 @@ exports[`getSegmentedControlSegmentStyles handles all possible style configurati exports[`getSegmentedControlSegmentStyles handles all possible style configurations 2`] = ` { - "--awsui-style-background-active-4hh3rt": undefined, - "--awsui-style-background-default-4hh3rt": undefined, - "--awsui-style-background-disabled-4hh3rt": undefined, - "--awsui-style-background-hover-4hh3rt": undefined, - "--awsui-style-color-active-4hh3rt": undefined, - "--awsui-style-color-default-4hh3rt": undefined, - "--awsui-style-color-disabled-4hh3rt": undefined, - "--awsui-style-color-hover-4hh3rt": undefined, - "--awsui-style-focus-ring-border-color-4hh3rt": undefined, - "--awsui-style-focus-ring-border-radius-4hh3rt": undefined, - "--awsui-style-focus-ring-border-width-4hh3rt": undefined, + "--awsui-style-background-active-c5ek4l": undefined, + "--awsui-style-background-default-c5ek4l": undefined, + "--awsui-style-background-disabled-c5ek4l": undefined, + "--awsui-style-background-hover-c5ek4l": undefined, + "--awsui-style-color-active-c5ek4l": undefined, + "--awsui-style-color-default-c5ek4l": undefined, + "--awsui-style-color-disabled-c5ek4l": undefined, + "--awsui-style-color-hover-c5ek4l": undefined, + "--awsui-style-focus-ring-border-color-c5ek4l": undefined, + "--awsui-style-focus-ring-border-radius-c5ek4l": undefined, + "--awsui-style-focus-ring-border-width-c5ek4l": undefined, "borderRadius": undefined, "fontSize": undefined, "paddingBlock": undefined, @@ -60,17 +60,17 @@ exports[`getSegmentedControlSegmentStyles handles all possible style configurati exports[`getSegmentedControlSegmentStyles handles all possible style configurations 3`] = ` { - "--awsui-style-background-active-4hh3rt": "#0073bb", - "--awsui-style-background-default-4hh3rt": "#ffffff", - "--awsui-style-background-disabled-4hh3rt": "#f0f0f0", - "--awsui-style-background-hover-4hh3rt": "#fafafa", - "--awsui-style-color-active-4hh3rt": "#ffffff", - "--awsui-style-color-default-4hh3rt": "#000000", - "--awsui-style-color-disabled-4hh3rt": "#999999", - "--awsui-style-color-hover-4hh3rt": "#000000", - "--awsui-style-focus-ring-border-color-4hh3rt": "#0073bb", - "--awsui-style-focus-ring-border-radius-4hh3rt": "8px", - "--awsui-style-focus-ring-border-width-4hh3rt": "2px", + "--awsui-style-background-active-c5ek4l": "#0073bb", + "--awsui-style-background-default-c5ek4l": "#ffffff", + "--awsui-style-background-disabled-c5ek4l": "#f0f0f0", + "--awsui-style-background-hover-c5ek4l": "#fafafa", + "--awsui-style-color-active-c5ek4l": "#ffffff", + "--awsui-style-color-default-c5ek4l": "#000000", + "--awsui-style-color-disabled-c5ek4l": "#999999", + "--awsui-style-color-hover-c5ek4l": "#000000", + "--awsui-style-focus-ring-border-color-c5ek4l": "#0073bb", + "--awsui-style-focus-ring-border-radius-c5ek4l": "8px", + "--awsui-style-focus-ring-border-width-c5ek4l": "2px", "borderRadius": "6px", "fontSize": "14px", "paddingBlock": "8px", diff --git a/src/slider/__tests__/__snapshots__/styles.test.tsx.snap b/src/slider/__tests__/__snapshots__/styles.test.tsx.snap index 0bbae37e46..5b880a8c80 100644 --- a/src/slider/__tests__/__snapshots__/styles.test.tsx.snap +++ b/src/slider/__tests__/__snapshots__/styles.test.tsx.snap @@ -2,36 +2,36 @@ exports[`getSliderStyles handles all possible style configurations 1`] = ` { - "--awsui-style-slider-handle-background-active-4hh3rt": undefined, - "--awsui-style-slider-handle-background-default-4hh3rt": undefined, - "--awsui-style-slider-handle-background-hover-4hh3rt": undefined, - "--awsui-style-slider-handle-border-radius-4hh3rt": undefined, - "--awsui-style-slider-range-background-active-4hh3rt": undefined, - "--awsui-style-slider-range-background-default-4hh3rt": undefined, - "--awsui-style-slider-track-background-color-4hh3rt": undefined, + "--awsui-style-slider-handle-background-active-c5ek4l": undefined, + "--awsui-style-slider-handle-background-default-c5ek4l": undefined, + "--awsui-style-slider-handle-background-hover-c5ek4l": undefined, + "--awsui-style-slider-handle-border-radius-c5ek4l": undefined, + "--awsui-style-slider-range-background-active-c5ek4l": undefined, + "--awsui-style-slider-range-background-default-c5ek4l": undefined, + "--awsui-style-slider-track-background-color-c5ek4l": undefined, } `; exports[`getSliderStyles handles all possible style configurations 2`] = ` { - "--awsui-style-slider-handle-background-active-4hh3rt": undefined, - "--awsui-style-slider-handle-background-default-4hh3rt": undefined, - "--awsui-style-slider-handle-background-hover-4hh3rt": undefined, - "--awsui-style-slider-handle-border-radius-4hh3rt": undefined, - "--awsui-style-slider-range-background-active-4hh3rt": undefined, - "--awsui-style-slider-range-background-default-4hh3rt": undefined, - "--awsui-style-slider-track-background-color-4hh3rt": undefined, + "--awsui-style-slider-handle-background-active-c5ek4l": undefined, + "--awsui-style-slider-handle-background-default-c5ek4l": undefined, + "--awsui-style-slider-handle-background-hover-c5ek4l": undefined, + "--awsui-style-slider-handle-border-radius-c5ek4l": undefined, + "--awsui-style-slider-range-background-active-c5ek4l": undefined, + "--awsui-style-slider-range-background-default-c5ek4l": undefined, + "--awsui-style-slider-track-background-color-c5ek4l": undefined, } `; exports[`getSliderStyles handles all possible style configurations 3`] = ` { - "--awsui-style-slider-handle-background-active-4hh3rt": "#1d4ed8", - "--awsui-style-slider-handle-background-default-4hh3rt": "#3b82f6", - "--awsui-style-slider-handle-background-hover-4hh3rt": "#2563eb", - "--awsui-style-slider-handle-border-radius-4hh3rt": "50%", - "--awsui-style-slider-range-background-active-4hh3rt": "#2563eb", - "--awsui-style-slider-range-background-default-4hh3rt": "#3b82f6", - "--awsui-style-slider-track-background-color-4hh3rt": "#dbeafe", + "--awsui-style-slider-handle-background-active-c5ek4l": "#1d4ed8", + "--awsui-style-slider-handle-background-default-c5ek4l": "#3b82f6", + "--awsui-style-slider-handle-background-hover-c5ek4l": "#2563eb", + "--awsui-style-slider-handle-border-radius-c5ek4l": "50%", + "--awsui-style-slider-range-background-active-c5ek4l": "#2563eb", + "--awsui-style-slider-range-background-default-c5ek4l": "#3b82f6", + "--awsui-style-slider-track-background-color-c5ek4l": "#dbeafe", } `; diff --git a/src/tabs/__tests__/__snapshots__/styles.test.tsx.snap b/src/tabs/__tests__/__snapshots__/styles.test.tsx.snap index 1819d94ef3..65c1b9228f 100644 --- a/src/tabs/__tests__/__snapshots__/styles.test.tsx.snap +++ b/src/tabs/__tests__/__snapshots__/styles.test.tsx.snap @@ -2,21 +2,21 @@ exports[`getTabStyles transforms tab styles to CSS properties 1`] = ` { - "--awsui-style-background-active-4hh3rt": "#bfdbfe", - "--awsui-style-background-default-4hh3rt": "#dbeafe", - "--awsui-style-background-disabled-4hh3rt": "#f3f4f6", - "--awsui-style-background-hover-4hh3rt": "#eff6ff", - "--awsui-style-border-color-active-4hh3rt": "#1d4ed8", - "--awsui-style-border-color-default-4hh3rt": "#3b82f6", - "--awsui-style-border-color-disabled-4hh3rt": "#93c5fd", - "--awsui-style-border-color-hover-4hh3rt": "#2563eb", - "--awsui-style-color-active-4hh3rt": "#1e3a8a", - "--awsui-style-color-default-4hh3rt": "#1e40af", - "--awsui-style-color-disabled-4hh3rt": "#93c5fd", - "--awsui-style-color-hover-4hh3rt": "#1e40af", - "--awsui-style-focus-ring-border-color-4hh3rt": "#3b82f6", - "--awsui-style-focus-ring-border-radius-4hh3rt": "4px", - "--awsui-style-focus-ring-border-width-4hh3rt": "2px", + "--awsui-style-background-active-c5ek4l": "#bfdbfe", + "--awsui-style-background-default-c5ek4l": "#dbeafe", + "--awsui-style-background-disabled-c5ek4l": "#f3f4f6", + "--awsui-style-background-hover-c5ek4l": "#eff6ff", + "--awsui-style-border-color-active-c5ek4l": "#1d4ed8", + "--awsui-style-border-color-default-c5ek4l": "#3b82f6", + "--awsui-style-border-color-disabled-c5ek4l": "#93c5fd", + "--awsui-style-border-color-hover-c5ek4l": "#2563eb", + "--awsui-style-color-active-c5ek4l": "#1e3a8a", + "--awsui-style-color-default-c5ek4l": "#1e40af", + "--awsui-style-color-disabled-c5ek4l": "#93c5fd", + "--awsui-style-color-hover-c5ek4l": "#1e40af", + "--awsui-style-focus-ring-border-color-c5ek4l": "#3b82f6", + "--awsui-style-focus-ring-border-radius-c5ek4l": "4px", + "--awsui-style-focus-ring-border-width-c5ek4l": "2px", "borderRadius": "4px", "borderWidth": "2px", "fontSize": "16px", @@ -28,10 +28,10 @@ exports[`getTabStyles transforms tab styles to CSS properties 1`] = ` exports[`getTabStyles transforms tab styles to CSS properties 2`] = ` { - "--awsui-style-tabs-active-indicator-border-radius-4hh3rt": "2px", - "--awsui-style-tabs-active-indicator-color-4hh3rt": "#1d4ed8", - "--awsui-style-tabs-active-indicator-width-4hh3rt": "3px", - "--awsui-style-tabs-separator-color-4hh3rt": "#cbd5e1", - "--awsui-style-tabs-separator-width-4hh3rt": "2px", + "--awsui-style-tabs-active-indicator-border-radius-c5ek4l": "2px", + "--awsui-style-tabs-active-indicator-color-c5ek4l": "#1d4ed8", + "--awsui-style-tabs-active-indicator-width-c5ek4l": "3px", + "--awsui-style-tabs-separator-color-c5ek4l": "#cbd5e1", + "--awsui-style-tabs-separator-width-c5ek4l": "2px", } `; diff --git a/src/text-filter/__tests__/__snapshots__/styles.test.tsx.snap b/src/text-filter/__tests__/__snapshots__/styles.test.tsx.snap index 1656057a7d..1d10ad578d 100644 --- a/src/text-filter/__tests__/__snapshots__/styles.test.tsx.snap +++ b/src/text-filter/__tests__/__snapshots__/styles.test.tsx.snap @@ -2,30 +2,30 @@ exports[`getTextFilterStyles handles all possible style configurations 1`] = ` { - "--awsui-style-background-default-4hh3rt": undefined, - "--awsui-style-background-disabled-4hh3rt": undefined, - "--awsui-style-background-focus-4hh3rt": undefined, - "--awsui-style-background-hover-4hh3rt": undefined, - "--awsui-style-background-readonly-4hh3rt": undefined, - "--awsui-style-border-color-default-4hh3rt": undefined, - "--awsui-style-border-color-disabled-4hh3rt": undefined, - "--awsui-style-border-color-focus-4hh3rt": undefined, - "--awsui-style-border-color-hover-4hh3rt": undefined, - "--awsui-style-border-color-readonly-4hh3rt": undefined, - "--awsui-style-box-shadow-default-4hh3rt": undefined, - "--awsui-style-box-shadow-disabled-4hh3rt": undefined, - "--awsui-style-box-shadow-focus-4hh3rt": undefined, - "--awsui-style-box-shadow-hover-4hh3rt": undefined, - "--awsui-style-box-shadow-readonly-4hh3rt": undefined, - "--awsui-style-color-default-4hh3rt": undefined, - "--awsui-style-color-disabled-4hh3rt": undefined, - "--awsui-style-color-focus-4hh3rt": undefined, - "--awsui-style-color-hover-4hh3rt": undefined, - "--awsui-style-color-readonly-4hh3rt": undefined, - "--awsui-style-placeholder-color-4hh3rt": undefined, - "--awsui-style-placeholder-font-size-4hh3rt": undefined, - "--awsui-style-placeholder-font-style-4hh3rt": undefined, - "--awsui-style-placeholder-font-weight-4hh3rt": undefined, + "--awsui-style-background-default-c5ek4l": undefined, + "--awsui-style-background-disabled-c5ek4l": undefined, + "--awsui-style-background-focus-c5ek4l": undefined, + "--awsui-style-background-hover-c5ek4l": undefined, + "--awsui-style-background-readonly-c5ek4l": undefined, + "--awsui-style-border-color-default-c5ek4l": undefined, + "--awsui-style-border-color-disabled-c5ek4l": undefined, + "--awsui-style-border-color-focus-c5ek4l": undefined, + "--awsui-style-border-color-hover-c5ek4l": undefined, + "--awsui-style-border-color-readonly-c5ek4l": undefined, + "--awsui-style-box-shadow-default-c5ek4l": undefined, + "--awsui-style-box-shadow-disabled-c5ek4l": undefined, + "--awsui-style-box-shadow-focus-c5ek4l": undefined, + "--awsui-style-box-shadow-hover-c5ek4l": undefined, + "--awsui-style-box-shadow-readonly-c5ek4l": undefined, + "--awsui-style-color-default-c5ek4l": undefined, + "--awsui-style-color-disabled-c5ek4l": undefined, + "--awsui-style-color-focus-c5ek4l": undefined, + "--awsui-style-color-hover-c5ek4l": undefined, + "--awsui-style-color-readonly-c5ek4l": undefined, + "--awsui-style-placeholder-color-c5ek4l": undefined, + "--awsui-style-placeholder-font-size-c5ek4l": undefined, + "--awsui-style-placeholder-font-style-c5ek4l": undefined, + "--awsui-style-placeholder-font-weight-c5ek4l": undefined, "borderRadius": undefined, "borderWidth": undefined, "fontSize": undefined, @@ -37,30 +37,30 @@ exports[`getTextFilterStyles handles all possible style configurations 1`] = ` exports[`getTextFilterStyles handles all possible style configurations 2`] = ` { - "--awsui-style-background-default-4hh3rt": undefined, - "--awsui-style-background-disabled-4hh3rt": undefined, - "--awsui-style-background-focus-4hh3rt": undefined, - "--awsui-style-background-hover-4hh3rt": undefined, - "--awsui-style-background-readonly-4hh3rt": undefined, - "--awsui-style-border-color-default-4hh3rt": undefined, - "--awsui-style-border-color-disabled-4hh3rt": undefined, - "--awsui-style-border-color-focus-4hh3rt": undefined, - "--awsui-style-border-color-hover-4hh3rt": undefined, - "--awsui-style-border-color-readonly-4hh3rt": undefined, - "--awsui-style-box-shadow-default-4hh3rt": undefined, - "--awsui-style-box-shadow-disabled-4hh3rt": undefined, - "--awsui-style-box-shadow-focus-4hh3rt": undefined, - "--awsui-style-box-shadow-hover-4hh3rt": undefined, - "--awsui-style-box-shadow-readonly-4hh3rt": undefined, - "--awsui-style-color-default-4hh3rt": undefined, - "--awsui-style-color-disabled-4hh3rt": undefined, - "--awsui-style-color-focus-4hh3rt": undefined, - "--awsui-style-color-hover-4hh3rt": undefined, - "--awsui-style-color-readonly-4hh3rt": undefined, - "--awsui-style-placeholder-color-4hh3rt": undefined, - "--awsui-style-placeholder-font-size-4hh3rt": undefined, - "--awsui-style-placeholder-font-style-4hh3rt": undefined, - "--awsui-style-placeholder-font-weight-4hh3rt": undefined, + "--awsui-style-background-default-c5ek4l": undefined, + "--awsui-style-background-disabled-c5ek4l": undefined, + "--awsui-style-background-focus-c5ek4l": undefined, + "--awsui-style-background-hover-c5ek4l": undefined, + "--awsui-style-background-readonly-c5ek4l": undefined, + "--awsui-style-border-color-default-c5ek4l": undefined, + "--awsui-style-border-color-disabled-c5ek4l": undefined, + "--awsui-style-border-color-focus-c5ek4l": undefined, + "--awsui-style-border-color-hover-c5ek4l": undefined, + "--awsui-style-border-color-readonly-c5ek4l": undefined, + "--awsui-style-box-shadow-default-c5ek4l": undefined, + "--awsui-style-box-shadow-disabled-c5ek4l": undefined, + "--awsui-style-box-shadow-focus-c5ek4l": undefined, + "--awsui-style-box-shadow-hover-c5ek4l": undefined, + "--awsui-style-box-shadow-readonly-c5ek4l": undefined, + "--awsui-style-color-default-c5ek4l": undefined, + "--awsui-style-color-disabled-c5ek4l": undefined, + "--awsui-style-color-focus-c5ek4l": undefined, + "--awsui-style-color-hover-c5ek4l": undefined, + "--awsui-style-color-readonly-c5ek4l": undefined, + "--awsui-style-placeholder-color-c5ek4l": undefined, + "--awsui-style-placeholder-font-size-c5ek4l": undefined, + "--awsui-style-placeholder-font-style-c5ek4l": undefined, + "--awsui-style-placeholder-font-weight-c5ek4l": undefined, "borderRadius": undefined, "borderWidth": undefined, "fontSize": undefined, @@ -72,30 +72,30 @@ exports[`getTextFilterStyles handles all possible style configurations 2`] = ` exports[`getTextFilterStyles handles all possible style configurations 3`] = ` { - "--awsui-style-background-default-4hh3rt": "#ffffff", - "--awsui-style-background-disabled-4hh3rt": "#f0f0f0", - "--awsui-style-background-focus-4hh3rt": "#ffffff", - "--awsui-style-background-hover-4hh3rt": "#fafafa", - "--awsui-style-background-readonly-4hh3rt": "#ffffff", - "--awsui-style-border-color-default-4hh3rt": "#cccccc", - "--awsui-style-border-color-disabled-4hh3rt": "#e0e0e0", - "--awsui-style-border-color-focus-4hh3rt": "#0073bb", - "--awsui-style-border-color-hover-4hh3rt": "#999999", - "--awsui-style-border-color-readonly-4hh3rt": "#e0e0e0", - "--awsui-style-box-shadow-default-4hh3rt": "none", - "--awsui-style-box-shadow-disabled-4hh3rt": "none", - "--awsui-style-box-shadow-focus-4hh3rt": "0 0 0 2px #0073bb", - "--awsui-style-box-shadow-hover-4hh3rt": "0 1px 2px rgba(0,0,0,0.1)", - "--awsui-style-box-shadow-readonly-4hh3rt": "none", - "--awsui-style-color-default-4hh3rt": "#000000", - "--awsui-style-color-disabled-4hh3rt": "#999999", - "--awsui-style-color-focus-4hh3rt": "#000000", - "--awsui-style-color-hover-4hh3rt": "#000000", - "--awsui-style-color-readonly-4hh3rt": "#000000", - "--awsui-style-placeholder-color-4hh3rt": "#999999", - "--awsui-style-placeholder-font-size-4hh3rt": "14px", - "--awsui-style-placeholder-font-style-4hh3rt": "italic", - "--awsui-style-placeholder-font-weight-4hh3rt": "400", + "--awsui-style-background-default-c5ek4l": "#ffffff", + "--awsui-style-background-disabled-c5ek4l": "#f0f0f0", + "--awsui-style-background-focus-c5ek4l": "#ffffff", + "--awsui-style-background-hover-c5ek4l": "#fafafa", + "--awsui-style-background-readonly-c5ek4l": "#ffffff", + "--awsui-style-border-color-default-c5ek4l": "#cccccc", + "--awsui-style-border-color-disabled-c5ek4l": "#e0e0e0", + "--awsui-style-border-color-focus-c5ek4l": "#0073bb", + "--awsui-style-border-color-hover-c5ek4l": "#999999", + "--awsui-style-border-color-readonly-c5ek4l": "#e0e0e0", + "--awsui-style-box-shadow-default-c5ek4l": "none", + "--awsui-style-box-shadow-disabled-c5ek4l": "none", + "--awsui-style-box-shadow-focus-c5ek4l": "0 0 0 2px #0073bb", + "--awsui-style-box-shadow-hover-c5ek4l": "0 1px 2px rgba(0,0,0,0.1)", + "--awsui-style-box-shadow-readonly-c5ek4l": "none", + "--awsui-style-color-default-c5ek4l": "#000000", + "--awsui-style-color-disabled-c5ek4l": "#999999", + "--awsui-style-color-focus-c5ek4l": "#000000", + "--awsui-style-color-hover-c5ek4l": "#000000", + "--awsui-style-color-readonly-c5ek4l": "#000000", + "--awsui-style-placeholder-color-c5ek4l": "#999999", + "--awsui-style-placeholder-font-size-c5ek4l": "14px", + "--awsui-style-placeholder-font-style-c5ek4l": "italic", + "--awsui-style-placeholder-font-weight-c5ek4l": "400", "borderRadius": "4px", "borderWidth": "1px", "fontSize": "14px", From df86788916cda1270a3f4945360f6ebec9b31f61 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Wed, 11 Feb 2026 11:43:03 +0100 Subject: [PATCH 16/34] retrigger checks From ab1e09d3d6dfb8919bdac441040bb1b667234861 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Wed, 11 Feb 2026 11:43:28 +0100 Subject: [PATCH 17/34] feat: allow any string value as width param --- src/internal/components/dropdown/index.tsx | 19 +++++++++++-------- .../components/dropdown/interfaces.ts | 7 +++++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index 2006fe2ca4..934052bfbf 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -429,31 +429,34 @@ const Dropdown = ({ // Compute CSS variable values for min/max width // These will be used by the use-flexible-width CSS class const getMinWidthCssValue = (): string | undefined => { + if (minWidth === undefined) { + return undefined; + } if (typeof minWidth === 'number') { return `${minWidth}px`; } - if (minWidth === 'max-content') { - return 'max-content'; - } + // 'trigger' is a special keyword that maps to 100% (relative to parent) if (minWidth === 'trigger') { return '100%'; } - return undefined; + // Pass through any other CSS value as-is + return minWidth; }; const getMaxWidthCssValue = (): string | undefined => { if (typeof maxWidth === 'number') { return `${maxWidth}px`; } - if (maxWidth === 'max-content') { - return 'max-content'; + // 'trigger' is a special keyword that maps to 100% (relative to parent) + if (maxWidth === 'trigger') { + return '100%'; } // When maxWidth is undefined, allow dropdown to grow to content size - // The CSS fallback of 100% would constrain it to trigger width if (maxWidth === undefined) { return 'none'; } - return undefined; + // Pass through any other CSS value as-is + return maxWidth; }; return ( diff --git a/src/internal/components/dropdown/interfaces.ts b/src/internal/components/dropdown/interfaces.ts index 46107fe332..4b9f34eab7 100644 --- a/src/internal/components/dropdown/interfaces.ts +++ b/src/internal/components/dropdown/interfaces.ts @@ -7,9 +7,12 @@ import { NonCancelableEventHandler } from '../../events'; export type OptionsFilteringType = 'none' | 'auto' | 'manual'; /** - * Width constraint that can be a pixel value, reference the trigger width, or fit content + * Width constraint for the dropdown. + * - 'trigger': references the trigger element's width + * - string: any valid CSS value (e.g., '100px', '50%', 'max-content') + * - number: width in pixels */ -export type DropdownWidthConstraint = number | 'trigger' | 'max-content'; +export type DropdownWidthConstraint = 'trigger' | string | number; export interface OptionsLoadItemsDetail { filteringText: string; From f0f88f200b75a4861a04e28479de48f5aa65ea45 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Wed, 11 Feb 2026 23:01:37 +0100 Subject: [PATCH 18/34] fix: run stretch with --- src/button-dropdown/internal.tsx | 1 + src/internal/components/dropdown/index.tsx | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/button-dropdown/internal.tsx b/src/button-dropdown/internal.tsx index 0bf242e022..173c7ab23f 100644 --- a/src/button-dropdown/internal.tsx +++ b/src/button-dropdown/internal.tsx @@ -360,6 +360,7 @@ const InternalButtonDropdown = React.forwardRef( toggleDropdown()} diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index 934052bfbf..ebd0bff8c0 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -298,14 +298,10 @@ const Dropdown = ({ // Check if the dropdown has enough space to fit with its desired width constraints // If not, remove the class that allows flexible width sizing - // Only applies when no explicit width constraints are set (default behavior) const fixStretching = () => { const classNameToRemove = styles['use-flexible-width']; if ( open && - minWidth === undefined && - maxWidth === undefined && - !matchTriggerWidth && dropdownRef.current && triggerRef.current && dropdownRef.current.classList.contains(classNameToRemove) && From 1caeaa6f873f3df7a5b02476386edc4dde27dc9c Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Thu, 12 Feb 2026 00:08:45 +0100 Subject: [PATCH 19/34] chore: add unit test for minWidth and maxWidth --- .../dropdown/__tests__/dropdown.test.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/internal/components/dropdown/__tests__/dropdown.test.tsx b/src/internal/components/dropdown/__tests__/dropdown.test.tsx index de788cd7e6..ab2c3165d1 100644 --- a/src/internal/components/dropdown/__tests__/dropdown.test.tsx +++ b/src/internal/components/dropdown/__tests__/dropdown.test.tsx @@ -5,6 +5,7 @@ import { act, fireEvent, render, screen } from '@testing-library/react'; import Dropdown from '../../../../../lib/components/internal/components/dropdown'; import { calculatePosition } from '../../../../../lib/components/internal/components/dropdown/dropdown-fit-handler'; +import customCssProps from '../../../../../lib/components/internal/generated/custom-css-properties'; import DropdownWrapper from '../../../../../lib/components/test-utils/dom/internal/dropdown'; const outsideId = 'outside'; @@ -192,6 +193,20 @@ describe('Dropdown Component', () => { expect(calculatePosition).toHaveBeenCalledTimes(0); }); }); + + describe('width CSS variables', () => { + test('passes through CSS string minWidth value', () => { + const [wrapper] = renderDropdown(} open={true} minWidth="300px" />); + const dropdown = wrapper.findOpenDropdown()!.getElement(); + expect(dropdown.style.getPropertyValue(customCssProps.dropdownDefaultMinWidth)).toBe('300px'); + }); + + test('passes through CSS string maxWidth value', () => { + const [wrapper] = renderDropdown(} open={true} maxWidth="250px" />); + const dropdown = wrapper.findOpenDropdown()!.getElement(); + expect(dropdown.style.getPropertyValue(customCssProps.dropdownDefaultMaxWidth)).toBe('250px'); + }); + }); }); /** From 01ad9b6dde25834c0a9509c9795de940e3723b39 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Thu, 12 Feb 2026 00:21:41 +0100 Subject: [PATCH 20/34] fix: use rendered with for dimensions --- src/internal/components/dropdown/dropdown-position.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/internal/components/dropdown/dropdown-position.ts b/src/internal/components/dropdown/dropdown-position.ts index 3ad3aaf2c0..e66a9e92fc 100644 --- a/src/internal/components/dropdown/dropdown-position.ts +++ b/src/internal/components/dropdown/dropdown-position.ts @@ -42,7 +42,10 @@ export function applyDropdownPositionRelativeToViewport({ dropdownElement.style.insetBlockStart = `${verticalScrollOffset + triggerRect.insetBlockEnd}px`; } if (position.dropInlineStart) { - dropdownElement.style.insetInlineStart = `calc(${horizontalScrollOffset + triggerRect.insetInlineEnd}px - ${position.inlineSize})`; + // For right-aligned dropdowns, use the actual rendered width when flexible width is enabled + // to ensure proper alignment even when CSS constraints differ from calculated inlineSize + const actualWidth = dropdownElement.getBoundingClientRect().width; + dropdownElement.style.insetInlineStart = `calc(${horizontalScrollOffset + triggerRect.insetInlineEnd}px - ${actualWidth}px)`; } else { dropdownElement.style.insetInlineStart = `${horizontalScrollOffset + triggerRect.insetInlineStart}px`; } From 966431d380223d905483783049bd4d35eb74defa Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Thu, 12 Feb 2026 00:33:28 +0100 Subject: [PATCH 21/34] chore: remove unused constraint --- src/internal/components/dropdown/dropdown-fit-handler.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/internal/components/dropdown/dropdown-fit-handler.ts b/src/internal/components/dropdown/dropdown-fit-handler.ts index 8f77c2c898..93abc6e660 100644 --- a/src/internal/components/dropdown/dropdown-fit-handler.ts +++ b/src/internal/components/dropdown/dropdown-fit-handler.ts @@ -170,15 +170,12 @@ const getWidths = ({ const { inlineSize: requiredWidth } = getLogicalBoundingClientRect(dropdownElement); // Calculate effective min/max widths - // 'max-content' uses the content's required width, undefined = no min constraint (0) const minWidth = minWidthConstraint === 'trigger' ? triggerInlineSize - : minWidthConstraint === 'max-content' - ? requiredWidth - : typeof minWidthConstraint === 'number' - ? minWidthConstraint - : 0; + : typeof minWidthConstraint === 'number' + ? minWidthConstraint + : 0; const maxWidth = maxWidthConstraint === 'trigger' From f324d2aef7cbb3be0dc0712be55bf420d2e8a8de Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Thu, 12 Feb 2026 00:43:08 +0100 Subject: [PATCH 22/34] refactor: simplify interface --- .../dropdown/__tests__/dropdown.test.tsx | 8 ++--- .../dropdown/dropdown-fit-handler.ts | 30 ++++++++++--------- src/internal/components/dropdown/index.tsx | 23 +++++--------- .../components/dropdown/interfaces.ts | 3 +- 4 files changed, 28 insertions(+), 36 deletions(-) diff --git a/src/internal/components/dropdown/__tests__/dropdown.test.tsx b/src/internal/components/dropdown/__tests__/dropdown.test.tsx index ab2c3165d1..321782f16e 100644 --- a/src/internal/components/dropdown/__tests__/dropdown.test.tsx +++ b/src/internal/components/dropdown/__tests__/dropdown.test.tsx @@ -195,14 +195,14 @@ describe('Dropdown Component', () => { }); describe('width CSS variables', () => { - test('passes through CSS string minWidth value', () => { - const [wrapper] = renderDropdown(} open={true} minWidth="300px" />); + test('applies numeric minWidth value as pixels', () => { + const [wrapper] = renderDropdown(} open={true} minWidth={300} />); const dropdown = wrapper.findOpenDropdown()!.getElement(); expect(dropdown.style.getPropertyValue(customCssProps.dropdownDefaultMinWidth)).toBe('300px'); }); - test('passes through CSS string maxWidth value', () => { - const [wrapper] = renderDropdown(} open={true} maxWidth="250px" />); + test('applies numeric maxWidth value as pixels', () => { + const [wrapper] = renderDropdown(} open={true} maxWidth={250} />); const dropdown = wrapper.findOpenDropdown()!.getElement(); expect(dropdown.style.getPropertyValue(customCssProps.dropdownDefaultMaxWidth)).toBe('250px'); }); diff --git a/src/internal/components/dropdown/dropdown-fit-handler.ts b/src/internal/components/dropdown/dropdown-fit-handler.ts index 93abc6e660..7b95f2f265 100644 --- a/src/internal/components/dropdown/dropdown-fit-handler.ts +++ b/src/internal/components/dropdown/dropdown-fit-handler.ts @@ -155,6 +155,20 @@ const getInteriorAvailableSpace = ({ ); }; +const resolveWidthConstraint = ( + constraint: DropdownWidthConstraint | undefined, + triggerWidth: number, + fallback: number +): number => { + if (constraint === 'trigger') { + return triggerWidth; + } + if (typeof constraint === 'number') { + return constraint; + } + return fallback; +}; + const getWidths = ({ triggerElement, dropdownElement, @@ -169,20 +183,8 @@ const getWidths = ({ const { inlineSize: triggerInlineSize } = getLogicalBoundingClientRect(triggerElement); const { inlineSize: requiredWidth } = getLogicalBoundingClientRect(dropdownElement); - // Calculate effective min/max widths - const minWidth = - minWidthConstraint === 'trigger' - ? triggerInlineSize - : typeof minWidthConstraint === 'number' - ? minWidthConstraint - : 0; - - const maxWidth = - maxWidthConstraint === 'trigger' - ? triggerInlineSize - : typeof maxWidthConstraint === 'number' - ? maxWidthConstraint - : Number.MAX_VALUE; // undefined = no max constraint + const minWidth = resolveWidthConstraint(minWidthConstraint, triggerInlineSize, 0); + const maxWidth = resolveWidthConstraint(maxWidthConstraint, triggerInlineSize, Number.MAX_VALUE); const idealWidth = Math.min(Math.max(requiredWidth, minWidth), maxWidth); return { idealWidth, minWidth, triggerInlineSize }; diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index ebd0bff8c0..97e66b3150 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -431,28 +431,19 @@ const Dropdown = ({ if (typeof minWidth === 'number') { return `${minWidth}px`; } - // 'trigger' is a special keyword that maps to 100% (relative to parent) - if (minWidth === 'trigger') { - return '100%'; - } - // Pass through any other CSS value as-is - return minWidth; + // 'trigger' maps to 100% (relative to parent) + return '100%'; }; const getMaxWidthCssValue = (): string | undefined => { - if (typeof maxWidth === 'number') { - return `${maxWidth}px`; - } - // 'trigger' is a special keyword that maps to 100% (relative to parent) - if (maxWidth === 'trigger') { - return '100%'; - } - // When maxWidth is undefined, allow dropdown to grow to content size if (maxWidth === undefined) { return 'none'; } - // Pass through any other CSS value as-is - return maxWidth; + if (typeof maxWidth === 'number') { + return `${maxWidth}px`; + } + // 'trigger' maps to 100% (relative to parent) + return '100%'; }; return ( diff --git a/src/internal/components/dropdown/interfaces.ts b/src/internal/components/dropdown/interfaces.ts index 4b9f34eab7..4fedaf1b62 100644 --- a/src/internal/components/dropdown/interfaces.ts +++ b/src/internal/components/dropdown/interfaces.ts @@ -9,10 +9,9 @@ export type OptionsFilteringType = 'none' | 'auto' | 'manual'; /** * Width constraint for the dropdown. * - 'trigger': references the trigger element's width - * - string: any valid CSS value (e.g., '100px', '50%', 'max-content') * - number: width in pixels */ -export type DropdownWidthConstraint = 'trigger' | string | number; +export type DropdownWidthConstraint = 'trigger' | number; export interface OptionsLoadItemsDetail { filteringText: string; From b22709c9225aa4ca77d6f16d7dbb800298fe5a59 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Thu, 12 Feb 2026 01:00:13 +0100 Subject: [PATCH 23/34] fix: remove condition --- src/internal/components/dropdown/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index 97e66b3150..074a90e024 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -223,8 +223,7 @@ const Dropdown = ({ // Only apply occupy-entire-width when matching trigger width exactly and not in portal mode if (!interior && matchTriggerWidth && !expandToViewport) { target.classList.add(styles['occupy-entire-width']); - } else if (!target.classList.contains(styles['use-flexible-width'])) { - // Only set inline-size if not using CSS class for flexible width + } else { target.style.inlineSize = position.inlineSize; } From 8871fee8461260bc93af56978ed0058610907fb5 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Thu, 12 Feb 2026 01:21:28 +0100 Subject: [PATCH 24/34] fix: remove border offset --- src/internal/components/dropdown/index.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index 074a90e024..3f2e3d2767 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -213,12 +213,7 @@ const Dropdown = ({ target: HTMLDivElement, verticalContainer: HTMLDivElement ) => { - if (!matchTriggerWidth) { - // 1px offset for dropdowns where the dropdown itself needs a border, rather than on the items - verticalContainer.style.maxBlockSize = `${parseInt(position.blockSize) + 1}px`; - } else { - verticalContainer.style.maxBlockSize = position.blockSize; - } + verticalContainer.style.maxBlockSize = position.blockSize; // Only apply occupy-entire-width when matching trigger width exactly and not in portal mode if (!interior && matchTriggerWidth && !expandToViewport) { From 62efd7cd10d08303aacaad8b76cc40772c559929 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Thu, 12 Feb 2026 11:04:42 +0100 Subject: [PATCH 25/34] chore: adapt integration test for changes --- src/internal/components/dropdown/__integ__/dropdown.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/internal/components/dropdown/__integ__/dropdown.test.ts b/src/internal/components/dropdown/__integ__/dropdown.test.ts index bdaaca4327..18bded9e48 100644 --- a/src/internal/components/dropdown/__integ__/dropdown.test.ts +++ b/src/internal/components/dropdown/__integ__/dropdown.test.ts @@ -79,7 +79,7 @@ describe('Dropdown', () => { }) ); test( - 'does nothing, if trigger width is smaller than the provided minWidth', + 'is respected even when larger than trigger width', setupTest('#/light/dropdown/min-width', 'minWidthDropdown', async page => { await page.setWindowSize({ width: 600, height: 600 }); // reopen the dropdown after the window got resized @@ -87,8 +87,8 @@ describe('Dropdown', () => { await page.click(page.getTrigger()); const { width: dropdownWidth } = await page.getBoundingBox(page.getOpenDropdown()); const { width: triggerWidth } = await page.getBoundingBox(page.getTrigger()); - expect(dropdownWidth).toBeLessThan(MIN_WIDTH); - expect(dropdownWidth).toBeLessThanOrEqual(triggerWidth); + expect(triggerWidth).toBeLessThan(MIN_WIDTH); + expect(dropdownWidth).toEqual(MIN_WIDTH); }) ); }); From 39258977bf7729104606953787ad81a8a8dbad48 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Thu, 12 Feb 2026 11:50:42 +0100 Subject: [PATCH 26/34] feat: introduce prop to hide block border --- src/internal/components/dropdown/index.tsx | 6 +++++- src/internal/components/dropdown/interfaces.ts | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index 3f2e3d2767..a3c1460dc2 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -65,6 +65,7 @@ interface TransitionContentProps { transitionRef: React.MutableRefObject; dropdownClasses: string; matchTriggerWidth: boolean; + hideBlockBorder: boolean; interior: boolean; isRefresh: boolean; dropdownRef: React.RefObject; @@ -90,6 +91,7 @@ const TransitionContent = ({ transitionRef, dropdownClasses, matchTriggerWidth, + hideBlockBorder, interior, isRefresh, dropdownRef, @@ -122,7 +124,7 @@ const TransitionContent = ({ className={clsx(styles.dropdown, dropdownClasses, { [styles.open]: open, [styles['with-limited-width']]: !matchTriggerWidth, - [styles['hide-block-border']]: matchTriggerWidth, + [styles['hide-block-border']]: hideBlockBorder, [styles.interior]: interior, [styles.refresh]: isRefresh, [styles['use-portal']]: expandToViewport && !interior, @@ -171,6 +173,7 @@ const Dropdown = ({ stretchHeight = false, minWidth, maxWidth, + hideBlockBorder = true, // eslint-disable-next-line @typescript-eslint/no-unused-vars stretchToTriggerWidth, // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -481,6 +484,7 @@ const Dropdown = ({ dropdownClasses={dropdownClasses} open={open} matchTriggerWidth={matchTriggerWidth} + hideBlockBorder={hideBlockBorder} interior={interior} header={header} content={content} diff --git a/src/internal/components/dropdown/interfaces.ts b/src/internal/components/dropdown/interfaces.ts index 4fedaf1b62..6859af70d1 100644 --- a/src/internal/components/dropdown/interfaces.ts +++ b/src/internal/components/dropdown/interfaces.ts @@ -134,6 +134,11 @@ export interface DropdownProps extends ExpandToViewport { */ preferCenter?: boolean; + /** + * Hides the block (top/bottom) borders of the dropdown content wrapper. + */ + hideBlockBorder?: boolean; + /** * Indicates if this dropdown lies within a parent dropdown and positions itself relative to it (as a fly out). */ From a8861706aaf9ce871e72f6efc3a1ddd4f9364951 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Thu, 12 Feb 2026 13:28:05 +0100 Subject: [PATCH 27/34] chore: remove unused props --- src/internal/components/dropdown/index.tsx | 4 ---- src/internal/components/dropdown/interfaces.ts | 15 --------------- 2 files changed, 19 deletions(-) diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index a3c1460dc2..733300fd71 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -174,10 +174,6 @@ const Dropdown = ({ minWidth, maxWidth, hideBlockBorder = true, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - stretchToTriggerWidth, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - stretchBeyondTriggerWidth, expandToViewport = false, preferCenter = false, interior = false, diff --git a/src/internal/components/dropdown/interfaces.ts b/src/internal/components/dropdown/interfaces.ts index 6859af70d1..32e8845703 100644 --- a/src/internal/components/dropdown/interfaces.ts +++ b/src/internal/components/dropdown/interfaces.ts @@ -113,21 +113,6 @@ export interface DropdownProps extends ExpandToViewport { */ maxWidth?: DropdownWidthConstraint; - /** - * Whether the dropdown content should be at least as wide as the trigger. - * - * @deprecated Use minWidth='trigger' instead - * @defaultValue true - */ - stretchToTriggerWidth?: boolean; - - /** - * Whether the dropdown content can grow beyond the width of the trigger. - * - * @deprecated Use maxWidth property instead. Leave maxWidth undefined to allow growth, or set maxWidth='trigger' to constrain to trigger width. - */ - stretchBeyondTriggerWidth?: boolean; - /** * Determines that the dropdown should preferably be aligned to the center of the trigger * instead of dropping left or right. From 06bdc08efb435d08e47ae420517fc15095cbbf2e Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Thu, 12 Feb 2026 14:02:47 +0100 Subject: [PATCH 28/34] fix: hide button dropdown block border --- src/button-dropdown/internal.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/button-dropdown/internal.tsx b/src/button-dropdown/internal.tsx index 173c7ab23f..a0f939602f 100644 --- a/src/button-dropdown/internal.tsx +++ b/src/button-dropdown/internal.tsx @@ -361,6 +361,7 @@ const InternalButtonDropdown = React.forwardRef( open={canBeOpened && isOpen} stretchTriggerHeight={variant === 'navigation'} minWidth={expandToViewport ? undefined : 'trigger'} + hideBlockBorder={true} expandToViewport={expandToViewport} preferCenter={preferCenter} onDropdownClose={() => toggleDropdown()} From adc343727eb0c85cfcc979ddcc500d814a782f91 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Thu, 12 Feb 2026 16:14:03 +0100 Subject: [PATCH 29/34] fix: add block border to button dropdown --- src/button-dropdown/internal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/button-dropdown/internal.tsx b/src/button-dropdown/internal.tsx index a0f939602f..cf3345105f 100644 --- a/src/button-dropdown/internal.tsx +++ b/src/button-dropdown/internal.tsx @@ -361,7 +361,7 @@ const InternalButtonDropdown = React.forwardRef( open={canBeOpened && isOpen} stretchTriggerHeight={variant === 'navigation'} minWidth={expandToViewport ? undefined : 'trigger'} - hideBlockBorder={true} + hideBlockBorder={false} expandToViewport={expandToViewport} preferCenter={preferCenter} onDropdownClose={() => toggleDropdown()} From 5987cd0d6c41d8b98d5e1d4668a5573508b010df Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Thu, 12 Feb 2026 16:41:40 +0100 Subject: [PATCH 30/34] retrigger checks From 0c8d124447570a2297133ac45221f6aad8a2ad29 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Thu, 12 Feb 2026 18:37:07 +0100 Subject: [PATCH 31/34] fix: hide border in internal button dropdown --- .../category-elements/expandable-category-element.tsx | 1 + src/internal/components/autosuggest-input/index.tsx | 2 +- src/multiselect/internal.tsx | 2 +- src/select/internal.tsx | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/button-dropdown/category-elements/expandable-category-element.tsx b/src/button-dropdown/category-elements/expandable-category-element.tsx index cdf4038102..682700b7f2 100644 --- a/src/button-dropdown/category-elements/expandable-category-element.tsx +++ b/src/button-dropdown/category-elements/expandable-category-element.tsx @@ -141,6 +141,7 @@ const ExpandableCategoryElement = ({ Date: Thu, 12 Feb 2026 18:43:35 +0100 Subject: [PATCH 32/34] chore: formatting --- src/internal/components/dropdown/interfaces.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/internal/components/dropdown/interfaces.ts b/src/internal/components/dropdown/interfaces.ts index 32e8845703..d4603738e3 100644 --- a/src/internal/components/dropdown/interfaces.ts +++ b/src/internal/components/dropdown/interfaces.ts @@ -55,38 +55,47 @@ export interface DropdownProps extends ExpandToViewport { * Trigger element. */ trigger: React.ReactNode; + /** * "Sticky" header of the dropdown content */ header?: React.ReactNode; + /** * Footer slot fixed at the bottom of the dropdown */ footer?: React.ReactNode; + /** * Dropdown content elements. */ content?: React.ReactNode; + /** * Updating content key triggers dropdown position re-evaluation. */ contentKey?: string; + /** * Open state of the dropdown. */ open?: boolean; + /** * Called when a user clicks outside of the dropdown content, when it is open. */ onDropdownClose?: NonCancelableEventHandler; + /** * Called when a mouse button is pressed inside the dropdown content. */ onMouseDown?: React.MouseEventHandler; + /** * Dropdown id */ dropdownId?: string; + /** * Stretches dropdown to occupy entire height. */ @@ -128,6 +137,7 @@ export interface DropdownProps extends ExpandToViewport { * Indicates if this dropdown lies within a parent dropdown and positions itself relative to it (as a fly out). */ interior?: boolean; + /** * Whether the dropdown will have a scrollbar or not */ @@ -152,14 +162,17 @@ export interface DropdownProps extends ExpandToViewport { * ID for the dropdown content wrapper */ dropdownContentId?: string; + /** * HTML role for the dropdown content wrapper */ dropdownContentRole?: string; + /** * Labelledby for the dropdown (required when role="dialog") */ ariaLabelledby?: string; + /** * Describedby for the dropdown (recommended when role="dialog") */ From 3b7b74927047ada51067f6670b96c5aa2cae7344 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Thu, 12 Feb 2026 18:47:33 +0100 Subject: [PATCH 33/34] refactor: remove redundant variable --- src/internal/components/dropdown/index.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index 733300fd71..d0b3806874 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -71,7 +71,6 @@ interface TransitionContentProps { dropdownRef: React.RefObject; verticalContainerRef: React.RefObject; expandToViewport?: boolean; - useFlexibleWidth?: boolean; minWidth?: string; maxWidth?: string; header?: React.ReactNode; @@ -97,7 +96,6 @@ const TransitionContent = ({ dropdownRef, verticalContainerRef, expandToViewport, - useFlexibleWidth, minWidth, maxWidth, header, @@ -128,7 +126,7 @@ const TransitionContent = ({ [styles.interior]: interior, [styles.refresh]: isRefresh, [styles['use-portal']]: expandToViewport && !interior, - [styles['use-flexible-width']]: useFlexibleWidth && !interior, + [styles['use-flexible-width']]: !matchTriggerWidth && !interior, })} ref={contentRef} id={id} @@ -412,9 +410,6 @@ const Dropdown = ({ const referrerId = useUniqueId(); - // Use flexible width sizing when not matching trigger width exactly - const useFlexibleWidth = !matchTriggerWidth; - // Compute CSS variable values for min/max width // These will be used by the use-flexible-width CSS class const getMinWidthCssValue = (): string | undefined => { @@ -485,7 +480,6 @@ const Dropdown = ({ header={header} content={content} expandToViewport={expandToViewport} - useFlexibleWidth={useFlexibleWidth} minWidth={getMinWidthCssValue()} maxWidth={getMaxWidthCssValue()} footer={footer} From 6adf26870b5ca9fbbfc16d93a4c45e48c29eafd6 Mon Sep 17 00:00:00 2001 From: Maximilian Schoell Date: Thu, 12 Feb 2026 21:30:40 +0100 Subject: [PATCH 34/34] refactor: rename dropdownContentRole to ariaRole --- src/internal/components/dropdown/index.tsx | 4 ++-- src/internal/components/dropdown/interfaces.ts | 2 +- src/multiselect/internal.tsx | 6 ++---- src/select/internal.tsx | 6 ++---- src/select/utils/use-select.ts | 7 ++----- 5 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/internal/components/dropdown/index.tsx b/src/internal/components/dropdown/index.tsx index d0b3806874..5ee9b28b01 100644 --- a/src/internal/components/dropdown/index.tsx +++ b/src/internal/components/dropdown/index.tsx @@ -181,7 +181,7 @@ const Dropdown = ({ onBlur, contentKey, dropdownContentId, - dropdownContentRole, + ariaRole, ariaLabelledby, ariaDescribedby, }: DropdownProps) => { @@ -489,7 +489,7 @@ const Dropdown = ({ verticalContainerRef={verticalContainerRef} position={position} id={dropdownContentId} - role={dropdownContentRole} + role={ariaRole} ariaLabelledby={ariaLabelledby} ariaDescribedby={ariaDescribedby} /> diff --git a/src/internal/components/dropdown/interfaces.ts b/src/internal/components/dropdown/interfaces.ts index d4603738e3..5acf2aacee 100644 --- a/src/internal/components/dropdown/interfaces.ts +++ b/src/internal/components/dropdown/interfaces.ts @@ -166,7 +166,7 @@ export interface DropdownProps extends ExpandToViewport { /** * HTML role for the dropdown content wrapper */ - dropdownContentRole?: string; + ariaRole?: string; /** * Labelledby for the dropdown (required when role="dialog") diff --git a/src/multiselect/internal.tsx b/src/multiselect/internal.tsx index 90329ace09..accf257535 100644 --- a/src/multiselect/internal.tsx +++ b/src/multiselect/internal.tsx @@ -163,10 +163,8 @@ const InternalMultiselect = React.forwardRef( > Pick< - DropdownProps, - 'onFocus' | 'onBlur' | 'dropdownContentId' | 'dropdownContentRole' - > = () => ({ + const getDropdownProps: () => Pick = () => ({ onFocus: handleFocus, onBlur: handleBlur, dropdownContentId: dialogId, - dropdownContentRole: hasFilter ? 'dialog' : undefined, + ariaRole: hasFilter ? 'dialog' : undefined, }); const getTriggerProps = (disabled = false, autoFocus = false) => {