# How to Customize OTP Input Styling with Conditional Classes per Input in Vue 3

> Customize OTP input styling in Vue 3 using conditional classes per input. Easily apply unique styles to each digit position with the vue3-otp-input component's conditionalClass prop.

- Repository: [Ejiro Asiuwhu/vue3-otp-input](https://github.com/ejirocodes/vue3-otp-input)
- Tags: how-to-guide
- Published: 2026-03-01

---

**Use the `conditionalClass` prop on the `vue3-otp-input` component to pass an array of class names—one per input box—allowing distinct styling for each OTP digit position.**

The `vue3-otp-input` library provides a flexible way to build one-time password forms in Vue 3. To customize OTP input styling with conditional classes per input in Vue 3, the component exposes a `conditionalClass` prop that accepts an array of strings mapped to each individual input box.

## How the conditionalClass Prop Works

The implementation spans two core components. The root `vue3-otp-input` component validates and forwards the class array, while the child `SingleOtpInput` applies the specific class to its rendered `<input>` element.

### Prop Definition in the Root Component

In [`src/components/vue3-otp-input.vue`](https://github.com/ejirocodes/vue3-otp-input/blob/main/src/components/vue3-otp-input.vue), the component defines `conditionalClass` as an optional prop expecting an array of strings. The array length must match the `numInputs` prop to ensure every OTP box receives a class definition:

```typescript
// src/components/vue3-otp-input.vue (lines 15-18)
props: {
  conditionalClass: {
    type: Array as PropType<string[]>,
    default: [],
  },
  // ...
}

```

### Forwarding Classes to Individual Inputs

The root component iterates over the `numInputs` range and passes the corresponding array index to each child. It uses optional chaining to safely handle cases where `conditionalClass` is undefined:

```vue
<!-- src/components/vue3-otp-input.vue (lines 38-40) -->
<SingleOtpInput
  v-for="(item, i) in numInputs"
  :key="i"
  :conditionalClass="conditionalClass?.[i]"
  ...
/>

```

### Class Binding in SingleOtpInput

The child component [`src/components/single-otp-input.vue`](https://github.com/ejirocodes/vue3-otp-input/blob/main/src/components/single-otp-input.vue) receives the single string and merges it into the input's class list alongside base styles and completion states:

```vue
<!-- src/components/single-otp-input.vue (lines 54-55) -->
<input
  :class="[inputClasses, conditionalClass, { 'is-complete': model }]"
  ...
/>

```

This binding ensures that any class passed from the parent array is applied directly to the specific OTP input element.

## Practical Implementation Examples

The following patterns demonstrate how to customize OTP input styling with conditional classes per input in Vue 3 for static, dynamic, and utility-first CSS workflows.

### Static Styling per Input Box

Apply distinct border colors to each position for visual segmentation:

```vue
<template>
  <v-otp-input
    :num-inputs="4"
    :conditionalClass="['first-box', 'second-box', 'third-box', 'fourth-box']"
    v-model:value="code"
  />
</template>

<style>
.first-box   { border: 2px solid #4caf50; }
.second-box  { border: 2px solid #2196f3; }
.third-box   { border: 2px solid #ff9800; }
.fourth-box  { border: 2px solid #f44336; }
</style>

```

### Dynamic Classes Based on Input State

Toggle background colors depending on whether the user has entered a value:

```vue
<script setup lang="ts">
import { ref, computed } from 'vue';
const code = ref('');

const conditionalClasses = computed(() => {
  const chars = code.value.padEnd(4, '_').split('');
  return chars.map(c => (c === '_' ? 'empty-box' : 'filled-box'));
});
</script>

<template>
  <v-otp-input
    :num-inputs="4"
    :conditionalClass="conditionalClasses"
    v-model:value="code"
  />
</template>

<style>
.empty-box  { background: #f0f0f0; }
.filled-box { background: #c8e6c9; }
</style>

```

### Tailwind CSS Gradient Styling

Use utility classes to create a color progression across the OTP fields:

```vue
<template>
  <v-otp-input
    :num-inputs="6"
    :conditionalClass="['bg-red-100', 'bg-orange-100', 'bg-amber-100', 'bg-yellow-100', 'bg-lime-100', 'bg-green-100']"
    input-classes="w-10 h-10 text-center border rounded"
  />
</template>

```

## Key Implementation Files

The styling pipeline relies on three specific source files in the `ejirocodes/vue3-otp-input` repository:

- **[`src/components/vue3-otp-input.vue`](https://github.com/ejirocodes/vue3-otp-input/blob/main/src/components/vue3-otp-input.vue)** – Defines the `conditionalClass` prop (lines 15‑18) and forwards the indexed class value to each child input (lines 38‑40).

- **[`src/components/single-otp-input.vue`](https://github.com/ejirocodes/vue3-otp-input/blob/main/src/components/single-otp-input.vue)** – Receives the individual class string and binds it to the `<input>` element alongside base and state classes (lines 54‑55).

- **[`README.md`](https://github.com/ejirocodes/vue3-otp-input/blob/main/README.md)** – Documents the prop signature and the requirement that the array length must equal `numInputs`.

## Summary

- The `conditionalClass` prop accepts an **array of strings** where each index maps to a specific OTP input box.
- The root component validates the prop and forwards the appropriate class via `conditionalClass?.[i]` to each `SingleOtpInput` child.
- Individual classes are merged into the input's class list in [`single-otp-input.vue`](https://github.com/ejirocodes/vue3-otp-input/blob/main/single-otp-input.vue), allowing per-box styling without affecting sibling inputs.
- You can use **static arrays**, **computed properties**, or **Tailwind utilities** to implement visual states such as color coding, completion indicators, or gradient effects.

## Frequently Asked Questions

### Can I use conditionalClass with any CSS framework?

Yes. The `conditionalClass` prop accepts plain strings, so you can pass **Tailwind** utility classes, **Bootstrap** classes, **BEM** naming conventions, or scoped CSS module identifiers. The component applies the string directly to the input's `class` attribute without transformation.

### What happens if the array length doesn't match numInputs?

The component does not enforce runtime validation, but the README specifies that the array length should equal `numInputs`. If the array is shorter, **undefined** values are passed to the remaining inputs via optional chaining `?.[i]`, resulting in no extra classes being applied to those boxes. Excess entries in a longer array are ignored.

### How do I apply different styles based on whether the input is filled?

Use a **computed property** to generate the `conditionalClass` array dynamically. Map over the current OTP value and return a class name for filled positions and a different one for empty positions. Because the array is reactive, Vue updates the classes instantly as the user types or deletes digits.

### Can I combine conditionalClass with the input-classes prop?

Absolutely. The `input-classes` prop applies **base styles** to every OTP input, while `conditionalClass` provides **per-index overrides**. In [`single-otp-input.vue`](https://github.com/ejirocodes/vue3-otp-input/blob/main/single-otp-input.vue), the final class binding merges both: `[inputClasses, conditionalClass, ...]`. This allows you to set common sizing and spacing via `input-classes` and unique colors or borders via `conditionalClass`.