Skip to content

Usage with Pinia

Since Regle is headless, you can use it anywhere in your app — whether in a composable or a store.

Using a Pinia store is an excellent way to avoid prop drilling with multiple properties while maintaining type inference seamlessly across your components.

Using regle in a Pinia store

ts
import { required, minLength, email } from '@regle/rules';
import { defineStore } from 'pinia';
import { useRegle } from '@regle/core';

export const useDemoStore = defineStore('demo-store', () => {
  const { r$ } = useRegle({ email: '' }, {
    email: { required, minLength: minLength(4), email }
  })

  return {
    r$
  }
})
vue
<template>
  <input v-model='r$.$value.email' placeholder='Type your email'/>
  <button type="button" @click="r$.$reset({toInitialState: true})">Reset</button>
</template>

<script setup lang='ts'>
import { useDemoStore } from './demo.store';
import { storeToRefs } from 'pinia';

const demoStore = useDemoStore();
const { r$ } = storeToRefs(demoStore);

</script>
vue
<template>
  <ul>
    <li v-for="error of r$.$errors.email" :key='error'>
      {{ error }}
    </li>
  </ul>
</template>

<script setup lang='ts'>
import { useDemoStore } from './demo.store';
import { storeToRefs } from 'pinia';

const demoStore = useDemoStore();
const { r$ } = storeToRefs(demoStore);
</script>

Component A:

Component B:

No errors

Avoid hydration issues

If you use store.$dispose() or Nuxt in SSR mode, you may encounter this error:

Uncaught TypeError: 'set' on proxy: trap returned falsish for property 'xxx'

This is because Pinia tries to hydrate the stateful property r$. To avoid this, you can use skipHydrate

pinia.store.ts
ts
import { skipHydrate } from 'pinia';

export const usePiniaStore = defineStore('pinia-store', () => {
  const {r$} = useRegle(/** */)

  return { r$: skipHydrate(r$) };
});

Released under the MIT License. Logo by Johannes Lacourly