v1.6.x-dev NDS IQ v6

Saudi Cities Dataset - National Design System

Bundled JSON dataset of 132 Saudi Arabian cities across all 13 administrative regions, with bilingual (English + Arabic) names. Drop into autocomplete inputs, region selectors, or any address flow.

Overview

A static JSON file that any page can fetch. Designed as a drop-in source for the autocomplete component, but plain enough to feed into selects, maps, filters, or any other lookup UI.

It ships at docs-assets/data/saudi-cities.json, outside the runtime assets a project copies wholesale — so copy the file into your own assets folder and serve it from there. The examples below assume /assets/data/saudi-cities.json.

132 cities

Major cities and regional towns. Capital cities of each region, governorate seats, and well-known towns are included; very small villages are not.

13 regions

Covers all administrative regions of the Kingdom: Riyadh, Makkah, Madinah, Eastern Province, Asir, Tabuk, Hail, Northern Borders, Jazan, Najran, Al Bahah, Al Jouf, Al Qassim.

Bilingual

Each entry carries both English (Name) and Arabic (NameAr) names. Switch which language drives display by changing data-name on the consuming component.

No build step

Static JSON served alongside the rest of the assets. Works with any consumer that can fetch() a URL — no Jekyll dependency, no rebuild required.

Schema

Each entry in the array follows this shape

FieldTypeDescription
IdintegerStable numeric identifier. Use as a row key when caching or submitting.
RegionstringAdministrative region the city belongs to, in English.
RegionArstringAdministrative region the city belongs to, in Arabic.
NamestringCity name in English (Latin transliteration).
NameArstringCity name in Arabic.

With Autocomplete

Point an autocomplete input at the JSON, set data-fetch="once", and you get an instant city picker that loads the dataset on first keystroke and filters it client-side

Live demo — type a city name
<div class="nds-form-container" data-url="/assets/data/saudi-cities.json" data-name="Name" data-fetch="once" data-min-chars="1"> <div class="nds-form-header"> <label for="city"><span class="nds-label">City</span></label> </div> <div class="nds-form-control"> <i class="nds-icon nds-hgi-search-01" aria-hidden="true"></i> <input type="text" id="city" autocomplete="on" placeholder="Type to search Saudi cities"> <div class="nds-form-action"> <button class="nds-btn nds-subtle nds-clear" type="button" aria-label="Clear input" hidden> <i class="nds-icon nds-hgi-cancel-01" aria-hidden="true"></i> </button> </div> </div> <div class="nds-form-footer" data-feedback-target hidden></div> </div>

Bilingual Search & Custom Display

Pass filter and renderItem callbacks to NDS.Autocomplete.create() to match across both languages and show a richer label. The selected value still comes from data-name.

Live demo — type "Riy" or "الر"
const el = document.getElementById('city-container'); const escape = (s) => String(s).replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c])); NDS.Autocomplete.create(el, { filter: (items, q) => { const lc = q.toLowerCase(); return items.filter(c => c.Name.toLowerCase().includes(lc) || c.NameAr.includes(q) ); }, renderItem: (item) => `<strong>${escape(item.Name)}</strong> <span style="color: var(--text-secondary)"> · ${escape(item.NameAr)} · ${escape(item.Region)} </span>` });

Direct Access

For non-autocomplete use — populate a select, build a region tree, draw a map, etc.

Fetch + group by region
const cities = await fetch('/assets/data/saudi-cities.json').then(r => r.json()); // Group by region const byRegion = cities.reduce((map, city) => { (map[city.Region] = map[city.Region] || []).push(city); return map; }, {}); // e.g. byRegion["Eastern Province"] → [Dammam, Al Khobar, Dhahran, ...]

Notes

  • The dataset is editorial — it favors administrative seats and well-known towns over an exhaustive census of every village. Expect to extend it for use cases that need full coverage.
  • Latin transliterations follow common English-language conventions, not a strict standard. Searches may need to handle alternate spellings (e.g., Mecca vs Makkah) — wire that into your filter callback rather than duplicating entries.
  • Total response size is well under the autocomplete component's 1 MB cap. Safe to load with data-fetch="once" on any device.
Last Modified Date: 01/08/2026 - 11:45 PM
Was this page useful?
60% of users said Yes from 2843 Feedbacks