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

@softwareproduction/dryvue

v2.0.1

Published

<p align="center"> <img src="public/logo.svg" title="Dryv" width="300"><br> <span style="font-size: 24px; font-weight: bold;">DRY Validation for Distributed Apps</span> </p>

Readme


Dryvue extends DryvJS by providing Vue 3 composables, plugins, and mixins. It seamlessly maps the core validation engine into Vue's reactivity system, yielding computed validation states, automated re-validation on updates, and frictionless integration with the v-model directive.

Like the core package, Dryvue works wonderfully as a standalone validation solution in Vue 3 or as the frontend runtime for full-stack rules generated by Dryv (.NET).

Table of Contents

Installation

npm install @softwareproduction/dryvue

(Requires @softwareproduction/dryvjs and vue ^3.5)

Why Dryvue?

  • Native Vue Reactivity: Extends the DryvJS core so that validation states (text, hasErrors, isDirty) are inherently reactive computed refs.
  • Effortless Component Binding: Provides dedicated composables like useDryvValueProp to create reusable, validation-aware UI input components that interoperate directly with v-model.
  • Zero Boilerplate Validation Forms: Grouped messages and complex state tracking become trivial with structural Vue composables like useDryvGroupSlot.

Setup

Plugin Registration

Register the Dryv plugin to bootstrap Vue-specific reactivity (Vue.reactive()) inside the validation engine:

import { createApp } from 'vue'
import { Dryv } from '@softwareproduction/dryvue'
import App from './App.vue'

createApp(App).use(Dryv).mount('#app')

Static Rule Sets

You can register static rule sets globally, making them accessible by name across all your components:

import { DryvStaticRuleSets } from '@softwareproduction/dryvue'
import { personalDataRules } from './rules/personalData'

app.use(DryvStaticRuleSets, {
  PersonalData: personalDataRules
})

Composables

useDryv(model, ruleSetOrName, options?)

The main workhorse. It attaches a validation session to your reactive model and exposes the validation state.

<template>
  <form @submit.prevent="validate">
    <input v-model="validatable.name.value" />
    <span class="error" v-if="validatable.name.hasErrors">
      {{ validatable.name.text }}
    </span>

    <button type="submit" :disabled="!valid">Submit</button>
    <button type="button" @click="revert" :disabled="!dirty">Revert Changes</button>
  </form>
</template>

<script setup lang="ts">
import { reactive } from 'vue'
import { useDryv } from '@softwareproduction/dryvue'

const data = reactive({ name: '', email: '' })

// Use an inline rule set, or reference a static rule set by string ('PersonalData')
const { validatable, validate, valid, dirty, commit, revert } = useDryv(data, 'PersonalData')
</script>

What useDryv Returns:

  • validatable: A reactive proxy reflecting your model structure, enriched with validation metadata (.value, .text, .hasErrors, etc.)
  • valid: Computed boolean returning true if there are zero errors/warnings.
  • dirty: Computed boolean indicating if data was altered since the last commit.
  • validate(): Triggers full tree validation.
  • clear(): Resets error messages but preserves dirty states.
  • commit() & revert(): Managing dirty baselines.
  • setValidationResult(): Apply a validation payload generated by the server directly into the UI state.

useDryvValueProp(emit, prop, event?)

Easily build customized input components that intelligently sync with Dryvue validators or plain v-models.

<!-- ValidatingInput.vue -->
<template>
  <div>
    <label>{{ label }} <span v-if="validatable.required">*</span></label>
    <input v-model="validatable.value" />
    <span v-if="validatable.hasErrors && !validatable.groupShown">
      {{ validatable.text }}
    </span>
  </div>
</template>

<script setup lang="ts">
import { type DryvValidatable, useDryvValueProp } from '@softwareproduction/dryvue'

const props = defineProps<{
  modelValue: string | DryvValidatable<any> | undefined
  label: string
}>()

const emit = defineEmits(['update:modelValue'])
const validatable = useDryvValueProp(emit, () => props.modelValue)
</script>

In your parent form, you simply drop it in:

<validating-input v-model="validatable.name" label="Name" />
<!-- Or use it independently! -->
<validating-input v-model="plainStringRef" label="Unvalidated Input" />

useDryvGroupSlot(slotOrGroupNames?, groupNames?)

Aggregates related validation messages declared inside a child slot. Perfect for grouping cross-field validations (e.g., "Provide either email OR phone").

<!-- ValidationGroup.vue -->
<template>
  <slot />
  <div v-for="group in groups" :key="group.name">
    <div v-for="{ type, texts } in group.results" :class="type">
      <p v-for="text in texts">{{ text }}</p>
    </div>
  </div>
</template>

<script setup lang="ts">
import { useDryvGroupSlot } from '@softwareproduction/dryvue'
const props = defineProps<{ groups: string[] }>()
const groups = useDryvGroupSlot(props.groups)
</script>

Mapped Validators

When a UI component's internal value differs from your model value (like storing strings but rendering Date objects in a Datepicker), use mapping:

<script setup lang="ts">
const datePickerValue = ref<Date | undefined>()
// Binds the validation state to a custom ref representation
const birthDateValidator = useMappedField('birthDate', datePickerValue)
</script>

Options API Support

For classic Vue architecture, or class-based components (vue-facing-decorator), import dryvValidatableMixin:

import { dryvValidatableMixin } from '@softwareproduction/dryvue'

export default {
  mixins: [dryvValidatableMixin<string>()],
  props: { label: String }
  // Exposes `this.validatable` automatically!
}

Complete Form Example

<template>
  <form @submit.prevent="onSubmit">
    <validation-group :groups="['contact']">
      <validating-input v-model="validatable.firstName" label="First Name" />
      <validating-input v-model="validatable.email" label="Email" />
      <validating-input v-model="validatable.phone" label="Phone" />
    </validation-group>

    <div class="actions">
      <button type="submit" :disabled="!valid">Submit</button>
      <button type="button" @click="revert" :disabled="!dirty">Reset Form</button>
    </div>
  </form>
</template>

<script setup lang="ts">
import { reactive } from 'vue'
import { useDryv } from '@softwareproduction/dryvue'

const data = reactive({ firstName: '', email: '', phone: '' })
const { validatable, validate, valid, dirty, revert, setValidationResult } =
  useDryv(data, 'PersonalData')

async function onSubmit() {
  const result = await validate()
  if (!result.success) return

  const response = await fetch('/api/submit', {
    method: 'POST',
    body: JSON.stringify(data)
  })
  
  const serverResult = await response.json()
  if (!serverResult.success) {
    // Applies server responses mapped to the corresponding fields
    setValidationResult(serverResult) 
  }
}
</script>

Using with Dryv (C#/.NET)

Dryvue is intended to gracefully execute validation rules provided by Dryv (.NET).

Because Dryvue completely encapsulates the dryvjs core, all integrations including runtime parameter fetching, generated TypeScript models, and auto-handling of dynamic backend async controllers work out of the box via the useDryv composable.

For a comprehensive guide on integrating your C# backend with Vue, including Server-Rendered Tag Helpers and Build-Time Code Generation strategies, see the Root README.

License

MIT