You can use the SLDS Form styling, to imitate the default record form in Salesforce and just add a new form row for each input and the whole thing will look authentic. In this context, removing label from the second radio group will do the thing and you don't have to use additional tricks to fix spacing around them.
On the other hand, you can use grid, as in the original question. To fix your problem with empty space above the second group, just add an empty label above it and hide with the slds-hidden
class. It will allign everything as needed.
<template>
<div class="slds-card slds-p-around_medium">
<!-- #1 form variant -->
<div class="slds-text-title_caps">#1 form variant</div>
<div class="slds-form" role="list">
<div class="slds-form__row">
<div class="slds-form__item" role="listitem">
<div class="slds-form-element slds-form-element_horizontal slds-is-editing">
<lightning-radio-group name="group" label="Group 1" options={options1} onchange={handleOptions}
type="radio">
</lightning-radio-group>
</div>
</div>
<div class="slds-form__item" role="listitem">
<div class="slds-form-element slds-form-element_horizontal slds-is-editing">
<lightning-radio-group name="group" label="Group 2" options={options2} onchange={handleOptions}
type="radio" variant="label-hidden">
</lightning-radio-group>
</div>
</div>
</div>
</div>
<!-- #2 grid variant -->
<div class="slds-text-title_caps">#2 grid variant</div>
<div class="slds-grid">
<div class="slds-col">
<lightning-radio-group name="group" label="Group 1" options={options1} onchange={handleOptions}
type="radio">
</lightning-radio-group>
</div>
<div class="slds-col">
<label class="slds-form-element__label slds-hidden">Form label</label>
<lightning-radio-group name="group" label="Group 2" options={options2} onchange={handleOptions}
variant="label-hidden" type="radio">
</lightning-radio-group>
</div>
</div>
</div>
</template>
Demo
UPDATE
Following our conversation in comments chat of this answer, we came to trying the approach of using static resource that contains styling override for the lightning-radio-group component. Instead of dividing the single group into two or more and maintaining duplicate code, we can use a single group but divide it into 2 columns using styling overrides. Static resource is used because LWC doesn't support inheritance of parent's LWC styling because of the shadow dom. There are some tricks with slot but not in our case since it's a standard component.
How to create static resource using sfdx
If you will make changes to your static resource's styling, don't forget to do hard reload of the page, because the old css will be cached and you won't see new changes.
Update your component with this code:
html
<template>
<div class="slds-card slds-p-around_medium">
<lightning-spinner if:true={isLoading} size="medium" variant="brand" alternative-text="Loading">
</lightning-spinner>
<div class="slds-p-bottom_medium">
<span class="slds-text-title_bold">Selected Option:</span> {selectedOption}
</div>
<div if:false={isLoading}>
<lightning-radio-group class="two-columns" name="group1" label="Group 1"
options={options} onchange={handleChange} type="radio">
</lightning-radio-group>
</div>
</div>
</template>
js
also added spinner to show while css is being loaded to not show user how elements jump all over the screen during rendering
how to load styling from css
import { LightningElement } from "lwc";
import { loadStyle } from "lightning/platformResourceLoader";
import CustomStyling from "@salesforce/resourceUrl/CustomStyling";
export default class TwoColumnsRadioButtons extends LightningElement {
isLoading = true;
selectedOption = "None";
connectedCallback() {
Promise.all([loadStyle(this, CustomStyling + "/overrides.css")]).then(
() => {
this.isLoading = false;
}
);
}
get options() {
return [
{ label: "Option 1", value: "Option 1" },
{ label: "Option 2", value: "Option 2" },
{ label: "Option 3", value: "Option 3" },
{ label: "Option 4", value: "Option 4" },
{ label: "Option 5", value: "Option 5" }
];
}
handleChange(event) {
try {
this.selectedOption = event.detail.value;
} catch (error) {
console.error(error);
}
}
}
staticresource/override.css
I added the two-columns
class to apply the overrides only for certain elements and not all radio button groups, since this css file will be loaded for the whole page.
lightning-radio-group.two-columns .slds-form-element__control {
display: flex;
flex-wrap: wrap;
}
lightning-radio-group.two-columns .slds-radio {
width: calc(100% / 2); /* divide by the number of columns you want to see */
}
Updated demo and how calc(100% / 2) works