FormInput
A form input component with built-in label, description, and error handling capabilities.
FormInput
A comprehensive form input component that combines labels, descriptions, and validation states. Perfect for creating accessible, user-friendly forms with proper labeling and helpful context.
Default
The default FormInput includes a label and optional description text, providing clear context for users.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
<fieldset className="flex flex-col gap-1.5 border-0 m-0 p-0">
<label
className="text-gray-11 text-[13px] flex items-center"
htmlFor=":S1:"
id=":S1:-label"
>
Username
</label>
<div className="relative flex items-center w-full text-grayA-12">
<input
aria-describedby=":S1:-helper"
className="flex min-h-9 w-full rounded-lg text-[13px] leading-5 transition-colors duration-300 disabled:cursor-not-allowed disabled:opacity-50 placeholder:text-grayA-8 text-grayA-12 border border-gray-5 hover:border-gray-8 bg-gray-2 dark:bg-black focus:border focus:border-accent-12 focus:ring-4 focus:ring-gray-5 focus-visible:outline-none focus:ring-offset-0 px-3 py-2"
id=":S1:"
placeholder="e.g. gandalf_grey"
/>
</div>
<div className="text-[13px] leading-5">
<output
className="text-gray-9 flex gap-2 items-start"
id=":S1:-helper"
>
<div className="size-[14px]">
<svg
aria-hidden="true"
className="flex-shrink-0 mt-[3px]"
height={14}
viewBox="0 0 18 18"
width={14}
xmlns="http://www.w3.org/2000/svg"
>
<g fill="currentColor">
<circle
cx="9"
cy="9"
fill="none"
r="7.25"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
/>
<line
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
x1="9"
x2="9"
y1="12.819"
y2="8.25"
/>
<path
d="M9,6.75c-.552,0-1-.449-1-1s.448-1,1-1,1,.449,1,1-.448,1-1,1Z"
fill="currentColor"
stroke="none"
/>
</g>
</svg>
</div>
<span className="flex-1">
Choose a unique username for your account
</span>
</output>
</div>
</fieldset>Input States
Required Field
Use the required prop to indicate mandatory fields. This automatically adds a "Required" tag to the label.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
<fieldset className="flex flex-col gap-1.5 border-0 m-0 p-0">
<label
className="text-gray-11 text-[13px] flex items-center"
htmlFor=":S2:"
id=":S2:-label"
>
Email Address
<span className="inline-flex items-center rounded border px-1 py-0.5 text-xs font-sans ml-2 border-warning-4 text-warning-11 bg-warning-3 dark:border-warning-4 dark:text-warning-11 dark:bg-warning-3">
Required
</span>
</label>
<div className="relative flex items-center w-full text-grayA-12">
<input
aria-describedby=":S2:-helper"
aria-required
className="flex min-h-9 w-full rounded-lg text-[13px] leading-5 transition-colors duration-300 disabled:cursor-not-allowed disabled:opacity-50 placeholder:text-grayA-8 text-grayA-12 border border-gray-5 hover:border-gray-8 bg-gray-2 dark:bg-black focus:border focus:border-accent-12 focus:ring-4 focus:ring-gray-5 focus-visible:outline-none focus:ring-offset-0 px-3 py-2"
id=":S2:"
placeholder="frodo@shire.me"
/>
</div>
<div className="text-[13px] leading-5">
<output
className="text-gray-9 flex gap-2 items-start"
id=":S2:-helper"
>
<div className="size-[14px]">
<svg
aria-hidden="true"
className="flex-shrink-0 mt-[3px]"
height={14}
viewBox="0 0 18 18"
width={14}
xmlns="http://www.w3.org/2000/svg"
>
<g fill="currentColor">
<circle
cx="9"
cy="9"
fill="none"
r="7.25"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
/>
<line
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
x1="9"
x2="9"
y1="12.819"
y2="8.25"
/>
<path
d="M9,6.75c-.552,0-1-.449-1-1s.448-1,1-1,1,.449,1,1-.448,1-1,1Z"
fill="currentColor"
stroke="none"
/>
</g>
</svg>
</div>
<span className="flex-1">
We'll send your confirmation email here
</span>
</output>
</div>
</fieldset>Required Field with Error
When a required field has an error, the "Required" tag changes to error styling to draw more attention.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
<fieldset className="flex flex-col gap-1.5 border-0 m-0 p-0">
<label
className="text-gray-11 text-[13px] flex items-center"
htmlFor=":S3:"
id=":S3:-label"
>
Username
<span className="inline-flex items-center rounded border px-1 py-0.5 text-xs font-sans ml-2 border-error-4 text-error-11 bg-error-3">
Required
</span>
</label>
<div className="relative flex items-center w-full text-error-11">
<input
aria-describedby=":S3:-error"
aria-invalid
aria-required
className="flex min-h-9 w-full rounded-lg text-[13px] leading-5 transition-colors duration-300 disabled:cursor-not-allowed disabled:opacity-50 placeholder:text-grayA-8 text-grayA-12 border border-error-9 hover:border-error-10 bg-gray-2 dark:bg-black focus:border-error-8 focus:ring-2 focus:ring-error-2 focus-visible:outline-none px-3 py-2"
id=":S3:"
placeholder="e.g. aragorn_king"
/>
</div>
<div className="text-[13px] leading-5">
<div
className="text-error-11 flex gap-2 items-center"
id=":S3:-error"
role="alert"
>
<svg
aria-hidden="true"
className="flex-shrink-0"
height="12"
viewBox="0 0 12 12"
width="12"
xmlns="http://www.w3.org/2000/svg"
>
<g fill="currentColor">
<circle
cx="6"
cy="10.125"
fill="currentColor"
r=".875"
strokeWidth="0"
/>
<line
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
x1="6"
x2="6"
y1="4.75"
y2="7.75"
/>
<path
d="m8.625,10.25h1.164c1.123,0,1.826-1.216,1.265-2.189L7.265,1.484c-.562-.975-1.969-.975-2.53,0L.946,8.061c-.561.973.142,2.189,1.265,2.189h1.164"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
/>
</g>
</svg>
<span className="flex-1">
This username is already taken
</span>
</div>
</div>
</fieldset>Optional Field
Use the optional prop to explicitly indicate non-mandatory fields. This adds an "Optional" tag to the label.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
<fieldset className="flex flex-col gap-1.5 border-0 m-0 p-0">
<label
className="text-gray-11 text-[13px] flex items-center"
htmlFor=":S4:"
id=":S4:-label"
>
Phone Number
<span className="inline-flex items-center rounded border border-grayA-4 text-grayA-11 px-1 py-0.5 text-xs font-sans bg-grayA-3 ml-2">
Optional
</span>
</label>
<div className="relative flex items-center w-full text-grayA-12">
<input
aria-describedby=":S4:-helper"
className="flex min-h-9 w-full rounded-lg text-[13px] leading-5 transition-colors duration-300 disabled:cursor-not-allowed disabled:opacity-50 placeholder:text-grayA-8 text-grayA-12 border border-gray-5 hover:border-gray-8 bg-gray-2 dark:bg-black focus:border focus:border-accent-12 focus:ring-4 focus:ring-gray-5 focus-visible:outline-none focus:ring-offset-0 px-3 py-2"
id=":S4:"
placeholder="+1 (555) 123-4567"
/>
</div>
<div className="text-[13px] leading-5">
<output
className="text-gray-9 flex gap-2 items-start"
id=":S4:-helper"
>
<div className="size-[14px]">
<svg
aria-hidden="true"
className="flex-shrink-0 mt-[3px]"
height={14}
viewBox="0 0 18 18"
width={14}
xmlns="http://www.w3.org/2000/svg"
>
<g fill="currentColor">
<circle
cx="9"
cy="9"
fill="none"
r="7.25"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
/>
<line
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
x1="9"
x2="9"
y1="12.819"
y2="8.25"
/>
<path
d="M9,6.75c-.552,0-1-.449-1-1s.448-1,1-1,1,.449,1,1-.448,1-1,1Z"
fill="currentColor"
stroke="none"
/>
</g>
</svg>
</div>
<span className="flex-1">
We'll only use this for important account notifications
</span>
</output>
</div>
</fieldset>Success State
Indicates successful validation or acceptance of input value. The success icon and text provide positive feedback.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
<fieldset className="flex flex-col gap-1.5 border-0 m-0 p-0">
<label
className="text-gray-11 text-[13px] flex items-center"
htmlFor=":S5:"
id=":S5:-label"
>
API Key
</label>
<div className="relative flex items-center w-full text-success-11">
<input
aria-describedby=":S5:-helper"
className="flex min-h-9 w-full rounded-lg text-[13px] leading-5 transition-colors duration-300 disabled:cursor-not-allowed disabled:opacity-50 placeholder:text-grayA-8 text-grayA-12 border border-success-9 hover:border-success-10 bg-gray-2 dark:bg-black focus:border-success-8 focus:ring-2 focus:ring-success-2 focus-visible:outline-none px-3 py-2"
defaultValue="sk_live_middleearth123"
id=":S5:"
placeholder="Enter your API key"
/>
</div>
<div className="text-[13px] leading-5">
<output
className="flex gap-2 items-start text-success-11"
id=":S5:-helper"
>
<div className="size-[14px]">
<svg
aria-hidden="true"
className="flex-shrink-0 mt-[3px]"
height={14}
viewBox="0 0 18 18"
width={14}
xmlns="http://www.w3.org/2000/svg"
>
<g fill="currentColor">
<circle
cx="9"
cy="9"
fill="none"
r="7.25"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
/>
<line
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
x1="9"
x2="9"
y1="12.819"
y2="8.25"
/>
<path
d="M9,6.75c-.552,0-1-.449-1-1s.448-1,1-1,1,.449,1,1-.448,1-1,1Z"
fill="currentColor"
stroke="none"
/>
</g>
</svg>
</div>
<span className="flex-1">
Your API key has been verified
</span>
</output>
</div>
</fieldset>Warning State
Used for potentially problematic inputs that don't prevent form submission. Includes a warning icon and explanatory text.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
<fieldset className="flex flex-col gap-1.5 border-0 m-0 p-0">
<label
className="text-gray-11 text-[13px] flex items-center"
htmlFor=":S6:"
id=":S6:-label"
>
Password
</label>
<div className="relative flex items-center w-full text-warning-11">
<input
aria-describedby=":S6:-helper"
className="flex min-h-9 w-full rounded-lg text-[13px] leading-5 transition-colors duration-300 disabled:cursor-not-allowed disabled:opacity-50 placeholder:text-grayA-8 text-grayA-12 border border-warning-9 hover:border-warning-10 bg-gray-2 dark:bg-black focus:border-warning-8 focus:ring-2 focus:ring-warning-2 focus-visible:outline-none px-3 py-2"
id=":S6:"
placeholder="Enter your password"
type="password"
/>
</div>
<div className="text-[13px] leading-5">
<output
className="flex gap-2 items-start text-warning-11"
id=":S6:-helper"
>
<div className="size-[14px]">
<svg
aria-hidden="true"
className="flex-shrink-0 mt-[3px]"
height="12"
size="md-regular"
viewBox="0 0 12 12"
width="12"
xmlns="http://www.w3.org/2000/svg"
>
<g fill="currentColor">
<circle
cx="6"
cy="10.125"
fill="currentColor"
r=".875"
strokeWidth="0"
/>
<line
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
x1="6"
x2="6"
y1="4.75"
y2="7.75"
/>
<path
d="m8.625,10.25h1.164c1.123,0,1.826-1.216,1.265-2.189L7.265,1.484c-.562-.975-1.969-.975-2.53,0L.946,8.061c-.561.973.142,2.189,1.265,2.189h1.164"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
/>
</g>
</svg>
</div>
<span className="flex-1">
Your password is about to expire
</span>
</output>
</div>
</fieldset>Error State
Shows validation errors or other issues that need user attention. Features prominent error styling and message.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
<fieldset className="flex flex-col gap-1.5 border-0 m-0 p-0">
<label
className="text-gray-11 text-[13px] flex items-center"
htmlFor=":S7:"
id=":S7:-label"
>
Repository Name
</label>
<div className="relative flex items-center w-full text-error-11">
<input
aria-describedby=":S7:-error"
aria-invalid
className="flex min-h-9 w-full rounded-lg text-[13px] leading-5 transition-colors duration-300 disabled:cursor-not-allowed disabled:opacity-50 placeholder:text-grayA-8 text-grayA-12 border border-error-9 hover:border-error-10 bg-gray-2 dark:bg-black focus:border-error-8 focus:ring-2 focus:ring-error-2 focus-visible:outline-none px-3 py-2"
id=":S7:"
placeholder="my-awesome-project"
/>
</div>
<div className="text-[13px] leading-5">
<div
className="text-error-11 flex gap-2 items-center"
id=":S7:-error"
role="alert"
>
<svg
aria-hidden="true"
className="flex-shrink-0"
height="12"
viewBox="0 0 12 12"
width="12"
xmlns="http://www.w3.org/2000/svg"
>
<g fill="currentColor">
<circle
cx="6"
cy="10.125"
fill="currentColor"
r=".875"
strokeWidth="0"
/>
<line
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
x1="6"
x2="6"
y1="4.75"
y2="7.75"
/>
<path
d="m8.625,10.25h1.164c1.123,0,1.826-1.216,1.265-2.189L7.265,1.484c-.562-.975-1.969-.975-2.53,0L.946,8.061c-.561.973.142,2.189,1.265,2.189h1.164"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
/>
</g>
</svg>
<span className="flex-1">
A repository with this name already exists
</span>
</div>
</div>
</fieldset>Disabled State
Apply when the field should be non-interactive, such as during form submission or based on other field values.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
<fieldset className="flex flex-col gap-1.5 border-0 m-0 p-0">
<label
className="text-gray-11 text-[13px] flex items-center"
htmlFor=":S8:"
id=":S8:-label"
>
Organization ID
</label>
<div className="relative flex items-center w-full text-grayA-12">
<input
aria-describedby=":S8:-helper"
className="flex min-h-9 w-full rounded-lg text-[13px] leading-5 transition-colors duration-300 disabled:cursor-not-allowed disabled:opacity-50 placeholder:text-grayA-8 text-grayA-12 border border-gray-5 hover:border-gray-8 bg-gray-2 dark:bg-black focus:border focus:border-accent-12 focus:ring-4 focus:ring-gray-5 focus-visible:outline-none focus:ring-offset-0 px-3 py-2"
defaultValue="org_fellowship123"
disabled
id=":S8:"
placeholder="Organization ID"
/>
</div>
<div className="text-[13px] leading-5">
<output
className="text-gray-9 flex gap-2 items-start"
id=":S8:-helper"
>
<div className="size-[14px]">
<svg
aria-hidden="true"
className="flex-shrink-0 mt-[3px]"
height={14}
viewBox="0 0 18 18"
width={14}
xmlns="http://www.w3.org/2000/svg"
>
<g fill="currentColor">
<circle
cx="9"
cy="9"
fill="none"
r="7.25"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
/>
<line
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
x1="9"
x2="9"
y1="12.819"
y2="8.25"
/>
<path
d="M9,6.75c-.552,0-1-.449-1-1s.448-1,1-1,1,.449,1,1-.448,1-1,1Z"
fill="currentColor"
stroke="none"
/>
</g>
</svg>
</div>
<span className="flex-1">
Contact admin to change organization ID
</span>
</output>
</div>
</fieldset>With Default Value
Pre-populated input with an initial value that users can modify.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
<fieldset className="flex flex-col gap-1.5 border-0 m-0 p-0">
<label
className="text-gray-11 text-[13px] flex items-center"
htmlFor=":S9:"
id=":S9:-label"
>
Project Name
</label>
<div className="relative flex items-center w-full text-grayA-12">
<input
aria-describedby=":S9:-helper"
className="flex min-h-9 w-full rounded-lg text-[13px] leading-5 transition-colors duration-300 disabled:cursor-not-allowed disabled:opacity-50 placeholder:text-grayA-8 text-grayA-12 border border-gray-5 hover:border-gray-8 bg-gray-2 dark:bg-black focus:border focus:border-accent-12 focus:ring-4 focus:ring-gray-5 focus-visible:outline-none focus:ring-offset-0 px-3 py-2"
defaultValue="The Fellowship Project"
id=":S9:"
placeholder="Enter project name"
/>
</div>
<div className="text-[13px] leading-5">
<output
className="text-gray-9 flex gap-2 items-start"
id=":S9:-helper"
>
<div className="size-[14px]">
<svg
aria-hidden="true"
className="flex-shrink-0 mt-[3px]"
height={14}
viewBox="0 0 18 18"
width={14}
xmlns="http://www.w3.org/2000/svg"
>
<g fill="currentColor">
<circle
cx="9"
cy="9"
fill="none"
r="7.25"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
/>
<line
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
x1="9"
x2="9"
y1="12.819"
y2="8.25"
/>
<path
d="M9,6.75c-.552,0-1-.449-1-1s.448-1,1-1,1,.449,1,1-.448,1-1,1Z"
fill="currentColor"
stroke="none"
/>
</g>
</svg>
</div>
<span className="flex-1">
Name of your new project
</span>
</output>
</div>
</fieldset>Read-only State
For displaying non-editable information while maintaining form layout consistency.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
<fieldset className="flex flex-col gap-1.5 border-0 m-0 p-0">
<label
className="text-gray-11 text-[13px] flex items-center"
htmlFor=":Sa:"
id=":Sa:-label"
>
Generated Token
</label>
<div className="relative flex items-center w-full text-grayA-12">
<input
aria-describedby=":Sa:-helper"
className="flex min-h-9 w-full rounded-lg text-[13px] leading-5 transition-colors duration-300 disabled:cursor-not-allowed disabled:opacity-50 placeholder:text-grayA-8 text-grayA-12 border border-gray-5 hover:border-gray-8 bg-gray-2 dark:bg-black focus:border focus:border-accent-12 focus:ring-4 focus:ring-gray-5 focus-visible:outline-none focus:ring-offset-0 px-3 py-2"
defaultValue="tkn_1ring2rulethemall"
id=":Sa:"
placeholder="Your token will appear here"
readOnly
/>
</div>
<div className="text-[13px] leading-5">
<output
className="text-gray-9 flex gap-2 items-start"
id=":Sa:-helper"
>
<div className="size-[14px]">
<svg
aria-hidden="true"
className="flex-shrink-0 mt-[3px]"
height={14}
viewBox="0 0 18 18"
width={14}
xmlns="http://www.w3.org/2000/svg"
>
<g fill="currentColor">
<circle
cx="9"
cy="9"
fill="none"
r="7.25"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
/>
<line
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
x1="9"
x2="9"
y1="12.819"
y2="8.25"
/>
<path
d="M9,6.75c-.552,0-1-.449-1-1s.448-1,1-1,1,.449,1,1-.448,1-1,1Z"
fill="currentColor"
stroke="none"
/>
</g>
</svg>
</div>
<span className="flex-1">
Copy this token for your records
</span>
</output>
</div>
</fieldset>Complex Usage
Example of a FormInput with multiple props configured for a specific use case.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
<fieldset className="flex flex-col gap-1.5 border-0 m-0 p-0 max-w-lg">
<label
className="text-gray-11 text-[13px] flex items-center"
htmlFor="webhook-url-input"
id="webhook-url-input-label"
>
Webhook URL
<span className="inline-flex items-center rounded border px-1 py-0.5 text-xs font-sans ml-2 border-warning-4 text-warning-11 bg-warning-3 dark:border-warning-4 dark:text-warning-11 dark:bg-warning-3">
Required
</span>
</label>
<div className="relative flex items-center w-full text-grayA-12">
<input
aria-describedby="webhook-url-input-helper"
aria-required
className="flex min-h-9 w-full rounded-lg text-[13px] leading-5 transition-colors duration-300 disabled:cursor-not-allowed disabled:opacity-50 placeholder:text-grayA-8 text-grayA-12 border border-gray-5 hover:border-gray-8 bg-gray-2 dark:bg-black focus:border focus:border-accent-12 focus:ring-4 focus:ring-gray-5 focus-visible:outline-none focus:ring-offset-0 px-3 py-2"
id="webhook-url-input"
placeholder="https://api.yourdomain.com/webhooks"
/>
</div>
<div className="text-[13px] leading-5">
<output
className="text-gray-9 flex gap-2 items-start"
id="webhook-url-input-helper"
>
<div className="size-[14px]">
<svg
aria-hidden="true"
className="flex-shrink-0 mt-[3px]"
height={14}
viewBox="0 0 18 18"
width={14}
xmlns="http://www.w3.org/2000/svg"
>
<g fill="currentColor">
<circle
cx="9"
cy="9"
fill="none"
r="7.25"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
/>
<line
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
x1="9"
x2="9"
y1="12.819"
y2="8.25"
/>
<path
d="M9,6.75c-.552,0-1-.449-1-1s.448-1,1-1,1,.449,1,1-.448,1-1,1Z"
fill="currentColor"
stroke="none"
/>
</g>
</svg>
</div>
<span className="flex-1">
Enter the URL where we'll send event notifications
</span>
</output>
</div>
</fieldset>Props
The FormInput component extends the standard Input component props with additional form-specific properties:
| Prop | Type | Default |
|---|---|---|
variant | "default" | "success" | "warning" | "error" | - |
leftIcon | ReactNode | - |
rightIcon | ReactNode | - |
wrapperClassName | string | - |
label | string | - |
description | ReactNode | - |
required | boolean | - |
optional | boolean | - |
error | string | - |
Accessibility
FormInput is built with accessibility in mind:
- Labels are properly associated with inputs using htmlFor/id
- Error messages are announced to screen readers using role="alert"
- Required fields are marked both visually and via aria-required
- Helper text is linked to inputs using aria-describedby
- Error states are indicated using aria-invalid
Best Practices
When using the FormInput component:
- Always provide clear, concise labels
- Use description text to provide additional context when needed
- Keep error messages specific and actionable
- Use required fields sparingly and logically
- Group related FormInputs using fieldset and legend when appropriate
- Consider the mobile experience when writing labels and descriptions
- Maintain consistent validation patterns across your form
- Use appropriate input types (email, tel, etc.) for better mobile keyboards
- Consider character/word limits in descriptions and error messages
- Test with screen readers to ensure accessibility
Layout Guidelines
- Labels should be clear and concise
- Error messages should appear immediately below the input
- Description text should be helpful but not too lengthy
- Consider using the optional tag for clarity in forms with many fields