Skip to content

Instantly share code, notes, and snippets.

@Abdallatif
Created November 23, 2021 21:57
Show Gist options
  • Select an option

  • Save Abdallatif/5943f505505b2d1a01810ee061f4bc47 to your computer and use it in GitHub Desktop.

Select an option

Save Abdallatif/5943f505505b2d1a01810ee061f4bc47 to your computer and use it in GitHub Desktop.
Remix Field

This component was inspired by Formik and the jokes demo from Remix. This is just an experiment it's not meant for production use (yet).

interface FormActionData {
  fieldErrors?: Record<string, string>;
  fields?: Record<string, string>;
}

interface Field {
  name: string;
  label: string;
  type?: string;
  as?: "input" | "textarea";
}

const Field: FunctionComponent<Field> = ({
  name,
  label,
  as: As = "input",
  type,
}) => {
  const actionData = useActionData<FormActionData | undefined>();
  return (
    <div>
      <label>
        {label}:{" "}
        <As
          defaultValue={actionData?.fields?.[name]}
          aria-invalid={Boolean(actionData?.fieldErrors?.[name]) || undefined}
          aria-describedby={
            actionData?.fieldErrors?.[name] ? `${name}-error` : undefined
          }
          type={type}
          name={name}
        />
      </label>
      {actionData?.fieldErrors?.[name] ? (
        <p className="form-validation-error" role="alert" id={`${name}-error`}>
          {actionData.fieldErrors?.[name] ?? ""}
        </p>
      ) : null}
    </div>
  );
};

and use it like

export default function NewJokeRoute() {
  return (
    <div>
      <p>Add your own hilarious joke</p>
      <Form method="post">
        <Field type="text" name="name" label="Name" />
        <Field as="textarea" name="content" label="Content" />
        <div>
          <button type="submit" className="button">
            Add
          </button>
        </div>
      </Form>
    </div>
  );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment