React map icons for countries, states, and regions
GeoIcons gives your React app the shapes of places: 255 countries and territories, 167 regions such as the European Union and the Sahara, and 377 states and provinces. Each one is its own React component that renders an inline SVG, so you size it, recolor it, and give it an accessible name with props.
If you are looking for a map pin or a location marker, any general icon set has one. GeoIcons draws the outline of the place itself, like the shape of Japan or Texas.
Install and render your first icon
Add the package to your project:
npm i @geoicons/reactThen import a place and render it like any other component:
import { Japan } from '@geoicons/react/countries';
export function ShippingDestination() {
return (
<p className="flex items-center gap-2">
<Japan size={20} aria-hidden="true" />
Ships to Japan
</p>
);
}The icons don't use any client-only React APIs, so they also render in Next.js Server Components
without "use client". The Server Components guide
explains what that means for the JavaScript your users download.
Import names you can guess
GeoIcons splits the set into three entry points, one per category:
| Entry point | What it holds | Example imports |
|---|---|---|
@geoicons/react/countries | Countries and territories | UnitedStates, Japan, or the ISO codes Us, Jp |
@geoicons/react/areas | Continents, unions, and physical regions | EuropeanUnion, Gcc, SaharaDesert, NewEngland |
@geoicons/react/subdivisions | States, provinces, parishes, and departments | UsTexas, UsCalifornia, CaOntario |
Countries accept either the full name or the ISO 3166-1 alpha-2 code.
UnitedStates and Us point to the same component. Subdivision names join the country code and
the region name, so Texas is UsTexas and Ontario is CaOntario. Once you type the entry point,
your editor autocompletes the rest.
Style with props and Tailwind
Every icon draws its outline with currentColor, so it takes the text color of its parent. Use
size for dimensions, strokeWidth for outline weight (the default is 1), and
fill="currentColor" when you want a solid shape:
<Brazil size={48} className="text-emerald-600" />
<Brazil size={48} strokeWidth={1.75} />
<Brazil size={48} fill="currentColor" strokeWidth={0} />Any other SVG prop, such as className, style, onClick, or a data-* attribute, goes straight
to the <svg> element. The styling docs cover every prop.
What React teams build with them
- Country pickers and address forms. A shape next to each option helps people find their country faster than a long text list. Follow the country list view tutorial to build one.
- Shipping and availability labels. Show where a product ships, or which regions a plan covers, in a line of small outlines.
- Dashboards grouped by region. Let users filter sales by US state or color states by a metric. The interactive SVG maps tutorial walks through both.
- Themed interfaces. Because the color comes from CSS, the same icon works in light and dark mode without a second file.
Pick an icon at runtime without losing tree-shaking
When the country code comes from your API, you might reach for a generic <Icon name={code} />. A
lookup like that has to import every icon, so all 799 of them land in your
bundle. Instead, import the icons a screen can show and keep them in a small object:
import { UnitedStates, Canada, Mexico } from '@geoicons/react/countries';
// Every icon shares the same props, so any one of them works as the type.
type MapIcon = typeof UnitedStates;
const marketIcons: Record<string, MapIcon> = {
us: UnitedStates,
ca: Canada,
mx: Mexico,
};
export function MarketBadge({ code, name }: { code: string; name: string }) {
const Icon = marketIcons[code];
return (
<span className="inline-flex items-center gap-1.5">
{Icon && <Icon size={16} aria-hidden="true" />}
{name}
</span>
);
}Your bundler sees three static imports and ships those three icons. Each one adds about 0.28 KB gzipped. The tree-shaking guide shows how to confirm that in your own build.
Accessibility
Icons are hidden from screen readers by default, which is right when a text label sits next to
them. If the shape is the only thing telling the user which place they are looking at, pass
aria-label="Japan". The component then adds role="img" and a <title> with a unique id, so
two icons on the same page never collide. Read more in the
accessibility docs.
Also available for Vue, Angular, and plain JavaScript
The same icons ship as @geoicons/vue, @geoicons/angular,
and @geoicons/vanilla, with matching names. If your team runs more than one
framework, designs and code stay consistent across all of them.
License
GeoIcons is free under GPLv3 when your project is open source under a GPL-compatible license. If you ship it in a closed-source product, you need a commercial license. The icons look and work the same under either license.
FAQ
- Do GeoIcons work in Next.js Server Components?
- Yes. The icons do not use client-only React APIs, so you can render them in a Server Component without adding "use client". They work in Client Components too.
- How much does each React map icon add to my bundle?
- About 0.28 KB gzipped per icon. Every place is its own named export, so your bundler only ships the icons you import by name.
- Can I use these icons to build a clickable map of US states?
- You can make each state clickable by wrapping its component in a button. Each shape is scaled to fill its own 24x24 frame, though, so the states do not fit together into one geographically positioned map. For zoom, pan, or true positions, use a map library such as react-simple-maps or d3-geo.