Migrating from ghl-ui InputOtp to HighRise InputOtp
This guide will help you migrate from the ghl-ui InputOtp component to the new HighRise InputOtp component.
Component Implementation Changes
Import Changes
diff
- import { UIInputOtp } from '@gohighlevel/ghl-ui'
+ import { HLInputOtp } from '@platform-ui/highrise'Basic Usage Changes
diff
- <UIInputOtp
- :fields="6"
- :disabled="false"
- placeholder="0"
- :size="'md'"
- :status="'default'"
- :separatorPosition="3"
- @onComplete="handleComplete"
- @onChange="handleChange"
- />
-
+ <HLInputOtp
+ id="otp-input"
+ :fields="6"
+ :separator-position="3"
+ :size="'md'"
+ @on-complete="handleComplete"
+ @on-change="handleChange"
+ />HighRise InputOtp is event-driven: it manages its own internal state and emits
on-changeandon-complete. There is nov-model; persist the OTP in your state from these events.
Props Changes
| ghl-ui Prop | HighRise Prop | Notes |
|---|---|---|
fields | fields | Same meaning; default 6 |
disabled | disabled | Same |
placeholder | placeholder | Same; default "0" |
size | size | Inherits form size if not set |
status | status | Adds CSS class (e.g., error, default) |
separatorPosition | separator-position | Same behavior; renders a separator after the position |
id | id | Optional; auto-generated when omitted |
| - | (no v-model) | Capture values from events instead of two-way binding |
Examples
Basic OTP Input
vue
<template>
<HLInputOtp id="basic-otp" :fields="6" :separator-position="3" size="md" @on-change="handleChange" />
</template>
<script setup>
import { ref } from 'vue'
import { HLInputOtp } from '@platform-ui/highrise'
const otpValue = ref('')
const handleChange = value => {
otpValue.value = value
}
</script>OTP Input with Completion Handling
vue
<template>
<HLInputOtp
id="otp-input"
:fields="6"
size="md"
:separator-position="3"
@on-change="value => (otpValue = value)"
@on-complete="handleComplete"
/>
</template>
<script setup>
import { ref } from 'vue'
import { HLInputOtp } from '@platform-ui/highrise'
const otpValue = ref('')
const handleComplete = payload => {
// payload.otp contains the concatenated value
otpValue.value = payload.otp
// Submit or validate here
}
</script>Resetting the OTP Fields
vue
<template>
<HLInputOtp :key="resetKey" id="resettable-otp" :fields="6" :separator-position="3" @on-change="value => (otpValue = value)" />
<HLButton size="sm" @click="resetOtp">Reset</HLButton>
</template>
<script setup>
import { ref } from 'vue'
import { HLButton, HLInputOtp } from '@platform-ui/highrise'
const otpValue = ref('')
const resetKey = ref(0)
const resetOtp = () => {
otpValue.value = ''
resetKey.value += 1 // forces a fresh instance
}
</script>Best Practices
- Persist the OTP via
@on-changeor@on-complete; there is nov-model. - Use
:keyto reset the input after failed attempts or resend flows. - Apply
status="error"(or similar) for visual feedback when validation fails. - Keep
fieldsconsistent with backend expectations; default is 6. - Provide a separator position only when you need visual grouping (e.g., after the third digit).
- Supply
idwhen you need deterministic selectors for testing; otherwise let it auto-generate.
Additional Notes
- Events:
on-changeemits the current string;on-completeemits{ otp, state: 'completed' }once the length matchesfields. - Pasting rejects non-numeric characters; invalid paste returns without mutating the value.
- Size defaults to the surrounding form size when used inside
HLFormItem. - All additional attributes are dropped; only the documented props are applied.