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

astro-snipform

v0.1.2

Published

Typesafe Astro integration and components for SnipForm — directive-driven form backend for static sites

Downloads

307

Readme

Astro Snipform

astro-snipform

Typesafe Astro integration and components for SnipForm — directive-driven form backend for static sites.

Installation

npm install astro-snipform

Setup

Add the integration to your Astro config:

// astro.config.mjs
import { defineConfig } from "astro/config";
import snipform from "astro-snipform";

export default defineConfig({
  integrations: [snipform()],
});

This automatically injects the SnipForm CDN script on all pages.

Integration Options

| Option | Type | Default | Description | | ----------------- | --------- | --------------------- | ---------------------------------------------------------------------------- | | cdnUrl | string | Official SnipForm CDN | Override the CDN URL | | scriptInjection | boolean | true | Set to false to disable auto-injection and use <SnipFormScript> per-page |

snipform({
  scriptInjection: false, // manually control which pages load the script
});

Components

Import components from astro-snipform/components:

---
import { SnipForm, Field, Input, Textarea, Select, ErrorMessage, ValidMessage, SubmitButton, SuccessContent, SnipFormScript } from 'astro-snipform/components';
---

<SnipForm>

Form container. Wraps your form fields and connects to the SnipForm backend.

| Prop | Type | Description | | ------------- | ------------------- | -------------------------------------------------- | --------------------------------------------- | | key | string (required) | Your form's unique key from the SnipForm dashboard | | transition | number | 'none' | Fade transition duration in ms (default: 150) | | mode | 'test' | Enable test mode — form won't actually submit | | readability | false | Disable the readability directive parser | | namespace | false | Disable the namespace directive parser | | shorthand | false | Disable the shorthand directive parser |

<SnipForm key="your-form-key">
  <!-- form fields here -->
</SnipForm>

<Field>

Compound component that renders an input element with validation and an auto-hidden error message.

| Prop | Type | Description | | ------------------- | ------------------- | ----------------------------------------------------------------- | ----------- | --------------------------------- | | name | string (required) | Field name (used for input name attr and error binding) | | validate | ValidateProp | Validation rules (see Validation) | | as | 'input' | 'select' | 'textarea' | Element type (default: 'input') | | errorMessageClass | string | CSS class for the auto-generated error message span | | hideError | boolean | Suppress built-in error element (use standalone <ErrorMessage>) | | errorClass | string | CSS class added to the input on error | | errorStyle | string | Inline style added to the input on error | | validClass | string | CSS class added to the input when valid | | validStyle | string | Inline style added to the input when valid |

<Field
  name="email"
  type="email"
  validate={{ required: 'Enter your email', email: 'Invalid email' }}
  errorClass="border-red-500"
  validClass="border-green-500"
/>

<Field name="role" as="select" validate={{ required: 'Pick a role' }}>
  <option value="">Select...</option>
  <option value="dev">Developer</option>
  <option value="design">Designer</option>
</Field>

<Input>

Standalone input element with validation and state styling (no built-in error message).

| Prop | Type | Description | | ------------ | -------------- | ----------------------------- | | validate | ValidateProp | Validation rules | | errorClass | string | CSS class added on error | | errorStyle | string | Inline style added on error | | validClass | string | CSS class added when valid | | validStyle | string | Inline style added when valid |

Also accepts all standard HTML <input> attributes.

<Input name="email" type="email" validate={{ required: 'Required', email: 'Invalid' }} />

<Textarea>

Same props as <Input>, renders a <textarea>.

<Textarea name="message" validate={{ required: 'Please enter a message' }} />

<Select>

Same props as <Input>, renders a <select>.

<Select name="country" validate="required">
  <option value="">Choose...</option>
  <option value="us">United States</option>
</Select>

<ErrorMessage>

Displays a validation error message for a specific field. Hidden by default, shown when the field has an error.

| Prop | Type | Default | Description | | ---------- | --------- | ---------- | ------------------------------------------------------- | | field | string | (required) | The field name to watch | | as | string | 'span' | HTML element to render | | visible | boolean | false | Keep element visible at all times (skip display:none) | | showOnly | boolean | false | Show element without injecting error text | | text | string | | Set custom text on error | | class | string | | CSS class added on error | | style | string | | Inline style added on error |

<ErrorMessage field="email" class="text-red-500 text-sm" />

<ValidMessage>

Displays content when a field passes validation.

| Prop | Type | Default | Description | | ------- | --------- | ---------- | -------------------------------- | | field | string | (required) | The field name to watch | | as | string | 'span' | HTML element to render | | show | boolean | | Show element when field is valid | | hide | boolean | | Hide element when field is valid | | text | string | | Set custom text when valid | | class | string | | CSS class added when valid | | style | string | | Inline style added when valid |

<ValidMessage field="email" class="text-green-500 text-sm">Looks good!</ValidMessage>

<SubmitButton>

Submit button with loading/submission state directives.

| Prop | Type | Description | | --------------- | --------- | ----------------------------------- | | onSubmitShow | boolean | Show this element during submission | | onSubmitHide | boolean | Hide this element during submission | | onSubmitText | string | Set text during submission | | onSubmitClass | string | Add CSS class during submission | | onSubmitStyle | string | Add inline style during submission |

<SubmitButton onSubmitText="Sending..." onSubmitClass="opacity-50 cursor-wait">
  Send Message
</SubmitButton>

<SuccessContent>

Content shown after a successful form submission. Hidden by default.

<SuccessContent>
  <p>Thanks! We'll be in touch.</p>
</SuccessContent>

<SnipFormScript>

Standalone script tag for the SnipForm CDN. Use when scriptInjection: false is set in the integration options.

| Prop | Type | Default | Description | | ----- | -------- | --------------------- | ---------------- | | src | string | Official SnipForm CDN | CDN URL override |

<SnipFormScript />

Validation

The validate prop accepts multiple formats:

<!-- Single rule -->
<Input name="name" validate="required" />

<!-- Multiple rules (array) -->
<Input name="age" validate={['required', 'integer']} />

<!-- Object map with custom messages -->
<Input name="email" validate={{ required: 'Email is required', email: 'Invalid email format' }} />

<!-- Parameterized rules -->
<Input name="age" validate={{ required: 'Required', 'between[18,99]': 'Must be 18-99' }} />

Available Rules

Simple rules: required, email, url, active_url, boolean, accepted, numeric, integer, alpha, alpha_num, alpha_dash, date, ip, ipv4, ipv6, uuid

Parameterized rules: max[n], min[n], between[n,m], min_length[n], max_length[n], starts_with[str], ends_with[str], doesnt_start_with[str], doesnt_end_with[str], in[a,b,c], not_in[a,b,c], after[date], before[date], after_or_equal[date], before_or_equal[date], date_equals[date], same[field], different[field], gt[field], gte[field], lt[field], lte[field]

Full Example

---
import { SnipForm, Field, SubmitButton, SuccessContent } from 'astro-snipform/components';
---

<SnipForm key="contact-form">
  <Field
    name="name"
    type="text"
    placeholder="Your name"
    validate={{ required: 'Name is required' }}
    errorClass="border-red-500"
  />

  <Field
    name="email"
    type="email"
    placeholder="[email protected]"
    validate={{ required: 'Email is required', email: 'Invalid email' }}
    errorClass="border-red-500"
  />

  <Field
    name="message"
    as="textarea"
    placeholder="Your message"
    validate={{ required: 'Message is required', 'min_length[10]': 'At least 10 characters' }}
    errorClass="border-red-500"
  />

  <SubmitButton onSubmitText="Sending..." onSubmitClass="opacity-50">
    Send
  </SubmitButton>

  <SuccessContent>
    <p>Thanks for reaching out! We'll get back to you soon.</p>
  </SuccessContent>
</SnipForm>

License

MIT