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

@ultraviolet/form

v6.0.15

Published

Ultraviolet Form

Downloads

14,431

Readme

Ultraviolet Form

npm version

Ultraviolet Form is an extension of Ultraviolet UI including everything to build forms using React. It is using React Hook Form under the hood.

Get Started

$ pnpm add @ultraviolet/form @ultraviolet/themes

Usage

To use the library you need to put a ThemeProvider from @ultraviolet/themes with the theme that comes from the same package or from @ultraviolet/ui then wrap all your fields inside a Form:

import { ThemeProvider } from '@ultraviolet/themes'
import { Form, TextInputField } from '@ultraviolet/form'
import { theme } from '@ultraviolet/ui' // or import { theme } from "@ultraviolet/themes
import { useForm } from '@ultraviolet/form'
import '@ultraviolet/ui/styles'

// Here are the input types of your form
type FormValues = {
  firstName: string
  lastName: string
}

// We define the initial values of the form
const INITIAL_VALUES: FormValues = {
  firstName: 'Marc',
  lastName: 'Scout',
} as const

export default function App() {
  const methods = useForm<FormValues>({
    defaultValues: INITIAL_VALUES,
    mode: 'onChange',
  })
  
  const formErrors = {
    required: () => 'This field is required',
    // Add more error messages as needed for min, max, etc.
  }
  
  const onSubmit = async ({
    firstName,
    lastName,
  }: FormValues) => {
    // Add your form submission logic here
    console.log('Form submitted with values:', { firstName, lastName })
  }

  return (
    <ThemeProvider theme={theme}>
      <Form methods={methods} errors={formErrors} onSubmit={onSubmit}>
        <TextInputField name="firstName" />
        <TextInputField name="lastName" />
      </Form>
    </ThemeProvider>
  )
}

useWatch Hook

You can use the useWatch hook from @ultraviolet/form to watch specific fields in your form thus subscribing to their changes. It can be useful for displaying real-time updates or triggering actions based on field values.

// FirstNameWatched is a component that needs to watch the firstName field
function FirstNameWatched({ control }: { control: Control<FormInputs> }) {
  const firstName = useWatch({
    control,
    name: "firstName",
  })

  return <p>Watch: {firstName}</p>
}

export default function App() {
  ... // same setup as before
  
  return (
    <ThemeProvider theme={theme}>
      <Form methods={methods} errors={formErrors} onSubmit={onSubmit}>
        <TextInputField name="firstName" />
        <TextInputField name="lastName" />
        
        <FirstNameWatched control={control} />
      </Form>
    </ThemeProvider>
  )
}

Form Validation

You can validate each fields passing either regex or validate to any field that support it. Not all field supports regex for instance but all fields support validate. In addition many field support required, minLength, maxLength, min, and max validation.

Native Validation

<TextInputField 
  name="firstName" 
  required
  minLength={2}
  maxLength={30}
/>

With Validate

const EXISTING_IPS = ['192.168.1.1']

<TextInputField 
  name="ip" 
  validate={{
  ipAlreadyExists: (ip: string) =>
    EXISTING_IPS.includes(ip) ? 'This ip is already in use' : undefined,
  }}
/>

With Regex

<TextInputField 
  name="email"
  regex={[/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/]}
/>

We all know regex can be tricky, so to help you with that we made Scaleway Regex library that contains a lot of useful regexes that you can use in your forms. You can easily install it with:

pnpm add @scaleway/regex

You can then use it like this:

import { email } from '@scaleway/regex'

<TextInputField 
  name="email"
  regex={[email]}
/>

Check all the available regexes in the Scaleway Regex file

Resolvers | Zod

You can use Zod for validation by integrating it with @ultraviolet/form. First you will need to install Zod and the Zod resolver for React Hook Form:

pnpm add zod @hookform/resolvers

Here's how you can do it:

import { ThemeProvider, theme  } from '@ultraviolet/themes'
import { Form, TextInputField } from '@ultraviolet/form'
import { useForm } from '@ultraviolet/form'
import { zodResolver } from "@hookform/resolvers/zod"
import * as z from "zod"

// Define your Zod schema for validation
const schema = z.object({
  firstName: z.string(),
  lastName: z.string(),
})

// Types are inferred from the Zod schema
type FormValues = z.infer<typeof schema>

// We define the initial values of the form
const INITIAL_VALUES: FormValues = {
  firstName: 'Marc',
  lastName: 'Scout',
} as const

export default function App() {
  const methods = useForm<FormValues>({
    defaultValues: INITIAL_VALUES,
    resolver: zodResolver(schema),
    mode: 'onChange',
  })
  
  const formErrors = {
    required: () => 'This field is required',
    // Add more error messages as needed for min, max, etc.
  }
  
  const onSubmit = async ({
    firstName,
    lastName,
  }: FormValues) => {
    // Add your form submission logic here
    console.log('Form submitted with values:', { firstName, lastName })
  }

  return (
    <ThemeProvider theme={theme}>
      <Form methods={methods} errors={formErrors} onSubmit={onSubmit}>
        <TextInputField name="firstName" />
        <TextInputField name="lastName" />
      </Form>
    </ThemeProvider>
  )
}

If you need more examples with other resolvers we invite you to check React Hook Form Resolvers Documentation

Documentation

Checkout our documentation website.