Josh Winters
Josh Winters

Reputation: 855

How do I style the borders of a formik error field?

I know how to style it with regular form inputs/selects/etc, but I have switched from using those to Formik Field, and the above doesn't work the same way.

<Formik
  initialValues={{
    example: ''
  }}
  validate={(values) => {
    const errors = {};

    if (!values.example) errors.example = 'Required';

    return errors;

  }}
  onSubmit={this.handleSubmit}
  render={formProps => {
    return (
      <Form>
        <Field type='text' name='example' />
        <ErrorMessage name='example' />
      </Form>
    )
  }} />

So how would I change the border of the input from whatever it is normally to red if it is empty on submit?

Upvotes: 5

Views: 17615

Answers (5)

ManuelTS
ManuelTS

Reputation: 356

In your top level (S)CSS file, paste

.formkit-outer[data-invalid] {
  .formkit-label, .formkit-messages {
    @apply tw-text-red;
  }

  input {
    @apply tw-border-red tw-outline-red;
  }
}

to have for all form-kit components the following label + input on error: enter image description here

Note, I used tailwind with the prefix "tw-". You can use your own classes here.

/Edit: Sorry I read FormKit! But maybe a similar way helps others here. I will not delete this post for that reason.

Upvotes: 0

T30
T30

Reputation: 12232

I've built a Component using react-bootstrap based on @gene b. answer

It gets the meta field from the useField hook and passes eventual errors to the isInvalid prop:

isInvalid={meta.touched && meta.error}

Full component for text input:

import React from 'react';
import { useField } from 'formik';
import Form from 'react-bootstrap/Form';

export default function TextInput (props) {
  const [field, meta] = useField(props);
  return (
      <Form.Group controlId={props.name}>
        <Form.Label>{props.label}</Form.Label>
        <Form.Control
          name={props.name}
          isInvalid={meta.touched && meta.error}
          {...field}
        />
        <Form.Control.Feedback type="invalid">
          {meta.error}
        </Form.Control.Feedback>
      </Form.Group>
  );
};

Usage

import { Form } from 'formik';
import TextInput from './textInput';
<Form>
  <TextInput name="username" label="Username"/>
</Form>

It's worth mention that exists also the isValid prop that works exactly the opposite way, adding green flag on valid fields.

Upvotes: 0

gene b.
gene b.

Reputation: 11996

FYI, the workaround that works for styling error fields (e.g. borders) is given here:

https://stackoverflow.com/a/66395574/1005607

Pretty astonishing that Formik doesn't provide this functionality out of the box, and you have to extend <Field> with custom code.

But in general, you're not supposed to use Formik's own <Field> component. Instead you should wire Formik to a component library like Material UI or React-Bootstrap which exposes isInvalid={..} or error={..} props on its components. That will allow you to style your controls properly. Here's an example of how to wire Formik to React-Bootstrap: https://react-bootstrap.github.io/components/forms/#forms-validation-libraries If you type into a control, you'll see how its style changes depending on errors.

Upvotes: 3

James Poulose
James Poulose

Reputation: 3833

When i try the technique suggested in the accepted answer for ErrorMessage component using

<ErrorMessage name="propertyName" style={{ color: 'red'}}/>

it didn't work for me. It worked when i enclosed it inside another container though.

<div style={{ color: 'red'}}>
     <ErrorMessage name="propertyName" />
</div>

Hope this helps someone.

Upvotes: 6

ron4ex
ron4ex

Reputation: 1083

Solution

You can style Field and ErrorMessage components provided by Formik just like you would style any other component in react. I created a working demo for you here: https://stackblitz.com/edit/react-formik-field-error-styles

Have a look. Continue reading for explanation.

Explanation

The simplest way would be to use style prop:

function getStyles(errors, fieldName) {
  if (getIn(errors, fieldName)) {
    return {
      border: '1px solid red'
    }
  }
}

...

<Field style={getStyles(formProps.errors, 'example')} type='text' name='example' />

...

However, if you need manageable customizations, I would recommend you create a custom component. Field provides you with a component prop to which you can assign your own custom component like CustomInput or something like so:


function getStyles(errors, fieldName) {
  if (getIn(errors, fieldName)) {
    return {
      border: '1px solid red'
    }
  }
}

function CustomInput({ field, form: { errors } }) {

  return <div>
    <input {...field} style={getStyles(errors, field.name)} />
    <ErrorMessage name={field.name} />
  </div>
}

...

<Field component={CustomInput} type="text" name="example" />

...

Upvotes: 7

Related Questions