Skip to content

Commit 291e6bc

Browse files
Gururajj77tay1orjonesmaradwan26
authored
refactor: radio button parity (#20418)
* refactor: radio button parity * refactor: added some more changes * fix: added some new things * fix: fixed story and readonly style apply * fix: modified styles for readonly instead of attribute switching * chore: comments cleanup and story formatting * chore: storybook spacing issue cleaned * fix: added ai label in overview docs * chore: added required attribute --------- Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com> Co-authored-by: Mahmoud <132728978+maradwan26@users.noreply.github.com>
1 parent 469bcdd commit 291e6bc

File tree

6 files changed

+102
-37
lines changed

6 files changed

+102
-37
lines changed

packages/react/src/components/RadioButton/RadioButton.stories.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,16 +190,19 @@ export const Default = (args) => {
190190
labelText="Radio button label"
191191
value="radio-1"
192192
id="radio-1"
193+
hideLabel={args.hideLabel}
193194
/>
194195
<RadioButton
195196
labelText="Radio button label"
196197
value="radio-2"
197198
id="radio-2"
199+
hideLabel={args.hideLabel}
198200
/>
199201
<RadioButton
200202
labelText="Radio button label"
201203
value="radio-3"
202204
id="radio-3"
205+
hideLabel={args.hideLabel}
203206
/>
204207
</RadioButtonGroup>
205208
);
@@ -208,6 +211,7 @@ export const Default = (args) => {
208211
Default.args = {
209212
defaultSelected: 'radio-2',
210213
helperText: 'Helper text',
214+
hideLabel: false,
211215
invalidText: 'Invalid selection',
212216
warn: false,
213217
warnText: 'Please notice the warning',
@@ -234,6 +238,13 @@ Default.argTypes = {
234238
type: 'text',
235239
},
236240
},
241+
hideLabel: {
242+
description:
243+
'Specify whether the label should be visually hidden but still available to screen readers',
244+
control: {
245+
type: 'boolean',
246+
},
247+
},
237248
invalid: {
238249
description: 'Specify whether the RadioButtonGroup is invalid',
239250
control: {

packages/web-components/src/components/radio-button/radio-button-group.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,22 @@ class CDSRadioButtonGroup extends FormMixin(HostListenerMixin(LitElement)) {
3939
@HostListener('eventChangeRadioButton')
4040
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- https://github.com/carbon-design-system/carbon/issues/20071
4141
// @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to
42-
private _handleAfterChangeRadioButton = () => {
42+
private _handleAfterChangeRadioButton = (event: CustomEvent) => {
43+
// Bail out early if readOnly
44+
if (this.readOnly) {
45+
return;
46+
}
47+
4348
const { selectorRadioButton } = this
4449
.constructor as typeof CDSRadioButtonGroup;
4550
const selected = find(
4651
this.querySelectorAll(selectorRadioButton),
4752
(elem) => (elem as CDSRadioButton).checked
4853
);
54+
4955
const oldValue = this.value;
5056
this.value = selected && selected.value;
57+
5158
if (oldValue !== this.value) {
5259
const { eventChange } = this.constructor as typeof CDSRadioButtonGroup;
5360
this.dispatchEvent(
@@ -56,6 +63,8 @@ class CDSRadioButtonGroup extends FormMixin(HostListenerMixin(LitElement)) {
5663
composed: true,
5764
detail: {
5865
value: this.value,
66+
name: this.name,
67+
event,
5968
},
6069
})
6170
);
@@ -174,6 +183,11 @@ class CDSRadioButtonGroup extends FormMixin(HostListenerMixin(LitElement)) {
174183
@property({ type: Boolean, reflect: true })
175184
readOnly = false;
176185

186+
/**
187+
* `true` to specify if input selection in group is required.
188+
*/
189+
@property({ type: Boolean, reflect: true })
190+
required = false;
177191
/**
178192
* The `value` attribute for the `<input>` for selection.
179193
*/
@@ -183,17 +197,22 @@ class CDSRadioButtonGroup extends FormMixin(HostListenerMixin(LitElement)) {
183197
updated(changedProperties) {
184198
const { selectorRadioButton } = this
185199
.constructor as typeof CDSRadioButtonGroup;
186-
['disabled', 'labelPosition', 'orientation', 'readOnly', 'name'].forEach(
187-
(name) => {
188-
if (changedProperties.has(name)) {
189-
const { [name as keyof CDSRadioButtonGroup]: value } = this;
190-
// Propagate the property to descendants until `:host-context()` gets supported in all major browsers
191-
forEach(this.querySelectorAll(selectorRadioButton), (elem) => {
192-
(elem as CDSRadioButton)[name] = value;
193-
});
194-
}
200+
[
201+
'disabled',
202+
'labelPosition',
203+
'orientation',
204+
'readOnly',
205+
'name',
206+
'required',
207+
].forEach((name) => {
208+
if (changedProperties.has(name)) {
209+
const { [name as keyof CDSRadioButtonGroup]: value } = this;
210+
// Propagate the property to descendants until `:host-context()` gets supported in all major browsers
211+
forEach(this.querySelectorAll(selectorRadioButton), (elem) => {
212+
(elem as CDSRadioButton)[name] = value;
213+
});
195214
}
196-
);
215+
});
197216
if (changedProperties.has('value')) {
198217
const { value } = this;
199218
forEach(this.querySelectorAll(selectorRadioButton), (elem) => {

packages/web-components/src/components/radio-button/radio-button.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import * as RadioButtonStories from './radio-button.stories';
1717
- [Overview](#overview)
1818
- [Vertical](#vertical)
1919
- [Skeleton](#skeleton)
20+
- [AI Label](#ai-label)
2021
- [Component API](#component-api)
2122
- [CDN](#cdn)
2223
- [Feedback](#feedback)

packages/web-components/src/components/radio-button/radio-button.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ $css--plex: true !default;
6868
margin-inline-end: 0;
6969
}
7070

71-
:host(#{$prefix}-radio-button[invalid]) .#{$prefix}--radio-button__appearance {
71+
:host(#{$prefix}-radio-button[invalid]:not([readOnly]))
72+
.#{$prefix}--radio-button__appearance {
7273
border-color: $support-error !important; /* stylelint-disable-line declaration-no-important */
7374
}
7475

packages/web-components/src/components/radio-button/radio-button.stories.ts

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ const args = {
7272
labelPosition: RADIO_BUTTON_LABEL_POSITION.RIGHT,
7373
orientation: RADIO_BUTTON_ORIENTATION.HORIZONTAL,
7474
name: 'radio-group',
75-
value: '',
75+
required: false,
76+
value: 'radio-2',
7677
warn: false,
7778
warnText: 'Please notice the warning',
7879
checked: false,
@@ -89,6 +90,10 @@ const argTypes = {
8990
control: 'boolean',
9091
description: 'read only (readOnly)',
9192
},
93+
required: {
94+
control: 'boolean',
95+
description: 'Required (required)',
96+
},
9297
helperText: {
9398
control: 'text',
9499
description: 'Helper text (helper-text)',
@@ -157,13 +162,14 @@ export const Default = {
157162
labelPosition,
158163
orientation,
159164
name,
160-
value,
165+
value = 'radio-2',
161166
warn,
162167
warnText,
163168
onChange,
164169
checked,
165170
hideLabel,
166171
labelText,
172+
required = false,
167173
} = args ?? {};
168174
return html`
169175
<cds-radio-button-group
@@ -177,6 +183,7 @@ export const Default = {
177183
orientation="${ifDefined(orientation)}"
178184
name="${ifDefined(name)}"
179185
value="${ifDefined(value)}"
186+
?required="${required}"
180187
?warn="${warn}"
181188
warn-text="${ifDefined(warnText)}"
182189
@cds-radio-button-group-changed="${onChange}">
@@ -238,9 +245,9 @@ export const WithAILabel = {
238245
name="radio-group"
239246
value="radio-1"
240247
orientation="vertical">
241-
<cds-ai-label alignment="bottom-left">
242-
${content}${actions}
243-
</cds-ai-label>
248+
<cds-ai-label alignment="bottom-left"
249+
>${content}${actions}</cds-ai-label
250+
>
244251
<cds-radio-button
245252
label-text="Radio button label"
246253
value="radio-1"></cds-radio-button>
@@ -257,16 +264,16 @@ export const WithAILabel = {
257264
name="radio-group-2"
258265
value="radio-4"
259266
orientation="vertical">
260-
<cds-radio-button label-text="Radio button label" value="radio-4">
261-
<cds-ai-label alignment="bottom-left">
262-
${content}${actions}
263-
</cds-ai-label>
264-
</cds-radio-button>
265-
<cds-radio-button label-text="Radio button label" value="radio-5">
266-
<cds-ai-label alignment="bottom-left">
267-
${content}${actions}
268-
</cds-ai-label>
269-
</cds-radio-button>
267+
<cds-radio-button label-text="Radio button label" value="radio-4"
268+
><cds-ai-label alignment="bottom-left"
269+
>${content}${actions}</cds-ai-label
270+
></cds-radio-button
271+
>
272+
<cds-radio-button label-text="Radio button label" value="radio-5"
273+
><cds-ai-label alignment="bottom-left"
274+
>${content}${actions}</cds-ai-label
275+
></cds-radio-button
276+
>
270277
<cds-radio-button
271278
label-text="Radio button label"
272279
value="radio-6"></cds-radio-button>
@@ -277,16 +284,16 @@ export const WithAILabel = {
277284
name="radio-group-3"
278285
value="radio-7"
279286
orientation="vertical">
280-
<cds-radio-button label-text="Radio button label" value="radio-7">
281-
<cds-ai-label slot="ai-label" alignment="bottom-left" kind="inline">
282-
${content}${actions}
283-
</cds-ai-label>
284-
</cds-radio-button>
285-
<cds-radio-button label-text="Radio button label" value="radio-8">
286-
<cds-ai-label slot="ai-label" alignment="bottom-left" kind="inline">
287-
${content}${actions}
288-
</cds-ai-label>
289-
</cds-radio-button>
287+
<cds-radio-button label-text="Radio button label" value="radio-7"
288+
><cds-ai-label slot="ai-label" alignment="bottom-left" kind="inline"
289+
>${content}${actions}</cds-ai-label
290+
></cds-radio-button
291+
>
292+
<cds-radio-button label-text="Radio button label" value="radio-8"
293+
><cds-ai-label slot="ai-label" alignment="bottom-left" kind="inline"
294+
>${content}${actions}</cds-ai-label
295+
></cds-radio-button
296+
>
290297
<cds-radio-button
291298
label-text="Radio button label"
292299
value="radio-9"></cds-radio-button>

packages/web-components/src/components/radio-button/radio-button.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ class RadioButtonDelegate implements ManagedRadioButtonDelegate {
7171
composed: true,
7272
detail: {
7373
checked,
74+
value: this._radio.value,
75+
name: this._radio.name,
7476
},
7577
})
7678
);
@@ -154,6 +156,9 @@ class CDSRadioButton extends HostListenerMixin(FocusMixin(LitElement)) {
154156
composed: true,
155157
detail: {
156158
checked: this.checked,
159+
value: this.value,
160+
name: this.name,
161+
event,
157162
},
158163
}
159164
)
@@ -167,6 +172,9 @@ class CDSRadioButton extends HostListenerMixin(FocusMixin(LitElement)) {
167172
composed: true,
168173
detail: {
169174
checked: this.checked,
175+
value: this.value,
176+
name: this.name,
177+
event,
170178
},
171179
}
172180
)
@@ -259,6 +267,12 @@ class CDSRadioButton extends HostListenerMixin(FocusMixin(LitElement)) {
259267
@property({ type: Boolean, reflect: true, attribute: 'data-table' })
260268
dataTable = false;
261269

270+
/**
271+
* Specify whether the `<radio-button>` should be checked by default
272+
*/
273+
@property({ type: Boolean, attribute: 'default-checked' })
274+
defaultChecked = false;
275+
262276
/**
263277
* `true` if the radio button item should be disabled.
264278
*/
@@ -313,6 +327,12 @@ class CDSRadioButton extends HostListenerMixin(FocusMixin(LitElement)) {
313327
@property({ type: Boolean, reflect: true })
314328
readOnly = false;
315329

330+
/**
331+
* `true` if the radio button is required.
332+
*/
333+
@property({ type: Boolean, reflect: true })
334+
required = false;
335+
316336
/**
317337
* The `value` attribute for the `<input>` for selection.
318338
*/
@@ -328,6 +348,11 @@ class CDSRadioButton extends HostListenerMixin(FocusMixin(LitElement)) {
328348

329349
firstUpdated() {
330350
this._radioButtonDelegate = new RadioButtonDelegate(this._inputNode);
351+
352+
// If user hasn’t explicitly set `checked`, respect `defaultChecked`
353+
if (this.defaultChecked && this.checked === false) {
354+
this.checked = true;
355+
}
331356
}
332357

333358
updated(changedProperties) {
@@ -395,6 +420,7 @@ class CDSRadioButton extends HostListenerMixin(FocusMixin(LitElement)) {
395420
class="${prefix}--radio-button"
396421
.checked=${checked}
397422
?disabled="${disabledItem || disabled}"
423+
?required=${this.required}
398424
name=${ifDefined(name)}
399425
value=${ifDefined(value)} />
400426
<label for="input" class="${prefix}--radio-button__label">

0 commit comments

Comments
 (0)