vernsg / nusa-filament
Ready-to-use Filament 4 components for creasi/laravel-nusa Indonesian administrative regions.
Requires
- php: ^8.2
- creasi/laravel-nusa: ^0.1.18
- filament/forms: ^4.0
- filament/infolists: ^4.0
- filament/tables: ^4.0
- illuminate/contracts: ^11.0|^12.0
- illuminate/database: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.18
- orchestra/testbench: ^9.0|^10.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
README
Nusa Filament provides Filament 4 components for working with Indonesian administrative regions in Laravel applications. It is powered by creasi/laravel-nusa, which supplies the underlying region data and lookup support.
Use this package to add cascading Provinsi -> Kabupaten/Kota -> Kecamatan -> Desa/Kelurahan selects to Filament forms. It also includes postal code autofill, table columns, filters, infolist entries, and validation rules for applications that store Indonesian address data.
Preview
Child regions are displayed as soon as a parent region is selected. Remote search remains available for filtering larger option lists.
Features
- Form components: cascading province, regency, district, and village selects, available individually or as a complete address group with sensible default field names.
- Dependent options: child regions are loaded immediately after their parent region is selected, with remote search for larger option lists.
- Postal code autofill: the postal code field can be filled automatically from the selected village.
- Display components: table columns and infolist entries resolve stored region codes to readable names.
- Table filtering: a dependent location filter supports province, regency, district, and village fields.
- Validation: Laravel validation rules check individual region codes and address hierarchy consistency.
- Configuration: field names, labels, search limit, native select behavior, and dropdown position can be customized.
Requirements
| Package Version | PHP | Laravel | Filament |
|---|---|---|---|
^0.1 |
^8.2 |
^11.0 | ^12.0 |
^4.0 |
The PHP sqlite3 extension is also required. Laravel Nusa stores its administrative region dataset in SQLite, so the extension must be enabled in the application that installs this package.
Installation
Install the package with Composer:
composer require vernsg/nusa-filament
Laravel package auto-discovery registers the service provider automatically.
Publish the configuration file if you need to customize field names, labels, the search limit, native select behavior, or dropdown position:
php artisan vendor:publish --tag=nusa-filament-config
The published configuration file will be available at:
config/nusa-filament.php
Usage
Quick Start
Add NusaAddress to a Filament resource form to render a complete Indonesian address block.
<?php namespace App\Filament\Resources\Customers\Schemas; use Filament\Forms\Components\TextInput; use Filament\Schemas\Schema; use Vernsg\NusaFilament\Forms\Components\NusaAddress; class CustomerForm { public static function configure(Schema $schema): Schema { return $schema ->components([ TextInput::make('name') ->required(), NusaAddress::make(), ]); } }
The component renders these fields:
Alamat
Provinsi
Kabupaten/Kota
Kecamatan
Desa/Kelurahan
Kode Pos
By default, values are stored in these model attributes:
address_line
province_code
regency_code
district_code
village_code
postal_code
Ensure that your model table contains matching nullable columns before saving the form.
Database Columns
The package stores administrative region codes, not region names. Use the provided table columns and infolist entries to display readable region names.
Example migration:
use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; Schema::table('customers', function (Blueprint $table): void { $table->text('address_line')->nullable(); $table->string('province_code')->nullable(); $table->string('regency_code')->nullable(); $table->string('district_code')->nullable(); $table->string('village_code')->nullable(); $table->string('postal_code', 10)->nullable(); });
Dependent Select Behavior
The address selects are reactive and dependent by default:
- Selecting a province loads its regencies.
- Selecting a regency loads its districts.
- Selecting a district loads its villages.
- Selecting a village can automatically fill the postal code field.
Options are available immediately after a parent region is selected. For example, after selecting a province, the regency dropdown displays the matching regencies without requiring the user to type first.
Remote search remains enabled for filtering larger option lists.
Naming Convention
The package uses English names in its PHP API while displaying Indonesian labels by default:
| Indonesian Label | Component / API Term |
|---|---|
| Provinsi | Province |
| Kabupaten/Kota | Regency |
| Kecamatan | District |
| Desa/Kelurahan | Village |
Form Components
Full Address Group
use Vernsg\NusaFilament\Forms\Components\NusaAddress; NusaAddress::make();
Customize field names when your model uses different columns:
NusaAddress::make() ->addressLine('shipping_address') ->province('shipping_province_code') ->regency('shipping_regency_code') ->district('shipping_district_code') ->village('shipping_village_code') ->postalCode('shipping_postal_code');
Hide optional fields:
NusaAddress::make() ->withoutAddressLine() ->withoutPostalCode();
Individual Selects
Use the individual components to place fields manually:
use Vernsg\NusaFilament\Forms\Components\DistrictSelect; use Vernsg\NusaFilament\Forms\Components\ProvinceSelect; use Vernsg\NusaFilament\Forms\Components\RegencySelect; use Vernsg\NusaFilament\Forms\Components\VillageSelect; ProvinceSelect::make('province_code'); RegencySelect::make('regency_code') ->provinceField('province_code'); DistrictSelect::make('district_code') ->regencyField('regency_code'); VillageSelect::make('village_code') ->districtField('district_code') ->fillPostalCode('postal_code');
Table Components
Display readable region names from stored codes:
use Vernsg\NusaFilament\Tables\Columns\DistrictColumn; use Vernsg\NusaFilament\Tables\Columns\ProvinceColumn; use Vernsg\NusaFilament\Tables\Columns\RegencyColumn; use Vernsg\NusaFilament\Tables\Columns\VillageColumn; return $table ->columns([ ProvinceColumn::make('province_code'), RegencyColumn::make('regency_code'), DistrictColumn::make('district_code'), VillageColumn::make('village_code'), ]);
Add a dependent location filter:
use Vernsg\NusaFilament\Tables\Filters\NusaLocationFilter; return $table ->filters([ NusaLocationFilter::make('location'), ]);
Customize filter field names:
NusaLocationFilter::make('shipping_location') ->provinceField('shipping_province_code') ->regencyField('shipping_regency_code') ->districtField('shipping_district_code') ->villageField('shipping_village_code');
Infolist Components
Display a complete address entry:
use Vernsg\NusaFilament\Infolists\Components\NusaAddressEntry; NusaAddressEntry::make();
Or display individual entries:
use Vernsg\NusaFilament\Infolists\Components\DistrictEntry; use Vernsg\NusaFilament\Infolists\Components\ProvinceEntry; use Vernsg\NusaFilament\Infolists\Components\RegencyEntry; use Vernsg\NusaFilament\Infolists\Components\VillageEntry; ProvinceEntry::make('province_code'); RegencyEntry::make('regency_code'); DistrictEntry::make('district_code'); VillageEntry::make('village_code');
Validation
Use the provided rules to validate individual region codes and confirm that the selected address hierarchy is consistent:
use Vernsg\NusaFilament\Rules\NusaRules; [ 'province_code' => ['required', NusaRules::province()], 'regency_code' => ['required', NusaRules::regency()], 'district_code' => ['required', NusaRules::district()], 'village_code' => [ 'required', NusaRules::village(), NusaRules::addressHierarchy(), ], ]
addressHierarchy() validates that:
- the regency belongs to the selected province;
- the district belongs to the selected regency;
- the village belongs to the selected district.
Configuration
Publish the configuration file:
php artisan vendor:publish --tag=nusa-filament-config
Available options:
return [ 'fields' => [ 'province' => 'province_code', 'regency' => 'regency_code', 'district' => 'district_code', 'village' => 'village_code', 'postal_code' => 'postal_code', 'address_line' => 'address_line', ], 'labels' => [ 'province' => 'Provinsi', 'regency' => 'Kabupaten/Kota', 'district' => 'Kecamatan', 'village' => 'Desa/Kelurahan', 'postal_code' => 'Kode Pos', 'address_line' => 'Alamat', ], 'search_limit' => 50, 'native' => false, 'select_position' => 'bottom', ];
select_position defaults to bottom so region dropdowns do not flip upward and cover previous fields on long forms. Set it to null to use Filament's default auto-placement behavior.
Relationship to Laravel Nusa
This package does not replace Laravel Nusa. It uses creasi/laravel-nusa as its data and region lookup layer, then adds Filament-specific components around it.
It can be used as:
- a ready-to-install Filament integration for Laravel applications;
- a concrete example of how Laravel Nusa can power admin panel address forms;
- a small reference implementation for dependent Indonesian region selects.
Development
Install dependencies:
composer install
Run the test suite:
composer test
Run static analysis:
composer analyse
Check code style:
composer format:test
Fix code style:
composer format
Changelog
Please see CHANGELOG.md for notable changes.
Contributing
Please see CONTRIBUTING.md for contribution guidelines.
Security
Please see SECURITY.md for the security policy.
Credits
creasi/laravel-nusafor the Indonesian administrative region data and underlying region support.- Filament for the application panel and component framework.
License
The MIT License. Please see LICENSE.md for details.
