UNPKG

nuqs-zod-adapter

Version:

A Nuqs adapter to safely bind Zod schemas with query parameters using type safety, debouncing and auto-reset support.

159 lines (113 loc) 4.43 kB
# nuqs-zod-adapter A nuqs adapter for using zod schemas and it's defaults together without having to repeat code unnecessarily ## Fully compatible with `zod` schemas and defaults ### How it will look like: `yourwebsite.com/search?title=cool+video&category=a` (All using Zod schemas & default values from them, 0 nuqs validation) ## Features - Infer types directly from Zod schema - Debouncing feature (completely customizable) - Optional reset of other query keys - Compatible with all Nuqs options (`shallow`, `history`, etc.) - Parses enums, numbers, booleans, unions, defaults... automatically ## Install ```bash npm install nuqs-zod-adapter ``` ## Usage example Let's say you want to create a filter for a search form which also includes category filtering that syncs with the URL using Nuqs, but with proper type safety, debouncing and optional reset of other keys (e.g., reset page on title change) and without having to duplicate the defaults ### 1. Define your Zod schema ```typescript import { z } from 'zod' export const paramsFields = { title: z.string().optional(), category: z.enum(['a', 'b', 'c']).default('a'), } ``` - **Title:** It's optional but not required, which means that it might not exist in the query - **Category:** Also optional, however its default value will be A when the query is empty ### 2. Use the hook to connect a param to the URL Once your schema is defined, you can plug individual fields into the useSafeQueryStateFromZod hook. Here's how to do it for the category param: ```typescript import { useSafeQueryStateFromZod } from 'nuqs-zod-adapter' import { paramsFields } from './schema' const [category, setCategory] = useSafeQueryStateFromZod( 'category', paramsFields.category, { delay: 200, // debounce delay (optional) resetKeys: ['page'], // reset other query params when this changes shallow: true // use shallow routing // and all the nuqs options available } ) ``` Syncs category with the query string Applies Zod validation and type inference Uses "a" as the default value if none is provided Debounces updates to avoid router spam Optionally resets other keys like "page" ### 3. Using it in your component Once you have `category` and `setCategory`, you can bind them directly to a `<select>` input, radio buttons, or any other component like this: ```typescript <select value={category} onChange={(e) => setCategory(e.target.value as typeof category)} className="border px-3 py-2 rounded" > <option value="a">Category A</option> <option value="b">Category B</option> <option value="c">Category C</option> </select> ``` > ⚠️ Make sure to cast e.target.value to the correct type (e.g. as typeof category) if TypeScript complains. ### 4. Combine multiple query params You can use the hook multiple times, once per field, to build a full filter system connected to the URL #### Category & Title together ```typescript const [title, setTitle] = useSafeQueryStateFromZod( 'title', paramsFields.title, { delay: 300, resetKeys: ['page'], shallow: true } ) const [category, setCategory] = useSafeQueryStateFromZod( 'category', paramsFields.category, { shallow: true } ) ``` Now they will be both synced, if you type a title on the form, it will display on the URL like this: **If there is no title:** - `yourwebsite.com` **If there is a title:** - `yourwebsite.com?title=super+title` **If there is a title AND a category:** - `yourwebsite.com?title=super+title&category=a` **If there is only a category:** - `yourwebsite.com?category=a` ## Resetting the values What if you want to reset all the values with a button? Well, it's as simple as adding a "onClick" function and using the exported setters to set the values to their defaults, here is an example: ```typescript <button onClick={() => { setTitle('') setCategory('A') // or paramsFields.category._def.defaultValue() if you want to extract it }} className="px-4 py-2 bg-gray-200 rounded hover:bg-gray-300" > Reset Filters </button> ``` As simple as that. ## 🛠 Contributing Contributions are welcome! If you have improvements, bug fixes or new ideas, feel free to submit a pull request or open an issue. ## 👤 Author **Diego Rodríguez** [LinkedIn](https://www.linkedin.com/in/bydiego/) [GitHub](https://github.com/dewstouh)