frontend/src/components/common/RadioGroup.vue (90 lines of code) (raw):
<script setup lang="ts">
import { toRefs } from 'vue';
import Typography from '@/components/common/Typography.vue';
interface RadioGroupProps {
name: string;
items: {
value: string;
label: string;
}[];
modelValue?: any;
classes?: string;
}
const $emit = defineEmits(['update:modelValue']);
const props = defineProps<RadioGroupProps>();
const { name, classes, modelValue } = toRefs(props);
const onChange = (event: Event) => {
$emit('update:modelValue', (event.target as HTMLInputElement).value);
};
</script>
<template>
<div :class="classes">
<div class="radio" v-for="item in items" :key="item.value">
<input
type="radio"
:name="name"
:value="item.value"
:id="item.value"
:checked="modelValue === item.value"
@input="onChange"
/>
<label :for="item.value">
<Typography variant="bodyText" class="labelText">
{{ item.label }}
</Typography>
</label>
</div>
</div>
</template>
<style lang="scss" scoped>
.radio {
position: relative;
display: flex;
margin-top: 16px;
}
.radio:first-child {
margin-top: 0;
}
.radio label {
display: inline-flex;
align-items: center;
margin: 0;
}
.radio input[type='radio'] {
display: none;
}
.labelText {
display: inline;
}
.radio label:before {
content: ' ';
display: inline-block;
position: relative;
margin-right: 8px;
width: 24px;
height: 24px;
border-radius: 15px;
border: 2px solid $grey3;
background-color: transparent;
}
.radio input[type='radio']:checked + label:before {
border-color: $blue-main;
}
.radio input[type='radio']:checked + label:after {
border-radius: 11px;
width: 14px;
height: 14px;
position: absolute;
top: 5px;
left: 5px;
content: ' ';
display: block;
background: $blue-main;
}
.radio input[type='radio']:checked:hover + label:after {
background: $blue125;
}
.radio input[type='radio']:checked:hover + label:before {
border-color: $blue125;
}
</style>