Skip to content

Radio

INFO

This page has not yet been updated to use the defineModel macro, which was added in Vue 3.4. The techniques described here should still work, but in some cases it might be better to use defineModel instead.

Radio Examples

We're going to look at two examples of a radio component. The first example wraps a native <input> element to create the radio button. The second example uses CSS to give the impression of a radio button without using an <input>.

In both cases the example usage is much the same:

vue
<template>
  <basic-radio v-model="radioValue" value="First" />
  <basic-radio v-model="radioValue" value="Second" />
  <basic-radio v-model="radioValue" value="Third" />
  <pre>Bound value: {{ radioValue }}</pre>
</template>

<script setup>
import { ref } from 'vue'
import BasicRadio from './radio.vue'

const radioValue = ref('First')
</script>
<template>
  <basic-radio v-model="radioValue" value="First" />
  <basic-radio v-model="radioValue" value="Second" />
  <basic-radio v-model="radioValue" value="Third" />
  <pre>Bound value: {{ radioValue }}</pre>
</template>

<script setup>
import { ref } from 'vue'
import BasicRadio from './radio.vue'

const radioValue = ref('First')
</script>

Radio with <input>

Live Example
Bound value: First

SFC Playground

vue
<template>
  <div>
    <input type="radio" v-model="radioModel" :value="value">
  </div>
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps({
  modelValue: {
    required: true
  },
  value: {
    required: true
  }
})

const emit = defineEmits(['update:modelValue'])

const radioModel = computed({
  get () {
    return props.modelValue
  },
  set (newChecked) {
    emit('update:modelValue', newChecked)
  }
})
</script>
<template>
  <div>
    <input type="radio" v-model="radioModel" :value="value">
  </div>
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps({
  modelValue: {
    required: true
  },
  value: {
    required: true
  }
})

const emit = defineEmits(['update:modelValue'])

const radioModel = computed({
  get () {
    return props.modelValue
  },
  set (newChecked) {
    emit('update:modelValue', newChecked)
  }
})
</script>

Radio without <input>

Live Example
Bound value: First

SFC Playground

vue
<template>
  <div>
    <div class="box" :class="{ checked }" @click="select" />
  </div>
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps({
  modelValue: {
    required: true
  },
  value: {
    required: true
  }
})

const emit = defineEmits(['update:modelValue'])

const checked = computed(() => props.value === props.modelValue)

const select = () => {
  if (!checked.value) {
    emit('update:modelValue', props.value)
  }
}
</script>

<style scoped>
.box {
  border: 1px solid #999;
  border-radius: 8px;
  height: 16px;
  width: 16px;
}

.checked::before {
  background: #00c;
  border-radius: 5px;
  content: '';
  display: block;
  height: 10px;
  margin: 2px;
  width: 10px;
}
</style>
<template>
  <div>
    <div class="box" :class="{ checked }" @click="select" />
  </div>
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps({
  modelValue: {
    required: true
  },
  value: {
    required: true
  }
})

const emit = defineEmits(['update:modelValue'])

const checked = computed(() => props.value === props.modelValue)

const select = () => {
  if (!checked.value) {
    emit('update:modelValue', props.value)
  }
}
</script>

<style scoped>
.box {
  border: 1px solid #999;
  border-radius: 8px;
  height: 16px;
  width: 16px;
}

.checked::before {
  background: #00c;
  border-radius: 5px;
  content: '';
  display: block;
  height: 10px;
  margin: 2px;
  width: 10px;
}
</style>

Libraries

Various libraries include a radio component, including: