Skip to content

Migrate from Vuelidate ​

Migrating from Vuelidate is really simple. Regle API is similar to Vuelidate's one on purpose, so the mental model stays the same.

Regle type safety will ensure you make no mistakes while making the migration.

TIP

There is a dedicated regle-migrate-vuelidate Agent Skill that walks an AI coding agent through this migration step by step. Install it with npx skills add victorgarciaesgi/regle.

Imports ​

ts
import { useVuelidate } from '@vuelidate/core';
import { required } from '@vuelidate/validators';
import { useRegle } from '@regle/core';
import { required } from '@regle/rules';
ts
const v$ = useVuelidate(rules, state, options);
const { r$ } = useRegle(state, rules, options);

Helpers ​

ts
import { helpers } from '@vuelidate/validators';
import { withMessage, withParams, withAsync, isEmpty, ... } from '@regle/rules';

Helpers which have been renamed:

  • req -> isFilled
  • len -> getSize
  • regex -> matchRegex
  • forEach -> Deleted, you can use $each directly.
  • unwrap -> use toValue from Vue
    • Parameters are automatically unwrapped when using createRule

Displaying errors ​

Vuelidate:

vue
<template> 
  <p 
    v-for="error of v$.name.$errors"
    :key="error.$uid" 
  >
      {{error.$message}}
  </p>
</template>

Regle:

vue
<template>
  <p
    v-for="(error, index) of r$.$errors.name"
    :key="index"
  >
      {{ error }} 
  </p>
</template>

withMessage ​

Order of parameters are swapped

ts
const rule = helpers.withMessage('This field cannot be empty', required)
const rule = withMessage(required, 'This field cannot be empty')

withParams ​

You can create rules with parameters with createRule helper

ts
const contains = (param) =>
  helpers.withParams(
    { type: 'contains', value: param },
    (value) => !helpers.req(value) || value.includes(param)
  )

const contains = createRule({ 
  validator(value: Maybe<string>, param: Maybe<string>) { 
    return isEmpty(value) || value.includes(param); 
  }, 
  message: ({$params: [param]}) => `Value must contain ${param}`, 
})

Properties ​

Some properties have been renamed

Accessing nested fields ​

ts
v$.nested.child.$error
r$.nested.child.$error

Collections ​

See docs for validating arrays

ts
const v$ = useVuelidate({ 
  collection: { 
    $each: helpers.forEach({ 
      name: { 
        required
      } 
    }) 
  } 
}, {collection: [{name: ''}]})
const { r$ } = useRegle({ collection: [{name: ''}]}, { 
  collection: {
    $each: {
      name: {
        required
      }
    }
  }
})

Methods ​

See docs for type safe output

ts
const result = await v$.$validate();
const { valid, data } = await r$.$validate();

Custom messages ​

If you used to declare this kind of helper methods with Vuelidate:

ts
import {helpers, required, numeric, minLength} from '@vuelidate/validators';

export const requiredValidator = helpers.withMessage(
  'This field is required.',
  required
);
export const numericValidator = helpers.withMessage(
  'Please enter a valid value.',
  numeric
);

export const minLengthValidator = (value) =>
  helpers.withMessage(
    ({ $model, $params }) =>
      `Please enter a value greater than or equal to  ${$params.max}.`,
    minLength(value)
  );

You can remove it and configure it with global config.

TIP

If you use Nuxt , check the Nuxt module documentation for even easier error message sharing.

ts
import { defineRegleConfig } from '@regle/core';
import { withMessage, minLength, required, numeric } from '@regle/rules';

const { useRegle: useCustomRegle } = defineRegleConfig({
  rules: () => ({
    required: withMessage(required, 'This field is required.'),
    numeric: withMessage(numeric, 'Please enter a valid value.'),
    minLength: withMessage(minLength, ({ $value, $params: [max] }) => {
      return `Minimum length is ${max}. Current length: ${$value?.length}`;
    })
  })
})

const { r$ } = useCustomRegle({ name: '' }, {
  name: {
    required,
    numeric,
    minLength: minLength(6)
  }
})

Nested component validation ​

Nested component validation is replaced by Scoped validation.

See docs for scoped validation for more details

ts
// [scoped-config.ts]
import { useScopedRegle, useCollectScope, useRegle } from '@regle/core';

// Parent.vue
const v$ = useVuelidate();
const v$ = useVuelidate({}, {}, {$scope: 'foo'});

const { r$ } = useCollectScope();
const { r$ } = useCollectScope('foo');


// Child.vue

const v$ = useVuelidate(validations, state);
const v$ = useVuelidate(validations, state, { $scope: false });
const v$ = useVuelidate(validations, state, { $scope: 'foo' });
const v$ = useVuelidate(validations, state, { $stopPropagation: true });

const { r$ } = useScopedRegle(state, validations);
const { r$ } = useRegle(state, validations);
const { r$ } = useScopedRegle(state, validations, {namespace: 'foo'});
const { r$ } = useScopedRegle(state, validations);

Validation groups ​

ts
const rules = { 
  number: { isEven },
  nested: {
    word: { required: v => !!v }
  },
  $validationGroups: {
    firstGroup: ['number', 'nested.word']
  }
}
const v$ = useVuelidate(rules, ...);

const { r$ } = useRegle(..., { 
  number: {isEven},
  nested: {
    word: { required: v => !!v }
  }
}, {
  validationGroups: (fields) => ({
    firstGroup: [fields.number, fields.nested.word]
  })
})
r$.$groups.firstGroup

Released under the MIT License. Logo by Johannes Lacourly