Skip to content

About

An out-of-the-box city map of Turkey for React JS applications.

Topics

Resources

Contributing

Accessibility

Stars

77 stars

Watchers

2 watching

Forks

Repository files navigation

Turkey Map React

npm version npm downloads license bundle size CI CodeQL React

An interactive SVG map of Turkey for React applications. Ships all 81 provinces, supports single and multiple selection, and is keyboard accessible by default.

81 built-in provinces · Selection · Zoom & pan · Accessible navigation · Custom tooltips · Choropleth color scales · CSS-variable theming · React 16.8–19

Live demo · npm package · Changelog · Issues

Installation

npm install turkey-map-react

or with Yarn:

yarn add turkey-map-react

React and React DOM >=16.8 are peer dependencies. React is not bundled; your application's copy is used at runtime. TypeScript definitions are included.

Quick start

import TurkeyMap from 'turkey-map-react';

export default function App() {
  return <TurkeyMap />;
}

The root entry includes the built-in 81-province dataset. See Getting started for events, custom data, and all entry points.

Rich geography data

The built-in dataset carries optional region, centroid, neighbors, areaKm2, population, isoCode, nutsCode, and altNames fields, plus a consumer-owned meta record. The component, core entry, and hook are generic over a city subtype, so typed metadata flows through data and callbacks:

type SalesCity = Omit<CityType, "meta"> & { meta: { sales: number } };

<TurkeyMap<SalesCity> data={salesData} onHover={(city) => city.meta.sales} />

See custom data for field meanings, units, centroid coordinates, and data sources.

GeoJSON conversion

Convert GeoJSON polygons into the data shape without hand-writing SVG paths:

import TurkeyMap from 'turkey-map-react';
import { geoJsonToCities } from 'turkey-map-react/geojson';

const cities = geoJsonToCities(provinceGeoJson, {
  idKey: 'ADM1_CODE',
  nameKey: 'NAME_1',
  plateKey: 'PLATE',
});

<TurkeyMap data={{ cities }} />;

Polygon and MultiPolygon are supported, including holes. The helper projects longitude/latitude into the map's viewBox and accepts a custom project hook. It lives in a separate entry point and is not part of the default bundle. See GeoJSON conversion for options and limitations.

Choropleth

Color provinces by any metric with values, keyed by city id:

const values = { istanbul: 92, ankara: 45, izmir: 61 };

<TurkeyMap
  values={values}
  colorScale={['#f7fbff', '#08306b']}
  scaleType="linear"
  noDataColor="#eeeeee"
/>;

Linear, quantize, quantile, and threshold scales are built in, with getColor as an escape hatch. Provinces without a value use noDataColor, hover and selection keep the metric fill, and renderTooltip receives the current value. See Choropleth values and color scales for the data contract and examples.

Zoom and pan

Zoom and pan are opt-in. Wheel, pinch, double-click, and drag work out of the box, with accessible controls and a typed ref for programmatic focus:

const ref = useRef(null);

<TurkeyMap zoomable minZoom={1} maxZoom={8} zoomControls ref={ref} />;

ref.current?.focusCity('istanbul');
ref.current?.zoomTo(2);
ref.current?.resetView();

The viewport can be controlled with viewport and onViewportChange. See Zoom and pan for gestures, keyboard shortcuts, bounds, and the full ref API.

Headless hook

Use useTurkeyMap when you want the interaction engine without the component's markup. The hook renders nothing, requires data, and returns selection state, handlers, ARIA props, roving focus, announcements, and tooltip state:

import { useTurkeyMap } from 'turkey-map-react';
import { cities } from 'turkey-map-react/data';

function HeadlessMap() {
  const {
    getContainerProps,
    getCityProps,
    getTooltipProps,
    selectedCities,
    tooltipCity,
    announcement,
  } = useTurkeyMap({
    data: { cities },
    selectionMode: 'multiple',
    showTooltip: true,
  });

  return (
    <div>
      <svg {...getContainerProps()}>
        {cities.map((city) => (
          <path
            key={city.id}
            d={city.path}
            {...getCityProps(city)}
            style={{
              fill: selectedCities.some((item) => item.id === city.id) ? '#dc3522' : '#444',
              cursor: 'pointer',
            }}
          />
        ))}
      </svg>
      {tooltipCity && <div {...getTooltipProps()}>{tooltipCity.name}</div>}
      <div role="status" aria-live="polite" aria-atomic="true" style={{ position: 'absolute', width: 1, height: 1, overflow: 'hidden' }}>
        {announcement}
      </div>
    </div>
  );
}

The hook is exported from both turkey-map-react and turkey-map-react/core, supports custom city metadata generics, and works with SVG or non-SVG renderers. See Headless hook for recipes, generics, tooltips, the live region, a native-select fallback, memoization, and SSR.

Entry points

Entry point What it provides Use it when
turkey-map-react The default TurkeyMap component plus the built-in 81-province dataset. You want the one-line <TurkeyMap /> map.
turkey-map-react/core The same component without the built-in dataset. data is required. You supply your own data and want the dataset out of your bundle.
turkey-map-react/data The built-in dataset as a named cities export. You want to read, filter, or extend the built-in provinces yourself.
turkey-map-react/geojson geoJsonToCities, which converts GeoJSON polygons into CityType[] for data. You have GeoJSON and do not want to hand-write SVG paths.

The root and core entries also export the named useTurkeyMap hook. The hook never imports the built-in dataset and requires data, so turkey-map-react/core is the smallest choice for a headless map with custom data. The root entry is roughly 96 kB gzipped, core is roughly 11 kB gzipped before your data, data is roughly 81 kB gzipped, and the optional geojson helper is roughly 3 kB gzipped. See entry points and bundle size for examples and guidance.

Documentation

Detailed guides live in docs/.

Guide What it covers
Getting started Installation, requirements, quick start, events, entry points, and bundle size.
Headless hook useTurkeyMap state, prop getters, custom metadata, non-SVG renderers, tooltips, and SSR.
Selection and forms Single and multiple selection, controlled and uncontrolled values, limits, and form integration.
Custom data and cities Custom datasets, disabled provinces, and city wrapping.
GeoJSON conversion geoJsonToCities, key mapping, custom projections, viewBox fitting, holes, and limitations.
Choropleth values Numeric values, linear/quantize/quantile/threshold scales, no-data styling, and transitions.
Zoom and pan Opt-in gestures, controlled and uncontrolled viewports, keyboard shortcuts, controls, and the ref API.
Tooltips Custom content, positioning, portals, delays, keyboard focus, and reduced motion.
Accessibility Keyboard navigation, ARIA semantics, live regions, and the native select fallback.
Styling and DOM ids CSS custom properties, customStyle, getCityStyle, container props, and instance ids.
API reference Every prop and exported TypeScript type.
Versioning and releases Versioning scheme and the automated release process.

Contributing

Pull requests are welcome. See CONTRIBUTING.md for the full workflow, and use Conventional Commits for commit messages.

License

Released under the MIT License.

Credits

Derived from dnomak's svg-turkiye-haritasi project.

About

An out-of-the-box city map of Turkey for React JS applications.

Topics

Resources

Contributing

Accessibility

Stars

77 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages