mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-03-22 13:47:19 +08:00
feat: add form validation and accessibility improvements
- Add required prop to FormInput with red asterisk indicator - Make all form fields required (name, company, email, message) - Add aria-label and aria-required attributes to inputs - Add aria-label to all buttons (Back, Submit, Learn More) - Add role='group' to button container - Fix logo size inconsistency (55px → 56px) Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
@@ -6,6 +6,7 @@ interface FormInputProps {
|
||||
placeholder?: string;
|
||||
type?: "text" | "email";
|
||||
rows?: number;
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
export function FormInput({
|
||||
@@ -16,6 +17,7 @@ export function FormInput({
|
||||
placeholder,
|
||||
type = "text",
|
||||
rows,
|
||||
required = false,
|
||||
}: FormInputProps) {
|
||||
const inputId = `form-input-${id}`;
|
||||
const inputClassName =
|
||||
@@ -28,6 +30,7 @@ export function FormInput({
|
||||
className="text-sm font-medium leading-5 text-[#FAFAFA] cursor-pointer"
|
||||
>
|
||||
{label}
|
||||
{required && <span className="text-red-500 ml-1" aria-hidden="true">*</span>}
|
||||
</label>
|
||||
{rows ? (
|
||||
<textarea
|
||||
@@ -37,6 +40,9 @@ export function FormInput({
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder={placeholder}
|
||||
rows={rows}
|
||||
required={required}
|
||||
aria-required={required}
|
||||
aria-label={label}
|
||||
className={`${inputClassName} h-auto resize-none`}
|
||||
/>
|
||||
) : (
|
||||
@@ -47,6 +53,9 @@ export function FormInput({
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder={placeholder}
|
||||
required={required}
|
||||
aria-required={required}
|
||||
aria-label={label}
|
||||
className={inputClassName}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -83,6 +83,7 @@ export function InformationRequestForm({
|
||||
label={t(I18nKey.ENTERPRISE$FORM_NAME_LABEL)}
|
||||
value={formData.name}
|
||||
placeholder={t(I18nKey.ENTERPRISE$FORM_NAME_PLACEHOLDER)}
|
||||
required
|
||||
onChange={(value) =>
|
||||
setFormData((prev) => ({ ...prev, name: value }))
|
||||
}
|
||||
@@ -93,6 +94,7 @@ export function InformationRequestForm({
|
||||
label={t(I18nKey.ENTERPRISE$FORM_COMPANY_LABEL)}
|
||||
value={formData.company}
|
||||
placeholder={t(I18nKey.ENTERPRISE$FORM_COMPANY_PLACEHOLDER)}
|
||||
required
|
||||
onChange={(value) =>
|
||||
setFormData((prev) => ({ ...prev, company: value }))
|
||||
}
|
||||
@@ -104,6 +106,7 @@ export function InformationRequestForm({
|
||||
type="email"
|
||||
value={formData.email}
|
||||
placeholder={t(I18nKey.ENTERPRISE$FORM_EMAIL_PLACEHOLDER)}
|
||||
required
|
||||
onChange={(value) =>
|
||||
setFormData((prev) => ({ ...prev, email: value }))
|
||||
}
|
||||
@@ -115,22 +118,25 @@ export function InformationRequestForm({
|
||||
value={formData.message}
|
||||
placeholder={messagePlaceholder}
|
||||
rows={4}
|
||||
required
|
||||
onChange={(value) =>
|
||||
setFormData((prev) => ({ ...prev, message: value }))
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Buttons */}
|
||||
<div className="flex gap-4 mt-4">
|
||||
<div className="flex gap-4 mt-4" role="group" aria-label="Form actions">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onBack}
|
||||
aria-label={t(I18nKey.COMMON$BACK)}
|
||||
className="flex-1 px-6 py-2.5 text-sm rounded bg-transparent text-white border border-[#242424] hover:bg-[#1a1a1a] transition-colors"
|
||||
>
|
||||
{t(I18nKey.COMMON$BACK)}
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
aria-label={t(I18nKey.ENTERPRISE$FORM_SUBMIT)}
|
||||
className="flex-1 px-6 py-2.5 text-sm rounded bg-white text-black border border-white hover:bg-gray-100 transition-colors"
|
||||
>
|
||||
{t(I18nKey.ENTERPRISE$FORM_SUBMIT)}
|
||||
|
||||
@@ -56,6 +56,7 @@ function EnterpriseCard({
|
||||
<button
|
||||
type="button"
|
||||
onClick={onLearnMore}
|
||||
aria-label={`${learnMoreLabel} ${title}`}
|
||||
className="mt-2 w-fit px-6 py-2.5 text-sm rounded-sm bg-[#050505] text-white border border-[#242424] hover:bg-white hover:text-black transition-colors"
|
||||
>
|
||||
{learnMoreLabel}
|
||||
@@ -117,7 +118,7 @@ export default function InformationRequest() {
|
||||
className="w-full max-w-4xl flex flex-col items-center gap-8 p-6"
|
||||
>
|
||||
{/* Logo */}
|
||||
<OpenHandsLogoWhite width={55} height={55} />
|
||||
<OpenHandsLogoWhite width={56} height={56} />
|
||||
|
||||
{/* Header */}
|
||||
<div className="text-center flex flex-col gap-3">
|
||||
@@ -154,6 +155,7 @@ export default function InformationRequest() {
|
||||
type="button"
|
||||
variant="secondary"
|
||||
onClick={handleBack}
|
||||
aria-label={t(I18nKey.COMMON$BACK)}
|
||||
className="px-6 py-2.5 bg-[#050505] text-white border border-[#242424] hover:bg-white hover:text-black"
|
||||
>
|
||||
{t(I18nKey.COMMON$BACK)}
|
||||
|
||||
Reference in New Issue
Block a user