From 0c6060eae799d65892ea51945e9c91ffa0710fe3 Mon Sep 17 00:00:00 2001 From: Jeremiah Hoyet <jerhoyet@gmail.com> Date: Mon, 22 Nov 2021 12:33:39 -0500 Subject: [PATCH] Add required attribute to radio group and radio --- docs/components/radio-group.md | 44 +++++++++++++++++++++++ src/components/radio-group/radio-group.ts | 23 ++++++++++++ src/components/radio/radio.ts | 4 +++ 3 files changed, 71 insertions(+) diff --git a/docs/components/radio-group.md b/docs/components/radio-group.md index 0f784721..e879eb85 100644 --- a/docs/components/radio-group.md +++ b/docs/components/radio-group.md @@ -49,4 +49,48 @@ const App = () => ( </SlRadioGroup> ); ``` + +### Using the required attribute + +Adding a `required` attribute to `sl-radio-group` will require at least one option to be selected. + +```html preview +<sl-radio-group id="radio-group1" label="Select an option" fieldset required> + <sl-radio value="1" name="foo">Option 1</sl-radio> + <sl-radio value="2" name="foo">Option 2</sl-radio> + <sl-radio value="3" name="foo">Option 3</sl-radio> +</sl-radio-group> + +<br /> + +<sl-button id="group1">Validate Group</sl-button> + +<script> + const button = document.getElementById('group1'); + const group = document.getElementById('radio-group1'); + + button.addEventListener('click', ()=> group.reportValidity()) +</script> +``` + +Alternatively, if any of the `sl-radio` elements has a `required` attribute, `sl-radio-group` mimics the behaviour of the browser and will require at least one selection from the group. + +```html preview +<sl-radio-group id="radio-group2" label="Select an option" fieldset> + <sl-radio value="1" name="foo" required>Option 1</sl-radio> + <sl-radio value="2" name="foo">Option 2</sl-radio> + <sl-radio value="3" name="foo">Option 3</sl-radio> +</sl-radio-group> + +<br /> + +<sl-button id="group2">Validate Group</sl-button> + +<script> + const button = document.getElementById('group2'); + const group = document.getElementById('radio-group2'); + + button.addEventListener('click', ()=> group.reportValidity()) +</script> +``` [component-metadata:sl-radio-group] diff --git a/src/components/radio-group/radio-group.ts b/src/components/radio-group/radio-group.ts index f306ac82..a444471d 100644 --- a/src/components/radio-group/radio-group.ts +++ b/src/components/radio-group/radio-group.ts @@ -26,6 +26,9 @@ export default class SlRadioGroup extends LitElement { /** Shows the fieldset and legend that surrounds the radio group. */ @property({ type: Boolean, attribute: 'fieldset' }) fieldset = false; + /** Indicates that a selection is required. */ + @property({ type: Boolean, reflect: true }) required = false; + handleFocusIn() { // When tabbing into the fieldset, make sure it lands on the checked radio requestAnimationFrame(() => { @@ -39,6 +42,26 @@ export default class SlRadioGroup extends LitElement { }); } + reportValidity() { + const radios = [...(this.defaultSlot.assignedElements({ flatten: true }) as SlRadio[])]; + let isChecked = true; + + // Set required to true if any of the radio elements are required + this.required = this.required || radios.some(el => el.required); + + if (this.required && radios.length > 0) { + isChecked = radios.some(el => el.checked); + + if (!isChecked) { + radios[0].required = true; + // Trigger validity message on first input + radios[0].reportValidity(); + } + } + + return isChecked; + } + render() { return html` <fieldset diff --git a/src/components/radio/radio.ts b/src/components/radio/radio.ts index 79690c20..916d200d 100644 --- a/src/components/radio/radio.ts +++ b/src/components/radio/radio.ts @@ -47,6 +47,9 @@ export default class SlRadio extends LitElement { /** Draws the radio in a checked state. */ @property({ type: Boolean, reflect: true }) checked = false; + /** Indicates that a selection is required. */ + @property({ type: Boolean, reflect: true }) required = false; + /** * This will be true when the control is in an invalid state. Validity in range inputs is determined by the message * provided by the `setCustomValidity` method. @@ -161,6 +164,7 @@ export default class SlRadio extends LitElement { type="radio" name=${ifDefined(this.name)} value=${ifDefined(this.value)} + ?required=${this.required} .checked=${live(this.checked)} .disabled=${this.disabled} aria-checked=${this.checked ? 'true' : 'false'}