Reputation: 1454
I have a NuxtJS app where I want create a custom <Radio>
component.
I bind a CSS class dynamically so I can change the font-weight
of my radio button once it's selected.
After the initial load and on the first click on the button, you can see that the text changes slightly in size, a kind of "shrinking/growing" effect but it doesn't happen again afterwards, the transition is more fluid afterwards. Could this be due to the way computed properties work?
I made a video of it to make it clearer.
Inspiration drawn from Stephanie Eckles
<template>
<div :class="containerClasses">
<label :class="radioClasses">
<span class="radio__wrapper">
<input
:id="radioId"
class="radio__input"
type="radio"
:checked="shouldBeChecked"
:value="radioValue"
@change="updateRadio"
/>
<span class="radio__control"></span>
</span>
<span :for="radioId" class="radio__label">{{ radioLabel }}</span>
</label>
</div>
</template>
<script lang="ts">
import { defineComponent, toRefs, computed } from '@nuxtjs/composition-api';
export default defineComponent({
name: 'Radio',
model: {
prop: 'modelValue',
event: 'change',
},
props: {
id: {
type: String,
required: true,
},
label: {
type: String,
required: true,
},
value: {
type: String,
default: undefined,
},
modelValue: {
type: String,
default: '',
},
},
setup(props, { emit }) {
const { label, id, value, modelValue } = toRefs(props);
const updateRadio = () => {
emit('change', value.value);
};
const shouldBeChecked = computed(() => modelValue.value === value.value);
const containerClasses = computed(() => ({
container: true,
'container--active': shouldBeChecked.value,
}));
const radioClasses = computed(() => ({
radio: true,
'radio--active': shouldBeChecked.value,
}));
return {
radioLabel: label,
radioId: id,
radioValue: value,
shouldBeChecked,
updateRadio,
containerClasses,
radioClasses,
};
},
});
</script>
<style lang="scss" scoped>
.container {
--border-width: 1px;
position: relative;
border: solid var(--border-width) transparent;
border-radius: 16px;
background: $color-white;
background-clip: padding-box;
cursor: pointer;
&::before {
content: '';
position: absolute;
z-index: -1;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: calc(var(--border-width) * -1);
border-radius: inherit;
background: $color-dark-grey;
}
&--active {
&::before {
background: $gradient-blue-purple;
}
}
}
.radio {
display: grid;
grid-gap: 1.6rem;
grid-template-columns: min-content auto;
padding: 2rem $spacing-s;
font-size: $font-size-s;
&__wrapper {
display: flex;
}
&--active {
font-weight: $font-weight-medium;
}
&__input {
width: 0;
height: 0;
opacity: 0;
+ .radio__control::before {
content: '';
width: 1rem;
height: 1rem;
transform: scale(0);
transition: 180ms transform ease-in-out;
border-radius: 50%;
box-shadow: inset 0.5em 0.5em currentColor;
}
&:checked + .radio__control::before {
transform: scale(1);
}
}
&__control {
display: grid;
width: 2.4rem;
height: 2.4rem;
transform: translateY(-0.1em);
border: 1px solid currentColor;
place-items: center;
border-radius: 50%;
}
&__label {
display: flex;
align-items: center;
line-height: 1;
}
}
</style>
Upvotes: 1
Views: 217
Reputation: 1454
This lead me to the right direction along with this style adjustement to make it look right.
// Before
.radio {
display: grid;
grid-gap: 1.6rem;
}
// After
.radio {
display: flex;
gap: 1.6rem;
}
Upvotes: 1