@jessebyarugaba/ug-address
v1.0.0
Published
Cascading Uganda address selector — District → County → Sub-county → Parish → Village. Single file, no dependencies, works offline.
Maintainers
Readme
ug-address.js
A lightweight, dependency-free JavaScript library for cascading Uganda address selection.
Supports:
District → County/Division → Sub-county → Parish → Village
The library is completely UI-agnostic:
- no CSS
- no HTML
- no framework dependencies
- no DOM coupling
You can use it with:
- plain HTML
- React
- Vue
- Svelte
- Alpine
- mobile webviews
- Electron
- or any custom UI system
Features
- Single-file library (
ug-address.js) - No external datasets required
- No fetch/CORS issues
- No async initialization
- Works offline
- Works with
file:// - Fully event-driven
- Automatically resets downstream selections
- Framework agnostic
- Includes all Uganda administrative levels
Included Data
| Level | Approximate Records | |---|---| | Districts | 137 | | Counties / Divisions | ~305 | | Sub-counties | ~2,100 | | Parishes | ~10,300 | | Villages / Cells | ~71,200 |
Installation
Plain HTML
<script src="ug-address.js"></script>Quick Start
<!DOCTYPE html>
<html>
<head>
<title>UgAddress Demo</title>
</head>
<body>
<select id="district"></select>
<script src="ug-address.js"></script>
<script>
const addr = new UgAddress();
console.log(
addr.getDistricts()
);
</script>
</body>
</html>Full Cascading Example
<!DOCTYPE html>
<html>
<head>
<title>UgAddress Demo</title>
</head>
<body>
<select id="district"></select>
<select id="county"></select>
<select id="subcounty"></select>
<select id="parish"></select>
<select id="village"></select>
<script src="ug-address.js"></script>
<script>
const addr = new UgAddress();
const districtEl = document.getElementById('district');
const countyEl = document.getElementById('county');
const subcountyEl = document.getElementById('subcounty');
const parishEl = document.getElementById('parish');
const villageEl = document.getElementById('village');
function populate(select, items, placeholder) {
select.innerHTML = '';
const first = document.createElement('option');
first.value = '';
first.textContent = placeholder;
select.appendChild(first);
items.forEach(function(item) {
const option = document.createElement('option');
option.value = item.id;
option.textContent = item.name;
select.appendChild(option);
});
select.disabled = items.length === 0;
}
populate(
districtEl,
addr.getDistricts(),
'Select District'
);
districtEl.addEventListener('change', function () {
addr.selectDistrict(this.value);
});
countyEl.addEventListener('change', function () {
addr.selectCounty(this.value);
});
subcountyEl.addEventListener('change', function () {
addr.selectSubcounty(this.value);
});
parishEl.addEventListener('change', function () {
addr.selectParish(this.value);
});
villageEl.addEventListener('change', function () {
addr.selectVillage(this.value);
});
addr.onDistrictChange(function (e) {
populate(
countyEl,
e.counties,
'Select County'
);
});
addr.onCountyChange(function (e) {
populate(
subcountyEl,
e.subcounties,
'Select Subcounty'
);
});
addr.onSubcountyChange(function (e) {
populate(
parishEl,
e.parishes,
'Select Parish'
);
});
addr.onParishChange(function (e) {
populate(
villageEl,
e.villages,
'Select Village'
);
});
</script>
</body>
</html>API Reference
Constructor
const addr = new UgAddress();Data Getters
All methods return arrays sorted alphabetically.
getDistricts()
Returns all districts.
addr.getDistricts();getCounties(districtId?)
Returns counties/divisions for a district.
addr.getCounties('32');If no argument is provided, the currently selected district is used.
getSubcounties(countyId?)
Returns sub-counties for a county.
addr.getSubcounties('69');getParishes(subcountyId?)
Returns parishes for a sub-county.
addr.getParishes('1546');getVillages(parishId?)
Returns villages/cells for a parish.
addr.getVillages('9127');Selection Methods
Selecting a level automatically clears downstream selections.
selectDistrict(id)
addr.selectDistrict('32');Fires:
districtChangeselectCounty(id)
addr.selectCounty('69');Fires:
countyChangeselectSubcounty(id)
addr.selectSubcounty('1546');Fires:
subcountyChangeselectParish(id)
addr.selectParish('9127');Fires:
parishChangeselectVillage(id)
addr.selectVillage('57217');Fires:
villageChangeEvent Listeners
The library is event-driven.
Each callback receives pre-filtered child records ready for your next dropdown.
onDistrictChange()
addr.onDistrictChange(function (e) {
console.log(e.districtId);
console.log(e.counties);
});onCountyChange()
addr.onCountyChange(function (e) {
console.log(e.subcounties);
});onSubcountyChange()
addr.onSubcountyChange(function (e) {
console.log(e.parishes);
});onParishChange()
addr.onParishChange(function (e) {
console.log(e.villages);
});onVillageChange()
addr.onVillageChange(function (e) {
console.log(e.villageId);
});Reading the Selection
getFormattedAddress()
Returns a formatted human-readable address.
addr.getFormattedAddress();Example:
Nakasero Village A, Nakasero Parish, Central Ward, Kampala Central Division, KampalaReset
reset()
Clears all selected levels.
addr.reset();Example Data Structure
District
└── County / Division
└── Sub-county
└── Parish
└── Village / CellRelationships:
county.district === district.id
subcounty.county === county.id
parish.subcounty === subcounty.id
village.parish === parish.idBrowser Support
Supports all modern browsers:
- Chrome
- Firefox
- Edge
- Safari
- Opera
Performance Notes
The library ships with the full Uganda administrative dataset embedded directly into the single JS file.
Advantages:
- no external requests
- instant access
- offline support
- zero configuration
- works without a server
License
MIT License
Use freely in:
- commercial projects
- SaaS products
- open-source applications
- government systems
- internal tools
- educational projects
