Interactive Demo
Experience Zenty in Action
A powerful Zustand-based library that simplifies CRUD operations with elegant state management. Try the interactive demo below to see how easy it is to manage your data.
Products Example Store
Manage a collection of products with full CRUD operations. Notice how Zenty handles validation and errors automatically!
Not LoadedReady
error
error
error
error
Live Zustand Store State
{ "entities": [], "loaded": false, "loading": false, "error": null }
Current Products (0)
No products yet. Add some products to see them here!
Get Started with Zenty
Install and start using Zenty in your project
npm
1npm install zenty zustand
yarn
1yarn add zenty zustand
pnpm
1pnpm add zenty zustand
See how Zenty simplifies your code:
❌ Before: Traditional Zustand (Entities)
type Product { id: string name: string price?: number category?: string } type ProductState { entities: Product[] loaded: boolean loading: boolean error: string | null selectedId: number | null } type ProductActions { add: (item: Product) => void addMany: (items: Product[]) => void update: (id: number, patch: Partial<Product>) => void updateMany: (updates: Array<{ id: number; patch: Partial<Product> }>) => void delete: (id: number) => void deleteMany: (ids: number[]) => void find: (id: number) => Product | undefined has: (id: number) => boolean clear: () => void replaceAll: (items: Product[]) => void setLoading: (loading: boolean) => void setError: (error: string | null) => void setSelected: (id: number | null) => void getSelected: () => Product | undefined } // store.ts import { create } from 'zustand' import { subscribeWithSelector } from 'zustand/middleware' const useProductStore = create<ProductState & ProductActions>()( subscribeWithSelector((set, get) => ({ // State entities: [], loaded: false, loading: false, error: null, selectedId: null, // Actions add: (item) => set((state) => ({ entities: [...state.entities, item], loaded: true, error: null })), addMany: (items) => set((state) => ({ entities: [...state.entities, ...items], loaded: true, error: null })), update: (id, patch) => set((state) => { const index = state.entities.findIndex(item => item.id === id) if (index === -1) { return { error: `Product with id ${id} not found` } } const newEntities = [...state.entities] newEntities[index] = { ...newEntities[index], ...patch } return { entities: newEntities, error: null } }), updateMany: (updates) => set((state) => { const newEntities = [...state.entities] let hasError = false updates.forEach(({ id, patch }) => { const index = newEntities.findIndex(item => item.id === id) if (index !== -1) { newEntities[index] = { ...newEntities[index], ...patch } } else { hasError = true } }) return { entities: newEntities, error: hasError ? 'Some updates failed' : null } }), delete: (id) => set((state) => { const exists = state.entities.some(item => item.id === id) if (!exists) { return { error: `Product with id ${id} not found` } } return { entities: state.entities.filter(item => item.id !== id), selectedId: state.selectedId === id ? null : state.selectedId, error: null } }), deleteMany: (ids) => set((state) => ({ entities: state.entities.filter(item => !ids.includes(item.id)), selectedId: ids.includes(state.selectedId!) ? null : state.selectedId, error: null })), find: (id) => get().entities.find(item => item.id === id), has: (id) => get().entities.some(item => item.id === id), clear: () => set({ entities: [], loaded: false, error: null, selectedId: null }), replaceAll: (items) => set({ entities: items, loaded: true, error: null, selectedId: null }), setLoading: (loading) => set({ loading }), setError: (error) => set({ error }), setSelected: (id) => set({ selectedId: id }), getSelected: () => { const state = get() return state.selectedId ? state.find(state.selectedId) : undefined } })) ) // Custom hooks for selectors export const useProducts = () => useProductStore(state => state.entities) export const useProductsLoaded = () => useProductStore(state => state.loaded) export const useProductsLoading = () => useProductStore(state => state.loading) export const useProductsError = () => useProductStore(state => state.error) export const useSelectedProduct = () => useProductStore(state => state.getSelected()) // 150+ lines of boilerplate code just for basic CRUD!
✅ After: Zenty Entities Mode
import { createEntitiesStore } from 'zenty' type Product { id: string name: string price?: number category?: string } const useProductStore = createEntitiesStore<Product>();
🚀 Result: 90% Less Code, 100% More Features
- • No boilerplate - Just one line to create a full-featured store
- • Built-in validation - Error handling and loading states included
- • TypeScript first - Full type safety out of the box
- • Powerful operations - CRUD, search, bulk operations, and more
- • Developer friendly - Intuitive API that just works