So I was thinking about writing a simple Custom HTML Prompt that would give me a multi-select listbox that I could filter by typing in a input box. Yes, I know we have this natively with KM, but I wanted to add some other features.
Here's my journey:
Step 1
I asked ChatGPT this question:
html js checkbox listbox with filtering
Here's the result, which is functional although there's some piping that would be needed to work in a Custom HTML Prompt:
Click to view the source
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Checkbox Listbox with Filtering</title>
<style>
body {
font-family: Arial, sans-serif;
}
.filter-box {
margin-bottom: 10px;
}
.checkbox-list {
list-style: none;
padding: 0;
max-height: 200px;
overflow-y: auto;
border: 1px solid #ddd;
padding: 10px;
}
.checkbox-list li {
margin-bottom: 5px;
}
</style>
</head>
<body>
<h1>Checkbox Listbox with Filtering</h1>
<div class="filter-box">
<input type="text" id="filterInput" placeholder="Filter items...">
</div>
<ul id="checkboxList" class="checkbox-list">
<li><label><input type="checkbox" value="Item 1"> Item 1</label></li>
<li><label><input type="checkbox" value="Item 2"> Item 2</label></li>
<li><label><input type="checkbox" value="Item 3"> Item 3</label></li>
<li><label><input type="checkbox" value="Item 4"> Item 4</label></li>
<li><label><input type="checkbox" value="Item 5"> Item 5</label></li>
<li><label><input type="checkbox" value="Item 6"> Item 6</label></li>
<li><label><input type="checkbox" value="Item 7"> Item 7</label></li>
</ul>
<script>
document.getElementById('filterInput').addEventListener('input', function() {
let filterValue = this.value.toLowerCase();
let items = document.querySelectorAll('#checkboxList li');
items.forEach(function(item) {
let label = item.textContent.toLowerCase();
if (label.indexOf(filterValue) !== -1) {
item.style.display = '';
} else {
item.style.display = 'none';
}
});
});
</script>
</body>
</html>
Step 2
I modified my query to this:
html js checkbox listbox with filtering check all button uncheck all button
Here's the result:
Click to view the source
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Checkbox List with Filter</title>
<style>
.list-container {
width: 300px;
margin: 20px auto;
border: 1px solid #ccc;
padding: 10px;
border-radius: 5px;
}
.filter-input {
width: 100%;
padding: 8px;
margin-bottom: 10px;
box-sizing: border-box;
}
.list-item {
display: flex;
align-items: center;
margin: 5px 0;
}
</style>
</head>
<body>
<div class="list-container">
<input type="text" id="filter" class="filter-input" placeholder="Filter items..." onkeyup="filterItems()">
<div>
<button onclick="checkAll()">Check All</button>
<button onclick="uncheckAll()">Uncheck All</button>
</div>
<div id="checkboxList">
<div class="list-item">
<input type="checkbox" id="item1">
<label for="item1">Apple</label>
</div>
<div class="list-item">
<input type="checkbox" id="item2">
<label for="item2">Banana</label>
</div>
<div class="list-item">
<input type="checkbox" id="item3">
<label for="item3">Cherry</label>
</div>
<div class="list-item">
<input type="checkbox" id="item4">
<label for="item4">Date</label>
</div>
<div class="list-item">
<input type="checkbox" id="item5">
<label for="item5">Elderberry</label>
</div>
</div>
</div>
<script>
function filterItems() {
const filter = document.getElementById('filter').value.toLowerCase();
const items = document.querySelectorAll('#checkboxList .list-item');
items.forEach(item => {
const label = item.querySelector('label').textContent.toLowerCase();
if (label.includes(filter)) {
item.style.display = '';
} else {
item.style.display = 'none';
}
});
}
function checkAll() {
const checkboxes = document.querySelectorAll('#checkboxList input[type="checkbox"]');
checkboxes.forEach(checkbox => checkbox.checked = true);
}
function uncheckAll() {
const checkboxes = document.querySelectorAll('#checkboxList input[type="checkbox"]');
checkboxes.forEach(checkbox => checkbox.checked = false);
}
</script>
</body>
</html>
Step 3
I got to thinking that I'd still need to write the code to populate the listbox, so I asked this:
html js dynamically built checkbox listbox with filtering check all button uncheck all button
And I got this:
Click to view the source
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dynamic Checkbox List with Filtering</title>
<style>
.filter-input {
margin-bottom: 10px;
padding: 5px;
width: 100%;
}
.checkbox-list {
list-style-type: none;
padding-left: 0;
}
.checkbox-list li {
margin-bottom: 5px;
}
</style>
</head>
<body>
<h1>Dynamic Checkbox List with Filtering</h1>
<input type="text" id="filterInput" class="filter-input" placeholder="Filter options...">
<button id="checkAllBtn">Check All</button>
<button id="uncheckAllBtn">Uncheck All</button>
<ul id="checkboxList" class="checkbox-list"></ul>
<script>
document.addEventListener('DOMContentLoaded', function () {
const items = [
"Apple", "Banana", "Cherry", "Date", "Elderberry",
"Fig", "Grape", "Honeydew", "Kiwi", "Lemon", "Mango"
];
const checkboxList = document.getElementById('checkboxList');
const filterInput = document.getElementById('filterInput');
const checkAllBtn = document.getElementById('checkAllBtn');
const uncheckAllBtn = document.getElementById('uncheckAllBtn');
// Function to render the checkbox list
function renderCheckboxList(filter = '') {
checkboxList.innerHTML = ''; // Clear the list first
const filteredItems = items.filter(item => item.toLowerCase().includes(filter.toLowerCase()));
filteredItems.forEach(item => {
const li = document.createElement('li');
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = item;
checkbox.value = item;
const label = document.createElement('label');
label.htmlFor = item;
label.textContent = item;
li.appendChild(checkbox);
li.appendChild(label);
checkboxList.appendChild(li);
});
}
// Event listener for filtering
filterInput.addEventListener('input', function () {
renderCheckboxList(filterInput.value);
});
// Event listener for Check All button
checkAllBtn.addEventListener('click', function () {
const checkboxes = checkboxList.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach(checkbox => {
checkbox.checked = true;
});
});
// Event listener for Uncheck All button
uncheckAllBtn.addEventListener('click', function () {
const checkboxes = checkboxList.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach(checkbox => {
checkbox.checked = false;
});
});
// Initial rendering of the checkbox list
renderCheckboxList();
});
</script>
</body>
</html>
Step 4 (last step for now - time for bed)
I thought to myself, I wonder if ChatGPT knows about KM's Custom HTML Prompt? So I asked this:
keyboard maestro custom html prompt dynamically built checkbox listbox with filtering check all button uncheck all button
And to my surprise, it did indeed understand the comcept and gave me something that works in a Custom HTML Prompt, although I didn't check it out too thoroughly.
You can ask the question of ChatGPT if you want to see the result.
But Wait, There's More!
And here's the kicker: After presenting this answer to me, ChatGPT asked me this:
Would you like guidance on integrating this with a specific use case in Keyboard Maestro?
Well slap my butt and call me Sally. Sure wish I had this back when I was working for a living.