# How to Implement Search Functionality That Spans Across Exercise Names in Vanilla JavaScript

> Implement client-side search spanning exercise names with vanilla JavaScript. Concatenate exercise details and filter using includes() with debounced input for fast results.

- Repository: [Hasan Emir Yıldırım/exercises-dataset](https://github.com/hasaneyldrm/exercises-dataset)
- Tags: how-to-guide
- Published: 2026-07-17

---

**You can implement client-side search across exercise names by creating a pre-computed index string for each exercise that concatenates the name, category, target muscle, equipment, and muscle group, then filtering the array using `String.prototype.includes()` with a debounced input handler.**

The `hasaneyldrm/exercises-dataset` repository demonstrates a pure front-end approach to implementing search functionality that spans across exercise names. By leveraging an in-memory index and vanilla JavaScript, the implementation delivers instant results across 1,324 exercises without requiring server requests. The following guide breaks down the exact patterns used in [`index.html`](https://github.com/hasaneyldrm/exercises-dataset/blob/main/index.html) to build, filter, and reset the search interface.

## Building the Searchable Index

The search capability relies on a pre-computed text index stored in each exercise object. During initialization, the code concatenates multiple searchable fields into a single lowercase string assigned to a private `_idx` property.

In [`index.html`](https://github.com/hasaneyldrm/exercises-dataset/blob/main/index.html), lines 24–28, the index construction works as follows:

```javascript
state.exercises.forEach(ex => {
  ex._idx = `${ex.name} ${ex.category} ${ex.target} ${ex.equipment} ${ex.muscle_group}`.toLowerCase();
});

```

This approach allows the search to span beyond just exercise names, including categories, target muscles, equipment types, and muscle groups in a single query. The concatenation happens once during app startup, ensuring O(1) lookup performance during filtering.

## Debouncing Search Input

To prevent excessive filtering while typing, the search input uses a 250ms debounce. The search box (`<input id="search">`) captures user input and updates the `state.search` property only after the user pauses typing.

The implementation in [`index.html`](https://github.com/hasaneyldrm/exercises-dataset/blob/main/index.html), lines 90–96, wires the event listener with a debounce utility:

```javascript
searchEl.addEventListener('input', debounce(() => {
  state.search = searchEl.value;
  searchClearEl.classList.toggle('visible', state.search.length > 0);
  applyFilters();
}, 250));

```

The `debounce` function delays execution until 250 milliseconds after the last keystroke, reducing the number of filter operations and keeping the UI responsive.

## Filtering Exercises by Name

The core filtering logic resides in the `applyFilters()` function, which checks the searchable index against the user's query. This function lower-cases the input and uses `String.prototype.includes()` to determine matches while respecting additional active filters for category, equipment, and target.

As implemented in [`index.html`](https://github.com/hasaneyldrm/exercises-dataset/blob/main/index.html), lines 92–99:

```javascript
function applyFilters() {
  const q = state.search.toLowerCase().trim();
  const { category, equipment, target } = state.filters;

  state.filtered = state.exercises.filter(ex => {
    if (q && !ex._idx.includes(q)) return false;          // Name search across index
    if (category.size && !category.has(ex.category)) return false;
    if (equipment.size && !equipment.has(ex.equipment)) return false;
    if (target.size && !target.has(ex.target)) return false;
    return true;
  });
  // Rendering logic follows...
}

```

The `ex._idx.includes(q)` check enables substring matching across all indexed fields, meaning a query for "chest" returns exercises with "chest" in the name, category, or target muscle fields.

## Clearing Search Results

The interface includes a clear button (marked with "×") that resets the search state and restores the full dataset. When clicked, the button clears the input value, hides itself, and re-applies filters to show all exercises.

The implementation in [`index.html`](https://github.com/hasaneyldrm/exercises-dataset/blob/main/index.html), lines 97–102:

```javascript
searchClearEl.addEventListener('click', () => {
  searchEl.value = '';
  state.search = '';
  searchClearEl.classList.remove('visible');
  applyFilters();
});

```

This pattern ensures the UI remains synchronized with the internal state, immediately displaying all 1,324 exercises when the search is cleared.

## Summary

- **Pre-computed indices** improve performance by concatenating searchable fields (`name`, `category`, `target`, `equipment`, `muscle_group`) into `ex._idx` during initialization.
- **Debounced input** (250ms) prevents excessive filter operations while maintaining responsive feedback.
- **Client-side filtering** uses `String.prototype.includes()` on the index string, eliminating server latency entirely.
- **State synchronization** between the search input, clear button visibility, and filtered results ensures consistent UI behavior.

## Frequently Asked Questions

### How does the search handle case sensitivity?

The search is case-insensitive. Both the index (`ex._idx`) and the user query (`q`) are converted to lowercase using `toLowerCase()` before comparison, ensuring "Push", "PUSH", and "push" all match the same exercises.

### Can I extend the search to include additional exercise fields?

Yes. Modify the index construction in [`index.html`](https://github.com/hasaneyldrm/exercises-dataset/blob/main/index.html) (lines 24–28) to include additional properties in the template literal. For example, add `${ex.instructions}` or `${ex.difficulty}` to the concatenation string to expand the searchable content.

### Why is the search implemented client-side instead of using a server API?

The `hasaneyldrm/exercises-dataset` repository stores all 1,324 exercises in a global `EXERCISES` array within [`index.html`](https://github.com/hasaneyldrm/exercises-dataset/blob/main/index.html). By building an in-memory index and filtering via JavaScript, the implementation eliminates network latency, works offline, and requires no backend infrastructure while remaining instantaneously responsive.

### What is the performance impact of searching 1,324 exercises?

The impact is negligible in modern browsers. The O(n) filter operation runs against a pre-computed string index, and the 250ms debounce ensures the function executes at most once per typing pause. Even with the full dataset, filtering completes in milliseconds because it performs simple string inclusion checks on cached property values.