Skip to content

hsnards/qif

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

20 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🎯 Qif

Powerful filtering system for React.js applications

NPM Size GitHub contributors GitHub license PRs Welcome

✨ Features

  • πŸ”„ Centralized State System - Efficient application state management
  • 🎨 Headless UI - Flexible, unstyled components for full customization
  • 🧩 Composable Components - Build complex UIs with simple, reusable parts
  • πŸ”— URL Sync - Built on nuqs for robust URL state management
  • πŸ› οΈ Developer-Friendly API - Intuitive design for seamless development
  • ⚑ Performance Optimized - Smooth handling of large datasets

πŸ“¦ Installation

# Using npm
npm install react-qif nuqs

# Using yarn
yarn add react-qif nuqs

πŸš€ Quick Start

import { useFilters, FiltersProvider, useFiltersContext } from 'react-qif';
import { parseAsString } from 'nuqs';

type FiltersType = {
  search: string;
  category: string;
};

const App = () => {
  const filtersInstance = useFilters({
    parsers: {
      search: parseAsString.withDefault(''),
      category: parseAsString.withDefault('test')
    }
  });

  return (
    <FiltersProvider instance={filtersInstance}>
      <SearchFilter />
    </FiltersProvider>
  );
};

const SearchFilter = () => {
  const { getValue, setValue } = useFiltersContext<FiltersType>();

  return (
    <input
      value={getValue('search') || ''}
      onChange={(e) => setValue('search', e.target.value)}
    />
  );
};

πŸ”§ Setup

1. Configure NuqsAdapter

For Next.js:

import { NuqsAdapter } from 'nuqs/adapters/next';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <NuqsAdapter>{children}</NuqsAdapter>
      </body>
    </html>
  );
}

For React:

import { NuqsAdapter } from 'nuqs/adapters/react';

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <NuqsAdapter>
      <App />
    </NuqsAdapter>
  </StrictMode>
);

πŸ“š API Reference

FiltersProvider Props

  • instance: Filter instance created by useFilters
  • children: React nodes

useFilters Hook Options

interface UseFiltersOptions<T extends FiltersValue> {
    syncWithSearchParams?: boolean;
    parsers: UseQueryStatesKeysMap<T>;
}

useFiltersContext Hook

Returns an object with the following methods:

  • register(name, defaultValue): Register a filter with default value
  • unregister(name): Remove a filter
  • setValue(name, value): Update filter value
  • getValue(name): Get current filter value
  • reset(): Reset all filters to defaults
  • isResetDisabled: Check if reset is available

πŸ”„ Client-Side Filtering

Unlike nuqs, Qif also supports client-side filtering. By setting syncWithSearchParams to false, no parameters will be added to the URL. This is useful for temporary filters or when you don't want to persist the filter state in the URL.

Client-Side Example

const App = () => {
  const filtersInstance = useFilters({
    syncWithSearchParams: false, // Disable URL synchronization
    parsers: {
      search: parseAsString.withDefault(''),
      category: parseAsString.withDefault('all')
    }
  });

  return (
    <FiltersProvider instance={filtersInstance}>
      <ProductFilters />
      <ProductList />
    </FiltersProvider>
  );
};

const ProductFilters = () => {
  const { getValue, setValue } = useFiltersContext();

  return (
    <div className="filters">
      <input
        value={getValue('search') || ''}
        onChange={(e) => setValue('search', e.target.value)}
        placeholder="Search products..."
      />
      
      <select
        value={getValue('category') || 'all'}
        onChange={(e) => setValue('category', e.target.value)}
      >
        <option value="all">All Categories</option>
        <option value="electronics">Electronics</option>
        <option value="clothing">Clothing</option>
      </select>
    </div>
  );
};

const ProductList = () => {
  const { getValue } = useFiltersContext();
  const searchTerm = getValue('search') as string;
  const category = getValue('category') as string;

  // Filter your products based on searchTerm and category
  const filteredProducts = products.filter(product => {
    const matchesSearch = product.name.toLowerCase().includes(searchTerm.toLowerCase());
    const matchesCategory = category === 'all' || product.category === category;
    return matchesSearch && matchesCategory;
  });

  return (
    <div className="products">
      {filteredProducts.map(product => (
        <ProductCard key={product.id} product={product} />
      ))}
    </div>
  );
};

This example demonstrates:

  • Client-side filtering without URL parameter synchronization
  • Multiple filter types (search input and category select)
  • Real-time filtering of product list
  • Type-safe filter values with TypeScript

🀝 Contributing

Contributions, issues and feature requests are welcome! Feel free to check issues page.

πŸ“„ License

MIT Β© Hasan Ardestani

About

Simplify filtering state system

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 5