FloatingLabelInput
floatinglabelinput-1779378816967.tsx
'use client'
import { useState } from 'react'
interface FloatingLabelInputProps {
label?: string
type?: string
maxLength?: number
required?: boolean
pattern?: string
helperText?: string
}
export default function FloatingLabelInput({ label = 'Email address', type = 'email', maxLength = 60, required = true, helperText = 'We never share your email.' }: FloatingLabelInputProps) {
const [value, setValue] = useState('')
const [focused, setFocused] = useState(false)
const [touched, setTouched] = useState(false)
const isValid = type === 'email' ? /^[^s@]+@[^s@]+.[^s@]+$/.test(value) : value.length > 0
const showError = touched && !isValid && value.length > 0
const showSuccess = touched && isValid && value.length > 0
const borderColor = showError ? '#ef4444' : showSuccess ? '#22c55e' : focused ? '#C9A84C' : 'rgba(255,255,255,0.12)'
const labelColor = showError ? '#ef4444' : showSuccess ? '#22c55e' : focused ? '#C9A84C' : 'rgba(255,255,255,0.4)'
return (
<div style={{ padding: 40, background: '#0A0A0A', display: 'flex', flexDirection: 'column', gap: 24, alignItems: 'center', minHeight: 200, justifyContent: 'center' }}>
{[
{ label: 'Email address', type: 'email', helper: 'We never share your email.' },
{ label: 'Password', type: 'password', helper: 'Minimum 8 characters.' },
{ label: 'Full name', type: 'text', helper: 'As it appears on your ID.' },
].map(field => {
const [fval, setFval] = useState('')
const [ffoc, setFfoc] = useState(false)
const [ftouch, setFtouch] = useState(false)
const fvalid = field.type === 'email' ? /^[^s@]+@[^s@]+.[^s@]+$/.test(fval) : fval.length >= (field.type === 'password' ? 8 : 1)
const ferr = ftouch && !fvalid && fval.length > 0
const fok = ftouch && fvalid
const fborder = ferr ? '#ef4444' : fok ? '#22c55e' : ffoc ? '#C9A84C' : 'rgba(255,255,255,0.12)'
const flabel = ferr ? '#ef4444' : fok ? '#22c55e' : ffoc ? '#C9A84C' : 'rgba(255,255,255,0.4)'
const floated = ffoc || fval.length > 0
return (
<div key={field.label} style={{ position: 'relative', width: 320 }}>
<label style={{
position: 'absolute', left: 14, top: floated ? -10 : 16,
fontSize: floated ? 11 : 14, color: flabel,
background: floated ? '#0A0A0A' : 'transparent',
padding: floated ? '0 4px' : 0,
transition: 'all 0.2s', pointerEvents: 'none', zIndex: 1,
}}>{field.label}{required && ' *'}</label>
<input
type={field.type === 'password' ? 'password' : 'text'}
value={fval}
onChange={e => setFval(e.target.value)}
onFocus={() => setFfoc(true)}
onBlur={() => { setFfoc(false); setFtouch(true) }}
maxLength={maxLength}
style={{
width: '100%', boxSizing: 'border-box',
background: 'rgba(255,255,255,0.03)', border: `1.5px solid ${fborder}`,
borderRadius: 10, color: '#F5F5F0', fontSize: 14,
padding: '16px 40px 8px 14px', outline: 'none',
transition: 'border-color 0.2s',
}}
/>
{(fok || ferr) && (
<span style={{ position: 'absolute', right: 12, top: 16, fontSize: 16 }}>
{fok ? '✓' : '✗'}
</span>
)}
<div style={{ marginTop: 4, fontSize: 11, color: ferr ? '#ef4444' : 'rgba(255,255,255,0.35)', paddingLeft: 4 }}>
{ferr ? (field.type === 'email' ? 'Invalid email address' : field.type === 'password' ? 'Too short' : 'Required') : field.helper}
</div>
</div>
)
})}
</div>
)
}Component info
CategoryForms
Frameworkreact
TierFREE
Views0
Copies0
About
Input with animated floating label, validation states, and character counter