I was looking for an OOTB solution for this myself, but out of luck. Just rolled my own.
Here you go.
HTML
<template>
<fieldset class="slds-form-element">
<legend class="slds-form-element__legend slds-form-element__label">{label}</legend>
<div class="slds-form-element__control">
<div class="slds-radio">
<table class="lwcir_radio_table">
<template for:each={referencedOptions} for:item="option" for:index="opt_index">
<tr key={option.id}>
<td>
<div class="lwcir_radio_input">
<input type="radio"
name={groupName}
id={option.id}
value={option.value}
checked={option.checked}
onchange={handleInputChange}
required={required} />
<label class="slds-radio__label" for={option.id}>
<span class="slds-radio_faux"></span>
<span class="slds-form-element__label">{option.label}</span>
</label>
</div>
</td>
<td if:true={option.hasHelp}>
<lightning-helptext content={option.help}></lightning-helptext>
</td>
</tr>
</template>
</table>
</div>
</div>
</fieldset>
Javascript
import {LightningElement, api, track} from 'lwc';
export default class LwcInputRadio extends LightningElement {
@api label;
@api groupName;
@api required = false;
@track selected;
referencedOptions;
@api
set options(ops) {
let asObject = [];
if (ops != null) {
if(typeof ops === "string") {
asObject = JSON.parse(ops);
} else {
//Must make copy of object before modifying due to LockerService.
asObject = JSON.parse(JSON.stringify(ops));
}
for (let i = 0; Array.isArray(asObject) && i < asObject.length; i++) {
asObject[i].id = asObject[i].value + "-" + i;
asObject[i].hasHelp = asObject[i]["help"] != null && asObject[i]["help"] !== "";
asObject[i].checked = false;
}
}
this.referencedOptions = asObject;
}
get options() {
return this.referencedOptions;
}
handleInputChange(event) {
this.selected = event.target.value;
this.referencedOptions.forEach(option => option.checked = option.value === this.selected);
this.dispatchChangeEvent();
}
dispatchChangeEvent() {
const changeEvent = new CustomEvent("delta", {
detail: {
value : this.selected,
}
});
this.dispatchEvent(changeEvent);
}
}
I'm using it from an aura component, but it would look something like this:
<aura:attribute name="myOptions" type="List" default="[
{'label': 'Option 1', 'value': 'VAL_1','help':'My help text for 1'},
{'label': 'Option 2', 'value': 'VAL_2','help':'My help text for 2'},
{'label': 'Option 3', 'value': 'VAL_3','help':'My help text for 3'},
]"/>
<c:lwc_Input_Radio
options="{!v.myOptions}"
label="Radio Options"
required="true"
ondelta="{!c.handleChangeEvent}"
groupName="myRadioGroup">
</c:lwc_Input_Radio>