((props, ref) => {
+ const {
+ ariaDescribedby,
+ errorMessage,
+ className,
+ helpMessagePrimary,
+ helpMessagePrimaryClassName,
+ helpMessageSecondary,
+ helpMessageSecondaryClassName,
+ id,
+ label,
+ required,
+ type = 'text',
+ ...restInputProps
+ } = props;
+
+ const inputErrorId = `input-${id}-error`;
+ const inputHelpMessagePrimaryId = `input-${id}-help-primary`;
+ const inputHelpMessageSecondaryId = `input-${id}-help-secondary`;
+ const inputLabelId = `input-${id}-label`;
+ const inputWrapperId = `input-${id}`;
+
+ function getAriaDescribedby() {
+ const describedby = [];
+ if (ariaDescribedby) describedby.push(ariaDescribedby);
+ if (helpMessagePrimary) describedby.push(inputHelpMessagePrimaryId);
+ if (helpMessageSecondary) describedby.push(inputHelpMessageSecondaryId);
+ return describedby.length > 0 ? describedby.join(' ') : undefined;
+ }
+
+ return (
+
+ );
+});
+
+InputField.displayName = 'InputField';
+
+export { InputField };
diff --git a/frontend/app/components/input-help.tsx b/frontend/app/components/input-help.tsx
new file mode 100644
index 00000000..906b9c4d
--- /dev/null
+++ b/frontend/app/components/input-help.tsx
@@ -0,0 +1,17 @@
+import type { ComponentProps, ReactNode } from 'react';
+
+import { cn } from '~/utils/tailwind-utils';
+
+export interface InputHelpProps extends ComponentProps<'span'> {
+ children: ReactNode;
+ id: string;
+}
+
+export function InputHelp(props: InputHelpProps) {
+ const { children, className, ...restProps } = props;
+ return (
+
+ {children}
+
+ );
+}
diff --git a/frontend/app/components/input-label.tsx b/frontend/app/components/input-label.tsx
new file mode 100644
index 00000000..572e8e74
--- /dev/null
+++ b/frontend/app/components/input-label.tsx
@@ -0,0 +1,18 @@
+import type { ComponentProps, ReactNode } from 'react';
+
+import { cn } from '~/utils/tailwind-utils';
+
+export interface InputLabelProps extends ComponentProps<'label'> {
+ children: ReactNode;
+ id: string;
+}
+
+export function InputLabel(props: InputLabelProps) {
+ const { children, className, ...restProps } = props;
+
+ return (
+
+ );
+}