Rushan

Introducing GeoIcons: 422 tree-shakeable geographic icons

  • announcement
  • geoicons
  • react
  • svg-icons

GeoIcons is a library of geographic map icons for the web: 255 countries and 167 areas, 422 icons in total at the time of this post, built for React, Vue, Angular, and vanilla JS. More is on the way, including subdivisions and flags. Every icon is a named export, so your bundler keeps only the ones you import. Here are three of them, inheriting the current text color:

Key takeaways

  • 422 icons: 255 countries (ISO 3166) + 167 areas (regions, continents, landforms, subdivisions).
  • Tree-shakeable by design. One import ships one icon, not the catalog.
  • Themed with currentColor and an adjustable strokeWidth. Accessible out of the box.
  • React, Vue, Angular, and vanilla JS. Free under GPLv3, commercial license available.

What ships in the box

The set covers 255 country icons, named by their ISO 3166 alpha-2 code, and 167 area icons for regions, continents, landforms, and subdivisions. Enough to build a country picker or label a map legend without a second asset library.

Every icon is a single SVG component. No sprite sheet to host and no font to load.

One import ships one icon

GeoIcons has no central registry and no <Icon name="us" /> string API. Each icon is its own named export, which is what lets bundlers drop everything you never reference:

import { Us, Fr, Jp } from '@geoicons/react/countries';

export function Legend() {
  return (
    <ul>
      <li><Us aria-label="United States" /> United States</li>
      <li><Fr aria-label="France" /> France</li>
      <li><Jp aria-label="Japan" /> Japan</li>
    </ul>
  );
}

Import three icons and your build includes three icons. The other 419 never touch your bundle. For the mechanics behind that, read why an icon library doesn't have to bloat your bundle.

Themeable with currentColor

Icons paint with currentColor, so they follow the text color of whatever wraps them. Change weight with strokeWidth, or fill them solid. No CSS overrides, no per-icon color props to thread through your components:

// Default, colored, heavier stroke, filled
<Ng />
<Ng stroke="#2563eb" />
<Ng strokeWidth={1.5} />
<Ng fill="currentColor" />

The same four, live:

Because color is inherited, the same icon works in light mode, dark mode, and on a colored button without any extra styling.

Accessible by default

Icons are decorative unless you say otherwise. Add a label and the icon becomes meaningful to screen readers:

<Us aria-label="United States" />

Under the hood each icon namespaces its <title> id with React's useId(), so rendering the same icon twice on a page never produces duplicate ids.

Four frameworks, one icon set

The same icons ship for every major framework, imported the same way:

import { Us } from '@geoicons/react/countries';   // React
import { Us } from '@geoicons/vue/countries';     // Vue
import { Us } from '@geoicons/angular/countries'; // Angular
import { Us } from '@geoicons/vanilla/countries'; // Vanilla JS

@geoicons/core holds the shared pieces the framework packages build on.

Naming you can guess

Countries use their ISO 3166 alpha-2 code in PascalCase: Us, Fr, Jp, De, Br. Areas use a slug in PascalCase, such as EuropeanUnionEu. If you know the country code, you know the import name, so autocomplete does most of the work.

Licensing

GeoIcons is dual-licensed. It is free under GPLv3 for open-source and GPL-compatible projects, and a commercial license covers everything else. Icons render the same either way. An unlicensed commercial use logs an offline console warning and nothing else, so nothing breaks at runtime.

Get started

Install the package for your framework and import your first icon:

npm i @geoicons/react
import { Us } from '@geoicons/react/countries';

export default function App() {
  return <Us aria-label="United States" />;
}

Full API, styling, and accessibility docs live in the docs, or browse all 422 icons to find what you need.