Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

aarontharker's avatar

Accessing template refs in <script setup>

I have a list of answers to a question and I know how to change the class on the option that is clicked but if they select the wrong answer I want to highlight the correct one. So I set a template ref on the list

<div class="neumorph-1 option option-default" v-for="(value, index) in curQuestion.answers" :key="index" ref="options">                        
  <div class="rounded-lg font-bold flex p-2" @click="scoreQuestion(index, value.score)">
      <!-- option ID -->
      <div class="p-3 rounded-lg">{{ index+1 }}</div>

      <!-- option name -->
      <div class="flex items-center pl-6">{{ value.answer }}</div>
  </div>
</div>

and defined the ref in my script

<script setup>
import { ref, onMounted } from 'vue';
const options = ref(null);

const scoreQuestion = function(index, curScore) {
  score.value = score.value + curQuestion.value.score * curScore/100
  options[index].classList.remove("option-default")
  if (curScore > 0) {
    options[index].classList.add("option-correct")
  } else {
    options[index].classList.add("option-wrong")
  }
}
</script>

but options[index] is coming up as undefined even though in Vue Tools I can clearly see the options array. Any suggestions?

0 likes
4 replies
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

It looks like you're trying to use the ref attribute within a v-for loop, which won't work as you might expect because ref inside a v-for will result in an array of elements being assigned to the ref, not a single element. However, in the Vue 3 Composition API with <script setup>, you need to use a function to access the refs when they are inside a loop.

Here's how you can modify your code to work with refs inside a v-for:

<template>
  <div v-for="(value, index) in curQuestion.answers" :key="index" 
       :ref="el => { if (el) options[index] = el }" 
       class="neumorph-1 option option-default">
    <div class="rounded-lg font-bold flex p-2" @click="scoreQuestion(index, value.score)">
      <!-- option ID -->
      <div class="p-3 rounded-lg">{{ index+1 }}</div>

      <!-- option name -->
      <div class="flex items-center pl-6">{{ value.answer }}</div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue';

const curQuestion = reactive({
  answers: [
    // ... your answers here
  ]
});

const options = reactive({});
const score = ref(0);

const scoreQuestion = function(index, curScore) {
  score.value = score.value + curQuestion.answers[index].score * curScore / 100;
  const optionElement = options[index];
  optionElement.classList.remove("option-default");
  if (curScore > 0) {
    optionElement.classList.add("option-correct");
  } else {
    optionElement.classList.add("option-wrong");
  }
}
</script>

In this solution, we use a function :ref="el => { if (el) options[index] = el }" to assign the DOM element to the options object at the correct index. This way, each option element is stored in the options object, and you can access it using the index in your scoreQuestion function.

Please note that I've used reactive for options instead of ref because we are dealing with an object that will have multiple properties (one for each option element). Also, ensure that curQuestion.answers is properly reactive, so changes to it will be reflected in the template. If curQuestion is a prop or comes from a store, you might need to handle it differently.

1 like
gych's avatar

When you use a ref you have to use .value in your script to get or set the value of the ref.

const scoreQuestion = function(index, curScore) {
  score.value = score.value + curQuestion.value.score * curScore/100
  options.value[index].classList.remove("option-default")
  if (curScore > 0) {
    options.value[index].classList.add("option-correct")
  } else {
    options.value[index].classList.add("option-wrong")
  }
}
aarontharker's avatar

@gych The AI's way of doing it works so I've gone with that :) with regards to the value attribute though, that is automatically unwrapped when used in the template or a this. reference isn't it?

gych's avatar

@aarontharker Yes when using options in the template you don't have to use the value attribute.

When using reactive instead of ref you also don't need to use the value attribute. Personally I mostly use ref but reactive will have the same results, ref uses reactive under the hood.

Please or to participate in this conversation.