PinInput

A specialized input component designed for entering PIN codes, one-time passwords (OTP), verification codes, and other sequential character inputs. The component provides an intuitive interface with automatic focus management.

Basic

Controlled 4-digit PIN input with automatic focus handoff and live preview.

Loading demo…

import

 

{

useState

}

 

from

 

'react'

;

import

 

{

 

PinInput

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

export

 

function

 

Demo

(

)

 

{

  

const

 

[

value

,

setValue

]

 

=

 

useState

(

''

)

;

 

  

return

 

(

    

<PinInput

      

value

=

{

value

}

      

onChange

=

{

setValue

}

      

label

=

"PIN code"

      

keyboardFocusId

=

"pin-demo-basic"

    

/>

  

)

;

}

Types

Contrast numeric-only PIN entry with an alphanumeric option for recovery codes.

Loading demo…

import

 

{

useState

}

 

from

 

'react'

;

 

import

 

{

 

Block

,

 

PinInput

,

 

Text

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

export

 

function

 

Demo

(

)

 

{

  

const

 

[

numericValue

,

setNumericValue

]

 

=

 

useState

(

''

)

;

  

const

 

[

alphanumericValue

,

setAlphanumericValue

]

 

=

 

useState

(

''

)

;

 

  

return

 

(

    

<Block

>

      

<Text

 

weight

=

"semibold"

>

PIN

input types

</Text

>

 

      

<Block

>

        

<Text

 

size

=

"sm"

 

weight

=

"semibold"

>

          

Numeric

 

(

default

)

        

</Text

>

        

<Text

 

size

=

"sm"

 

color

=

"secondary"

>

          

Restricts

entry to digits

0

-

9

 

for

 

PIN

and

OTP

flows

.

        

</Text

>

        

<PinInput

          

value

=

{

numericValue

}

          

onChange

=

{

setNumericValue

}

          

type

=

"numeric"

          

label

=

"Numeric PIN"

        

/>

      

</Block

>

 

      

<Block

>

        

<Text

 

size

=

"sm"

 

weight

=

"semibold"

>

          

Alphanumeric

        

</Text

>

        

<Text

 

size

=

"sm"

 

color

=

"secondary"

>

          

Allow

letters and numbers

for

recovery or backup codes

.

        

</Text

>

        

<PinInput

          

value

=

{

alphanumericValue

}

          

onChange

=

{

setAlphanumericValue

}

          

type

=

"alphanumeric"

          

label

=

"Alphanumeric code"

          

length

=

{

6

}

        

/>

      

</Block

>

    

</Block

>

  

)

;

}

Sizes

Demonstrates xs through lg PIN inputs and when each token fits best.

Loading demo…

import

 

{

useState

}

 

from

 

'react'

;

 

import

 

{

 

Block

,

 

PinInput

,

 

Text

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

type

 

SizeToken

 

=

 

'xs'

 

|

 

'sm'

 

|

 

'md'

 

|

 

'lg'

;

 

export

 

function

 

Demo

(

)

 

{

  

const

 

[

xsValue

,

setXsValue

]

 

=

 

useState

(

''

)

;

  

const

 

[

smValue

,

setSmValue

]

 

=

 

useState

(

''

)

;

  

const

 

[

mdValue

,

setMdValue

]

 

=

 

useState

(

''

)

;

  

const

 

[

lgValue

,

setLgValue

]

 

=

 

useState

(

''

)

;

 

  

const

sizeExamples

:

 

Array

<

{

    id

:

 

SizeToken

;

    label

:

 

string

;

    helper

:

 

string

;

    size

:

 

SizeToken

;

    value

:

 

string

;

    setValue

:

 

(

value

:

 

string

)

 

=>

 

void

;

  

}

>

 

=

 

[

    

{

      id

:

 

'xs'

,

      label

:

 

'Extra small (xs)'

,

      helper

:

 

'Use for dense layouts or compact verification prompts.'

,

      size

:

 

'xs'

,

      value

:

xsValue

,

      setValue

:

setXsValue

,

    

}

,

    

{

      id

:

 

'sm'

,

      label

:

 

'Small (sm)'

,

      helper

:

 

'Pairs well with mobile forms and inline flows.'

,

      size

:

 

'sm'

,

      value

:

smValue

,

      setValue

:

setSmValue

,

    

}

,

    

{

      id

:

 

'md'

,

      label

:

 

'Medium (md)'

,

      helper

:

 

'Default size for most experiences.'

,

      size

:

 

'md'

,

      value

:

mdValue

,

      setValue

:

setMdValue

,

    

}

,

    

{

      id

:

 

'lg'

,

      label

:

 

'Large (lg)'

,

      helper

:

 

'Highlight critical actions with spacious fields.'

,

      size

:

 

'lg'

,

      value

:

lgValue

,

      setValue

:

setLgValue

,

    

}

,

  

]

;

 

  

return

 

(

    

<Block

>

      

<Text

 

weight

=

"semibold"

>

PIN

input sizes

</Text

>

 

      

{

sizeExamples

.

map

(

(

example

)

 

=>

 

(

        

<Block

 

key

=

{

example

.

id

}

>

          

<Text

 

size

=

"sm"

 

weight

=

"semibold"

>

            

{

example

.

label

}

          

</Text

>

          

<Text

 

size

=

"sm"

 

color

=

"secondary"

>

            

{

example

.

helper

}

          

</Text

>

          

<PinInput

            

value

=

{

example

.

value

}

            

onChange

=

{

example

.

setValue

}

            

size

=

{

example

.

size

}

            

label

=

{

`${example.label} PIN`

}

          

/>

        

</Block

>

      

)

)

}

    

</Block

>

  

)

;

}

Lengths

Compare 4, 6, and 8-digit PIN inputs tailored for common authentication flows.

Loading demo…

import

 

{

useState

}

 

from

 

'react'

;

 

import

 

{

 

Block

,

 

PinInput

,

 

Text

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

export

 

function

 

Demo

(

)

 

{

  

const

 

[

fourDigit

,

setFourDigit

]

 

=

 

useState

(

''

)

;

  

const

 

[

sixDigit

,

setSixDigit

]

 

=

 

useState

(

''

)

;

  

const

 

[

eightDigit

,

setEightDigit

]

 

=

 

useState

(

''

)

;

 

  

const

lengthExamples

=

 

[

    

{

      length

:

 

4

,

      title

:

 

'4-digit PIN (default)'

,

      helper

:

 

'Common for ATM and device security codes.'

,

      label

:

 

'4-digit PIN'

,

      value

:

fourDigit

,

      setValue

:

setFourDigit

,

    

}

,

    

{

      length

:

 

6

,

      title

:

 

'6-digit verification'

,

      helper

:

 

'Typical for SMS-based one-time codes.'

,

      label

:

 

'Verification code'

,

      value

:

sixDigit

,

      setValue

:

setSixDigit

,

    

}

,

    

{

      length

:

 

8

,

      title

:

 

'8-digit code'

,

      helper

:

 

'Use for longer recovery or backup codes.'

,

      label

:

 

'Security code'

,

      value

:

eightDigit

,

      setValue

:

setEightDigit

,

    

}

,

  

]

;

 

  

return

 

(

    

<Block

>

      

<Text

 

weight

=

"semibold"

>

PIN

input lengths

</Text

>

      

{

lengthExamples

.

map

(

(

example

)

 

=>

 

(

        

<Block

 

key

=

{

example

.

length

}

>

          

<Text

 

size

=

"sm"

 

weight

=

"semibold"

>

            

{

example

.

title

}

          

</Text

>

          

<Text

 

size

=

"sm"

 

color

=

"secondary"

>

            

{

example

.

helper

}

          

</Text

>

          

<PinInput

            

value

=

{

example

.

value

}

            

onChange

=

{

example

.

setValue

}

            

length

=

{

example

.

length

}

            

label

=

{

example

.

label

}

          

/>

        

</Block

>

      

)

)

}

    

</Block

>

  

)

;

}

Security

Highlights masking, automatic OTP completion, and validation flows with inline messaging.

Loading demo…

import

 

{

useState

}

 

from

 

'react'

;

 

import

 

{

 

Block

,

 

Button

,

 

PinInput

,

 

Row

,

 

Text

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

export

 

function

 

Demo

(

)

 

{

  

const

 

[

maskedValue

,

setMaskedValue

]

 

=

 

useState

(

''

)

;

  

const

 

[

otpValue

,

setOtpValue

]

 

=

 

useState

(

''

)

;

  

const

 

[

otpStatus

,

setOtpStatus

]

 

=

 

useState

(

''

)

;

  

const

 

[

validationValue

,

setValidationValue

]

 

=

 

useState

(

''

)

;

  

const

 

[

validationMessage

,

setValidationMessage

]

 

=

 

useState

(

''

)

;

  

const

 

[

error

,

setError

]

 

=

 

useState

(

''

)

;

  

const

 

[

disabled

,

setDisabled

]

 

=

 

useState

(

false

)

;

 

  

const

correctPin

=

 

'1234'

;

 

  

const

handleValidate

=

 

(

)

 

=>

 

{

    

if

 

(

validationValue

!==

correctPin

)

 

{

      

setError

(

'Incorrect PIN. Try again.'

)

;

      

setValidationMessage

(

''

)

;

      

return

;

    

}

 

    

setError

(

''

)

;

    

setValidationMessage

(

'PIN verified successfully.'

)

;

  

}

;

 

  

const

handleOtpComplete

=

 

(

value

:

 

string

)

 

=>

 

{

    

setOtpStatus

(

`OTP entered: ${value}`

)

;

  

}

;

 

  

const

handleToggleDisabled

=

 

(

)

 

=>

 

{

    

setDisabled

(

(

prev

)

 

=>

 

!

prev

)

;

    

setError

(

''

)

;

    

setValidationMessage

(

''

)

;

  

}

;

 

  

const

handleClear

=

 

(

)

 

=>

 

{

    

setValidationValue

(

''

)

;

    

setError

(

''

)

;

    

setValidationMessage

(

''

)

;

  

}

;

 

  

return

 

(

    

<Block

>

      

<Text

 

weight

=

"semibold"

>

Security

-

focused

PIN

inputs

</Text

>

 

      

<Block

>

        

<Text

 

size

=

"sm"

 

weight

=

"semibold"

>

          

Masked

 

PIN

input

        

</Text

>

        

<Text

 

size

=

"sm"

 

color

=

"secondary"

>

          

Conceal

characters as they are typed

.

        

</Text

>

        

<PinInput

          

value

=

{

maskedValue

}

          

onChange

=

{

setMaskedValue

}

          mask

          

label

=

"Secure PIN"

        

/>

      

</Block

>

 

      

<Block

>

        

<Text

 

size

=

"sm"

 

weight

=

"semibold"

>

          

OTP

with auto

-

complete

        

</Text

>

        

<Text

 

size

=

"sm"

 

color

=

"secondary"

>

          

Automatically

completes once all digits are entered

.

        

</Text

>

        

<PinInput

          

value

=

{

otpValue

}

          

onChange

=

{

(

value

)

 

=>

 

{

            

setOtpValue

(

value

)

;

            

if

 

(

otpStatus

)

 

setOtpStatus

(

''

)

;

          

}

}

          

onComplete

=

{

handleOtpComplete

}

          oneTimeCode

          

length

=

{

6

}

          

label

=

"One-time password"

        

/>

        

{

otpStatus

?

 

(

          

<Text

 

size

=

"xs"

 

color

=

"secondary"

>

            

{

otpStatus

}

          

</Text

>

        

)

 

:

 

null

}

      

</Block

>

 

      

<Block

>

        

<Text

 

size

=

"sm"

 

weight

=

"semibold"

>

          

PIN

validation state

        

</Text

>

        

<Text

 

size

=

"sm"

 

color

=

"secondary"

>

          

Enter

the correct

PIN

:

 

1234

        

</Text

>

        

<PinInput

          

value

=

{

validationValue

}

          

onChange

=

{

(

newValue

)

 

=>

 

{

            

setValidationValue

(

newValue

)

;

            

if

 

(

error

)

 

setError

(

''

)

;

            

if

 

(

validationMessage

)

 

setValidationMessage

(

''

)

;

          

}

}

          

label

=

"Enter PIN"

          

error

=

{

error

}

          

disabled

=

{

disabled

}

          

helperText

=

{

!

error

?

 

'Enter the correct 4-digit PIN'

 

:

 

undefined

}

        

/>

 

        

<Row

 

gap

=

"sm"

 

wrap

=

"wrap"

>

          

<Button

            

variant

=

"filled"

            

onPress

=

{

handleValidate

}

            

disabled

=

{

validationValue

.

length

!==

 

4

}

          

>

            

Validate

          

</Button

>

          

<Button

 

variant

=

"outline"

 

onPress

=

{

handleToggleDisabled

}

>

            

{

disabled

?

 

'Enable input'

 

:

 

'Disable input'

}

          

</Button

>

          

<Button

 

variant

=

"outline"

 

onPress

=

{

handleClear

}

>

            

Clear

          

</Button

>

        

</Row

>

 

        

{

validationMessage

?

 

(

          

<Text

 

size

=

"xs"

 

color

=

"secondary"

>

            

{

validationMessage

}

          

</Text

>

        

)

 

:

 

null

}

      

</Block

>

    

</Block

>

  

)

;

}

Scan to open this page on your phonereact-ui-library.com/components/PinInput

</>

react-ui-library

100+ accessible, themeable components that work seamlessly across iOS, Android, and Web.

A Platform Blocks product.