From 6998082f2284b54b9ed13ba3cdcdcb02c1220e24 Mon Sep 17 00:00:00 2001 From: Joan Perals Tresserra Date: Fri, 7 Nov 2025 14:41:01 +0100 Subject: [PATCH 1/6] chore: Refactor radio button into internal component --- src/radio-group/internal.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/radio-group/internal.tsx b/src/radio-group/internal.tsx index 6f3485be98..f8682ba5dc 100644 --- a/src/radio-group/internal.tsx +++ b/src/radio-group/internal.tsx @@ -80,6 +80,7 @@ const InternalRadioGroup = React.forwardRef( controlId={item.controlId} readOnly={readOnly} style={style} + className={clsx(styles.radio, item.description && styles['radio--has-description'])} {...getAnalyticsMetadataAttribute( !item.disabled && !readOnly ? { From 572b57091121b2db45d6f3a272c1838b9c978c73 Mon Sep 17 00:00:00 2001 From: Joan Perals Tresserra Date: Tue, 30 Sep 2025 16:09:23 +0200 Subject: [PATCH 2/6] feat: Horizontal radio group --- pages/radio-group/common-permutations.tsx | 108 ++++++++++++++++++ .../horizontal.permutations.page.tsx | 57 +++++++++ pages/radio-group/permutations.page.tsx | 103 +---------------- .../__snapshots__/documenter.test.ts.snap | 14 +++ src/radio-group/index.tsx | 4 +- src/radio-group/interfaces.ts | 5 + src/radio-group/internal.tsx | 14 ++- src/radio-group/styles.scss | 21 +++- 8 files changed, 219 insertions(+), 107 deletions(-) create mode 100644 pages/radio-group/common-permutations.tsx create mode 100644 pages/radio-group/horizontal.permutations.page.tsx diff --git a/pages/radio-group/common-permutations.tsx b/pages/radio-group/common-permutations.tsx new file mode 100644 index 0000000000..3e9cc0994f --- /dev/null +++ b/pages/radio-group/common-permutations.tsx @@ -0,0 +1,108 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import React from 'react'; + +import Link from '~components/link'; +import { RadioGroupProps } from '~components/radio-group'; + +import createPermutations from '../utils/permutations'; + +const permutations = createPermutations([ + { + value: ['first'], + items: [ + [ + { value: 'first', label: 'First Button' }, + { value: 'second', label: 'Second Button' }, + { value: 'third', label: 'Third Button', disabled: true }, + ], + [ + { + value: 'first', + label: + 'Long text, long enough to wrap. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Whatever.', + }, + { + value: 'second', + label: + 'Long text, long enough to wrap. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Whatever.', + description: + 'Long text, long enough to wrap. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Whatever.', + }, + ], + ], + }, + { + value: ['second'], + items: [ + [ + { value: 'first', label: 'First Button', description: 'Short description' }, + { value: 'second', label: 'Second Button', description: 'Short description' }, + { value: 'third', label: 'Third Button', description: 'Short description' }, + ], + [ + { value: 'first', label: 'First Button', description: 'Short description', disabled: true }, + { value: 'second', label: 'Second Button', description: 'Short description' }, + { + value: 'third', + label: 'Description with link', + description: ( + <> + Long text,{' '} + + google + {' '} + long enough to wrap. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor + incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco + laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit + esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa + qui officia deserunt mollit anim id est laborum. Whatever. + + ), + }, + { + value: 'forth', + label: 'Description with icon', + description: ( + <> + Link at end of description{' '} + + learn more + + + ), + }, + { + value: 'fifth', + label: 'Long description with icon', + description: ( + <> + Icon in the middle of long description. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud + exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.{' '} + + learn more + {' '} + Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. + Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. + + ), + }, + ], + ], + }, + { + readOnly: [true], + value: ['first'], + items: [ + [ + { value: 'first', label: 'First Button' }, + { value: 'second', label: 'Second Button' }, + { value: 'third', label: 'Third Button', disabled: true }, + ], + ], + }, +]); + +export default permutations; diff --git a/pages/radio-group/horizontal.permutations.page.tsx b/pages/radio-group/horizontal.permutations.page.tsx new file mode 100644 index 0000000000..2c7f746589 --- /dev/null +++ b/pages/radio-group/horizontal.permutations.page.tsx @@ -0,0 +1,57 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import React from 'react'; + +import Box from '~components/box'; +import RadioGroup, { RadioGroupProps } from '~components/radio-group'; + +import createPermutations from '../utils/permutations'; +import PermutationsView from '../utils/permutations-view'; +import ScreenshotArea from '../utils/screenshot-area'; +import permutations from './common-permutations'; + +const extraPermutations = createPermutations([ + { + value: ['first'], + items: [ + [ + { value: 'first', label: 'First Button' }, + { value: 'second', label: 'Second Button' }, + { value: 'third', label: 'Third Button' }, + { value: 'fourth', label: 'Fourth Button' }, + { value: 'fifth', label: 'Fifth Button' }, + { value: 'sixth', label: 'Sixth Button' }, + { value: 'seventh', label: 'Seventh Button' }, + { value: 'eighth', label: 'Eighth Button' }, + { value: 'ninth', label: 'Ninth Button' }, + { value: 'tenth', label: 'Tenth Button' }, + { value: 'eleventh', label: 'Eleventh Button' }, + { value: 'twelfth', label: 'Twelfth Button' }, + ], + ], + }, +]); + +export default function HorizontalRadioGroupPermutations() { + return ( + <> +

RadioGroup horizontal permutations

+ + ( + + { + /*empty handler to suppress react controlled property warning*/ + }} + {...permutation} + /> + + )} + /> + + + ); +} diff --git a/pages/radio-group/permutations.page.tsx b/pages/radio-group/permutations.page.tsx index 6646b708be..34be6aef7d 100644 --- a/pages/radio-group/permutations.page.tsx +++ b/pages/radio-group/permutations.page.tsx @@ -2,110 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 import React from 'react'; -import Link from '~components/link'; -import RadioGroup, { RadioGroupProps } from '~components/radio-group'; +import RadioGroup from '~components/radio-group'; -import createPermutations from '../utils/permutations'; import PermutationsView from '../utils/permutations-view'; import ScreenshotArea from '../utils/screenshot-area'; - -const permutations = createPermutations([ - { - value: ['first'], - items: [ - [ - { value: 'first', label: 'First Button' }, - { value: 'second', label: 'Second Button' }, - { value: 'third', label: 'Third Button', disabled: true }, - ], - [ - { - value: 'first', - label: - 'Long text, long enough to wrap. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Whatever.', - }, - { - value: 'second', - label: - 'Long text, long enough to wrap. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Whatever.', - description: - 'Long text, long enough to wrap. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Whatever.', - }, - ], - ], - }, - { - value: ['second'], - items: [ - [ - { value: 'first', label: 'First Button', description: 'Short description' }, - { value: 'second', label: 'Second Button', description: 'Short description' }, - { value: 'third', label: 'Third Button', description: 'Short description' }, - ], - [ - { value: 'first', label: 'First Button', description: 'Short description', disabled: true }, - { value: 'second', label: 'Second Button', description: 'Short description' }, - { - value: 'third', - label: 'Description with link', - description: ( - <> - Long text,{' '} - - google - {' '} - long enough to wrap. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor - incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco - laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit - esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa - qui officia deserunt mollit anim id est laborum. Whatever. - - ), - }, - { - value: 'forth', - label: 'Description with icon', - description: ( - <> - Link at end of description{' '} - - learn more - - - ), - }, - { - value: 'fifth', - label: 'Long description with icon', - description: ( - <> - Icon in the middle of long description. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do - eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud - exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.{' '} - - learn more - {' '} - Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. - Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. - - ), - }, - ], - ], - }, - { - readOnly: [true], - value: ['first'], - items: [ - [ - { value: 'first', label: 'First Button' }, - { value: 'second', label: 'Second Button' }, - { value: 'third', label: 'Third Button', disabled: true }, - ], - ], - }, -]); +import permutations from './common-permutations'; export default function RadioGroupPermutations() { return ( diff --git a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap index c0c8d4991e..b8c022f0fa 100644 --- a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap +++ b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap @@ -20313,6 +20313,20 @@ is provided by its parent form field component.", "optional": true, "type": "string", }, + { + "description": "Defines the direction in which the radio buttons are laid out.", + "inlineType": { + "name": ""horizontal" | "vertical"", + "type": "union", + "values": [ + "horizontal", + "vertical", + ], + }, + "name": "direction", + "optional": true, + "type": "string", + }, { "deprecatedTag": "The usage of the \`id\` attribute is reserved for internal use cases. For testing and other use cases, use [data attributes](https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes). If you must diff --git a/src/radio-group/index.tsx b/src/radio-group/index.tsx index 13f0762a3c..cb91d71e38 100644 --- a/src/radio-group/index.tsx +++ b/src/radio-group/index.tsx @@ -16,7 +16,9 @@ import analyticsSelectors from './analytics-metadata/styles.css.js'; export { RadioGroupProps }; const RadioGroup = React.forwardRef((props: RadioGroupProps, ref: React.Ref) => { - const baseComponentProps = useBaseComponent('RadioGroup', { props: { readOnly: props.readOnly } }); + const baseComponentProps = useBaseComponent('RadioGroup', { + props: { readOnly: props.readOnly, direction: props.direction ?? 'vertical' }, + }); return ( @@ -54,7 +55,12 @@ const InternalRadioGroup = React.forwardRef( aria-controls={ariaControls} aria-readonly={readOnly ? 'true' : undefined} {...baseProps} - className={clsx(baseProps.className, testUtilStyles.root, styles['radio-group'])} + className={clsx( + baseProps.className, + testUtilStyles.root, + styles['radio-group'], + direction === 'horizontal' && styles['horizontal-group'] + )} ref={__internalRootRef} > {items && @@ -80,7 +86,11 @@ const InternalRadioGroup = React.forwardRef( controlId={item.controlId} readOnly={readOnly} style={style} - className={clsx(styles.radio, item.description && styles['radio--has-description'])} + className={clsx( + styles.radio, + item.description && styles['radio--has-description'], + direction === 'horizontal' && styles.horizontal + )} {...getAnalyticsMetadataAttribute( !item.disabled && !readOnly ? { diff --git a/src/radio-group/styles.scss b/src/radio-group/styles.scss index 8d970f6558..17e1dcaf55 100644 --- a/src/radio-group/styles.scss +++ b/src/radio-group/styles.scss @@ -8,13 +8,28 @@ .radio-group { @include styles.styles-reset; - display: block; + + &:not(.horizontal-group) { + display: block; + } + + &.horizontal-group { + display: flex; + align-items: start; + flex-wrap: wrap; + gap: awsui.$space-scaled-l; + } } -.radio + .radio { +.radio + .radio:not(.horizontal) { margin-block-start: awsui.$space-scaled-xxs; } -.radio--has-description + .radio { +.radio--has-description + .radio:not(.horizontal) { margin-block-start: awsui.$space-scaled-xs; } + +.radio.horizontal { + // Approximately 80 characters, which is the usually recommended maximum to keep columns readable. + max-inline-size: 40em; +} From 3e45c444df6bdb9709096c863760331a5c72c3ce Mon Sep 17 00:00:00 2001 From: Joan Perals Tresserra Date: Tue, 30 Sep 2025 18:10:48 +0200 Subject: [PATCH 3/6] Add dividers --- .../horizontal.permutations.page.tsx | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/pages/radio-group/horizontal.permutations.page.tsx b/pages/radio-group/horizontal.permutations.page.tsx index 2c7f746589..1f71257653 100644 --- a/pages/radio-group/horizontal.permutations.page.tsx +++ b/pages/radio-group/horizontal.permutations.page.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 import React from 'react'; -import Box from '~components/box'; import RadioGroup, { RadioGroupProps } from '~components/radio-group'; import createPermutations from '../utils/permutations'; @@ -40,15 +39,17 @@ export default function HorizontalRadioGroupPermutations() { ( - - { - /*empty handler to suppress react controlled property warning*/ - }} - {...permutation} - /> - + <> +
+ { + /*empty handler to suppress react controlled property warning*/ + }} + {...permutation} + /> +
+ )} /> From 988a995016876896499d6e8cc5d1e8194d4b9970 Mon Sep 17 00:00:00 2001 From: Joan Perals Tresserra Date: Fri, 7 Nov 2025 16:11:09 +0100 Subject: [PATCH 4/6] Add maximum width --- src/radio-group/styles.scss | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/radio-group/styles.scss b/src/radio-group/styles.scss index 17e1dcaf55..5a0e629af6 100644 --- a/src/radio-group/styles.scss +++ b/src/radio-group/styles.scss @@ -30,6 +30,7 @@ } .radio.horizontal { - // Approximately 80 characters, which is the usually recommended maximum to keep columns readable. - max-inline-size: 40em; + // Leaves approximately up to 80 characters for the description before wrapping. + // This is the usually recommended maximum to keep text columns readable. + max-inline-size: calc(16 * #{awsui.$space-scaled-xxl}); } From f589b3b17786087a448eef1d2158e51b38354381 Mon Sep 17 00:00:00 2001 From: Joan Perals Tresserra Date: Fri, 7 Nov 2025 16:11:29 +0100 Subject: [PATCH 5/6] Revert "Add dividers" This reverts commit 99eb7f063b09a410edc0e0372616e05c859edbd1. --- .../horizontal.permutations.page.tsx | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/pages/radio-group/horizontal.permutations.page.tsx b/pages/radio-group/horizontal.permutations.page.tsx index 1f71257653..2c7f746589 100644 --- a/pages/radio-group/horizontal.permutations.page.tsx +++ b/pages/radio-group/horizontal.permutations.page.tsx @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import React from 'react'; +import Box from '~components/box'; import RadioGroup, { RadioGroupProps } from '~components/radio-group'; import createPermutations from '../utils/permutations'; @@ -39,17 +40,15 @@ export default function HorizontalRadioGroupPermutations() { ( - <> -
- { - /*empty handler to suppress react controlled property warning*/ - }} - {...permutation} - /> -
- + + { + /*empty handler to suppress react controlled property warning*/ + }} + {...permutation} + /> + )} /> From 8d7a83b359242b30290569e69121708a037a84d1 Mon Sep 17 00:00:00 2001 From: Joan Perals Tresserra Date: Thu, 13 Nov 2025 18:32:05 +0100 Subject: [PATCH 6/6] fix duplicated prop --- src/radio-group/internal.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/radio-group/internal.tsx b/src/radio-group/internal.tsx index 60dd8a89ba..6a07bd36dc 100644 --- a/src/radio-group/internal.tsx +++ b/src/radio-group/internal.tsx @@ -71,6 +71,7 @@ const InternalRadioGroup = React.forwardRef( className={clsx( styles.radio, item.description && styles['radio--has-description'], + direction === 'horizontal' && styles.horizontal, item.value === value && analyticsSelectors.selected )} checked={item.value === value} @@ -86,11 +87,6 @@ const InternalRadioGroup = React.forwardRef( controlId={item.controlId} readOnly={readOnly} style={style} - className={clsx( - styles.radio, - item.description && styles['radio--has-description'], - direction === 'horizontal' && styles.horizontal - )} {...getAnalyticsMetadataAttribute( !item.disabled && !readOnly ? {