Lightweight, zero-dependency tags input for any web project. Attach it to a text input by id: free tags, or pick-only tags from a local list or a search URL.
<link rel="stylesheet" href="tagsinput.css">
<script src="tagsinput.js"></script>
Ketik lalu Enter atau koma. Paste a,b,c jadi 3 tag. Backspace di field kosong hapus tag terakhir.
source: KATEGORI — pilih dari daftar, teks di luar daftar ditolak.
source: '/api/provinsi?q=', max: 3 — demo ini pakai fetch tiruan.
creatable: true — teks yang tidak ada di daftar muncul sebagai + Tambah "teks".
<input class="my-input"> — class pindah ke wrapper.
const tags = OnvTagsInput.init(id, options)
| # | Parameter | Type | Description |
|---|---|---|---|
| 1 | id |
string | HTMLInputElement |
Input id ('kota' or '#kota') or the element |
| 2 | options |
object |
Optional, see the options table below |
| Key | Type | Default | Description |
|---|---|---|---|
source | array | string | null | Empty = free tags. Array = pick from local list. String URL = search via fetch(url + query) |
creatable | boolean | false | With a source: text not in the list can become a new tag |
max | number | 0 | Maximum number of tags, 0 = unlimited |
separator | string | ',' | Separator used in the input value |
source | Behavior |
|---|---|
| empty | Free tags. Enter or comma adds a tag. Leftover text on blur becomes a tag. |
| array | Local list. Typing filters the list, pick with click or arrows + Enter. Text not in the list is rejected. The array is read live. |
| string URL | Server list. Same as array, the list comes from fetch(url + text) while typing (250 ms delay). |
+ creatable | List + new tags. No exact match shows + Tambah "text". New tag value = its text, chip gets .onvs-tagsinput-tag-new. |
Source items can be strings or { value, label } objects. The input stores the value, the chip shows the label. A URL must return that array as JSON, or { data: [...] }.
| Property / Method | Description |
|---|---|
getTags() | Array of values, e.g. ['1', '5'] (a new tag's value is its text) |
getNewTags() | Array of texts of new tags (creatable) |
setTags(list) | Replace all tags. Values or { value, label } |
add(tag) | Add one tag. Returns false when duplicate / full / empty |
remove(value) | Remove a tag by value |
element | Wrapper element (.onvs-tagsinput) |
OnvTagsInput.init('kota')
OnvTagsInput.init('kategori', { source: @json($kategori) })
// [{ value: 1, label: 'Berita' }, { value: 2, label: 'Olahraga' }, ...]
OnvTagsInput.init('provinsi', { source: '/api/provinsi?q=', max: 3 })
// Laravel route
Route::get('/api/provinsi', function (Request $request) {
return DB::table('provinsi')
->where('nama', 'like', '%' . $request->q . '%')
->limit(20)
->get(['id as value', 'nama as label']);
});
const provinsi = OnvTagsInput.init('provinsi', { source: '/api/provinsi?q=' })
provinsi.setTags(@json($terpilih)) // [{ value: 3, label: 'Banten' }]
$ids = array_filter(explode(',', $request->kota));
document.getElementById('kota').addEventListener('change', e => console.log(e.target.value))
The input's own classes (e.g. form-control) move to the wrapper. An input without classes gets .onvs-tagsinput-plain.
| Variable | Default |
|---|---|
--onvs-tagsinput-tag-bg | #5bc0de |
--onvs-tagsinput-tag-text | #fff |
--onvs-tagsinput-tag-radius | 4px |
--onvs-tagsinput-list-bg | #fff |
--onvs-tagsinput-list-border | #d0d5dd |
--onvs-tagsinput-list-hover | #e9ecf2 |
--onvs-tagsinput-muted | #98a2b3 |
--onvs-tagsinput-tag-new-bg | #f79009 |
--onvs-tagsinput-create-text | #1a4099 |
The original input is hidden, so a theme's .form-control:focus does not apply. Add a focus style yourself:
.onvs-tagsinput.form-control:focus-within { border-color: #86b7fe; box-shadow: 0 0 0 .25rem rgba(13, 110, 253, .25); }
"a,b,c"), so a normal form submit sends it.change on the original input.init again returns the existing instance.add() / setTags() from code are not checked against the list.required input needs manual validation, since it is hidden.disabled / readonly inputs are not supported yet.