shadcn.io is an independent project built on shadcn/ui
useMap keeps key-value pairs in a Map. set, setAll, remove, and reset each store a new Map, so React can see the change.
Pass a Map or a list of pairs to start from data you already have. When the value is only on or off, use useBoolean. In React those four functions keep the same identity between renders, so a button can take one as its click handler.
Installation
Anatomy

Usage
import { useMap } from "@/hooks/use-map";const [map, { set, setAll, remove, reset }] = useMap<string, string>([
["name", "Ada"],
]);Pass nothing to start empty. Pass pairs, or an existing Map, to start with data. reset clears the map. It does not restore those initial pairs.
FAQ
Are map updates immutable?
Every action copies the map before changing it. set and remove copy the previous entries, then add or delete one key. setAll and reset store a brand-new Map. React sees a new object and re-renders. The map from the last render is never mutated, so it is safe to pass to a child or to compare across renders.
How do I start with existing entries?
Pass a Map or an array of pairs. Both are copied into state with the Map constructor, so later edits do not change the value you passed in. Leave the argument off and the map starts empty. Key and value types are inferred from that initial data. Pass the two generics yourself when the map starts empty and the first set would otherwise be too wide.
How do I read a value from the map?
The first item is a Map with set, clear, and delete removed from the type, so the read methods stay. Use get, has, size, keys, values, entries, and forEach. Those calls do not update state. Changes go through the actions on the second item. Hiding the mutators means a child cannot edit the map in place and skip a re-render.
Does setAll merge with the current entries?
setAll takes a Map or an array of pairs and replaces every entry. It does not merge with what was already there. Call set once per key when only some entries should change. Each set copies the whole map. reset stores a new empty Map. It does not put the initial entries back. The initial value is only read on the first render.
How do I type the keys and values?
Pass the key type first and the value type second. TypeScript infers both from an initial Map or from an array of pairs, so you can omit them when that data is already typed. The hook returns a tuple: the read-only map, then the actions. MapOrEntries, UseMapActions, and UseMapReturn are exported next to the hook when a prop needs those names.
Is useMap safe on the server?
Yes. It is useState plus four callbacks, and it never reads window, document, or storage. The server and the client both start from the Map or the pairs you passed, so the first render matches. Do not build that initial value from localStorage or from the clock if the two sides would disagree. useState ignores a new initial value after the first render.
API Reference
Parameters
initialState?MapOrEntries<K, V>
The entries it starts with: a Map or an array of [key, value] pairs.
- Type
MapOrEntries<K, V>- Default
new Map()
Returns
[0] mapOmit<Map<K, V>, "set" | "clear" | "delete">
The map, read-only: get, has, size, iteration. Each change is a new map, so it works as an effect's dependency. /
- Type
Omit<Map<K, V>, "set" | "clear" | "delete">
[1] actionsUseMapActions<K, V>
The functions that change it. Stable across renders.
- Type
UseMapActions<K, V>
actions.remove(key: K) => void
Deletes a key.
- Type
(key: K) => void
actions.resetMap<K, V>["clear"]
Empties the map.
- Type
Map<K, V>["clear"]
actions.set(key: K, value: V) => void
Adds or replaces one entry.
- Type
(key: K, value: V) => void
actions.setAll(entries: MapOrEntries<K, V>) => void
Replaces every entry with these.
- Type
(entries: MapOrEntries<K, V>) => void











