npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

gib-validate

v1.0.2

Published

gib-validate is a lightweight validation helper for Vue 3 (Composition API). It provides a set of common validation rules and a `useValidation` hook to validate reactive form state.

Readme

gib-validate

gib-validate is a lightweight validation helper for Vue 3 (Composition API). It provides a set of common validation rules and a useValidation hook to validate reactive form state.

Quick summary

  • Peer dependency: Vue 3
  • Main exports: useValidation, a collection of rules (for example required, minLength, isEmail) and types (ValidationState, ValidationRule, ValidationRules, Errors).

Installation

npm install gib-validate

Basic usage (Vue 3, Composition API)

import { reactive } from 'vue';
import { useValidation, required, minLength, isEmail } from 'gib-validate';

const form = reactive({ email: '', password: '' });

const rules = {
  email: [required('Email is required'), isEmail('Invalid email')],
  password: [required(), minLength(8, 'Minimum 8 characters')]
};

// useValidation returns ComputedRef<ValidationState<T>>
const v = useValidation(form, rules);

// In script: access via v.value (v is a ComputedRef)
// v.value.$errors, v.value.$touch(), v.value.$reset(), etc.
<template>
  <input v-model="form.email" />
  <div v-if="v.$errors.email">{{ v.$errors.email[0] }}</div>

  <input v-model="form.password" type="password" />
  <div v-if="v.$errors.password">{{ v.$errors.password[0] }}</div>

  <button @click="v.$touch()">Submit</button>
</template>

API overview

  • useValidation:
    • Returns a computed validation state exposing:
      • $touch() — mark form as touched (marks all fields and child validators)
      • $reset() — reset dirty/touched state
      • $touchField(field | fields) — mark one or more fields as touched
      • $dirty: boolean — whether the form was attempted/submitted
      • $errors: Errors<T> — visible errors (only for touched fields)
      • $silentErrors: Errors<T> — all validation errors regardless of touched state
      • $children — support for nested validators (via provide/inject)

Dynamic rules

The useValidation function now supports dynamic rules through computed properties. This allows you to change validation rules based on reactive conditions:

import { reactive, ref, computed } from 'vue';
import { useValidation, required, minLength } from 'gib-validate';

const form = reactive({ password: '' });
const requirePassword = ref(false);

// Dynamic rules based on reactive conditions
const rules = computed(() => ({
  password: requirePassword.value 
    ? [required('Password is required'), minLength(8, 'Minimum 8 characters')] 
    : [minLength(8, 'Minimum 8 characters')]
}));

const v = useValidation(form, rules);

// Later, when you change requirePassword, the validation rules will automatically update
requirePassword.value = true;
  • useNamedValidation:

    • Returns a reactive ref to a named validation:
      • Allows reactive access to named validations
      • Updates automatically when the named validation changes
      • Returns undefined if no validation is registered with that name
  • Validation rules: a ValidationRule<T> returns true (success) or a string (error message). Rules can be synchronous or asynchronous (return Promise<string|boolean>).

Types (short):

  • ValidationRule<T> = (value: T) => string | boolean | Promise<string | boolean>
  • ValidationRules<T> = { [K in keyof T]?: ValidationRule<T[K]>[] }
  • Errors<T> = Partial<Record<keyof T, string[]>>

Built-in rules

The package exports a set of common rules from src/rules:

  • required(error?)
  • requiredIf(...)
  • oneOf(...)
  • isEmail(...)
  • isUrl(...)
  • isPhone(...)
  • isNumeric(...)
  • isInteger(...)
  • isDate(...)
  • isPastDate(...), isFutureDate(...)
  • isPassword(...)
  • fileType(...), fileSizeLessThan(...)
  • equalTo(...)
  • contains(...)
  • between(...)
  • minLength(...), maxLength(...)

Each rule typically accepts parameters (for example, minLength(8, 'Too short')) and returns a function that will be invoked with the value to validate.

Example custom rules:

// sync rule
const startsWithA = (v: string) => (v.startsWith('A') ? true : 'Must start with A');

// async rule
const uniqueEmail = async (email: string) => {
  const ok = await checkEmailOnServer(email); // your API call
  return ok ? true : 'Email already taken';
};

Behavior and notes

  • The hook watches the provided state and runs validation rules automatically, updating $silentErrors.
  • $errors contains only errors for fields that are touched (or after calling $touch()).
  • Rules return true on success or a string with an error message on failure. Async rules are supported.
  • Nested validators are supported: child validators register with a parent via provide/inject.

Nested validation

gib-validate supports nested validators across component boundaries. When a child component calls useValidation, it will automatically register its validation state with a parent validator (if a parent is present) using provide/inject. This allows the parent to trigger child validation ($touch) and for child validators to be reset together with the parent.

Key points:

  • Child validators register automatically; you don't need to pass the parent explicitly.
  • Parent's $touch() will call $touch() on registered children. Parent's $reset() will reset children as well.
  • Registered children appear under the parent's $children ref (keys are assigned internally, in insertion order).

Simple example (Parent + Child component):

Parent component (script setup):

import { reactive } from 'vue';
import { useValidation, required } from 'gib-validate';
import AddressField from './AddressField.vue';

const form = reactive({ name: '', address: { street: '', city: '' } });

const rules = {
  name: [required('Name required')]
};

const v = useValidation(form, rules);

// trigger parent + child validation before submit
function onSubmit() {
  v.value.$touch(); // will also touch children
  // check parent errors and optionally inspect children via v.value.$children
}

Child component AddressField.vue (script setup):

import { toRef } from 'vue';
import { useValidation, required, minLength } from 'gib-validate';

// props: { address }
const street = toRef(props.address, 'street');
const city = toRef(props.address, 'city');

const rules = {
  street: [required('Street is required')],
  city: [required('City is required'), minLength(2, 'Too short')]
};

// useValidation in the child registers itself with the parent validator automatically
const v = useValidation(props.address, rules);

How to inspect child errors from parent:

// v is parent's computed validation state
// parent silent errors
console.log(v.value.$silentErrors);

// iterate registered children
for (const [key, childState] of Object.entries(v.value.$children.value)) {
  console.log('child errors', key, childState.$errors);
}

Note: child validators are stored under $children as a Ref<Record<string, ValidationState>>; the keys are created internally and may change when children mount/unmount. Use $children for programmatic inspection only — prefer using high-level flows like v.$touch() on the parent which will propagate to children.

Named validations

gib-validate also supports naming your validations to make them easier to access and manage. You can name both top-level validations and nested children validations.

Named top-level validations

import { reactive } from 'vue';
import { useValidation, required, useNamedValidation } from 'gib-validate';

const form = reactive({ name: '' });
const rules = {
  name: [required('Name is required')]
};

// Register validation with a name
const v = useValidation(form, rules, 'userForm');

// Later, retrieve the validation by name from anywhere in your app
// useNamedValidation returns a reactive ref that updates when the validation changes
const userFormValidation = useNamedValidation('userForm');
userFormValidation.value?.$touch(); // Trigger validation

Named nested children validations

When creating nested validations, you can provide names for children to make them easier to identify:

// Parent component
import { reactive } from 'vue';
import { useValidation, required } from 'gib-validate';

const form = reactive({ name: '', address: { street: '', city: '' } });
const rules = {
  name: [required('Name required')]
};

// Parent validation (without name)
const parentValidation = useValidation(form, rules);

// Child component
import { toRef } from 'vue';
import { useValidation, required, minLength } from 'gib-validate';

const address = toRef(props, 'address');
const rules = {
  street: [required('Street is required')],
  city: [required('City is required'), minLength(2, 'Too short')]
};

// Child validation with name - this will appear in parent.$children under the key 'addressForm'
const addressValidation = useValidation(address, rules, 'addressForm');

// Now you can access the child by name:
// parentValidation.value.$children.value['addressForm']

This makes it easier to work with nested validations as you can directly access children by meaningful names rather than numeric indices. </file_content>

</file_content>