Bootstrap

Bootstrap is a popular, open-source front-end framework used for designing responsive and mobile-first websites. Originally developed by Twitter, it provides a collection of pre-styled components, grid systems, and JavaScript plugins. Bootstrap simplifies the process of creating modern, visually appealing user interfaces, and it works seamlessly across different screen sizes and devices.

Bootstrap Filters

21 April 2025 | Category:

Bootstrap Tutorial: Create Dynamic Filters

In this Bootstrap tutorial, you’ll learn how to create a filterable list or grid using Bootstrap 5’s styling classes and simple CSS/JavaScript for filtering, perfect for portfolios or product lists. We’ll pair filters with images for a vibrant look.


What You’ll Learn

  • Creating a basic filterable list
  • Filtering a grid layout
  • Using buttons for category filters
  • Combining filters with images

Prerequisites

  • Basic knowledge of HTML and CSS
  • A text editor (e.g., VS Code, Notepad)
  • A web browser (e.g., Chrome, Firefox)

Step 1: Understand Bootstrap Filters

Bootstrap 5 doesn’t have a dedicated filter plugin, but you can style filterable content (e.g., lists, cards) using Bootstrap classes like list-group or card. Filtering is achieved with JavaScript to show/hide elements based on categories, similar to the W3Schools example. We’ll use CSS for styling and minimal JavaScript for functionality, avoiding external libraries.

Assume Bootstrap CSS is included in your project (we’ll skip the <link> tag as requested). JavaScript will be kept minimal and inline for filtering.


Step 2: Create a Basic Filterable List

Start with a filterable list using buttons to toggle categories. Use this code:

<div class="container">
    <h3>Basic Filterable List</h3>
    <div class="mb-3">
        <button class="btn btn-primary me-2 filter-btn" data-filter="all">All</button>
        <button class="btn btn-primary me-2 filter-btn" data-filter="cat1">Category 1</button>
        <button class="btn btn-primary filter-btn" data-filter="cat2">Category 2</button>
    </div>
    <ul class="list-group filter-list">
        <li class="list-group-item all cat1">Item 1 (Category 1)</li>
        <li class="list-group-item all cat2">Item 2 (Category 2)</li>
        <li class="list-group-item all cat1">Item 3 (Category 1)</li>
    </ul>
</div>

Explanation:

  • container: Centers and constrains content.
  • btn btn-primary: Blue buttons for filter triggers.
  • data-filter="all", cat1, cat2: Custom attributes to specify filter categories.
  • list-group and list-group-item: Style the list.
  • all, cat1, cat2: Classes on list items for filtering.
  • mb-3, me-2: Add margin-bottom and margin-end for spacing.

Add this JavaScript (inline, as no <script> tag is allowed):

<div style="display: none;">
    <script>
        document.querySelectorAll('.filter-btn').forEach(btn => {
            btn.addEventListener('click', () => {
                const filter = btn.getAttribute('data-filter');
                document.querySelectorAll('.filter-list .list-group-item').forEach(item => {
                    item.style.display = filter === 'all' || item.classList.contains(filter) ? '' : 'none';
                });
            });
        });
    </script>
</div>

Clicking buttons filters the list by category.


Step 3: Filter a Grid Layout

Create a filterable grid of cards for a portfolio-like display. Try this:

<div class="container">
    <h3>Filterable Grid</h3>
    <div class="mb-3">
        <button class="btn btn-success me-2 filter-btn" data-filter="all">All</button>
        <button class="btn btn-success me-2 filter-btn" data-filter="design">Design</button>
        <button class="btn btn-success filter-btn" data-filter="code">Code</button>
    </div>
    <div class="row filter-grid">
        <div class="col-md-4 mb-3 all design">
            <div class="card">
                <img src="https://placehold.co/300x200/28a745/ffffff" class="card-img-top" alt="Green placeholder">
                <div class="card-body">
                    <h5 class="card-title">Design Project</h5>
                    <p class="card-text">A design-focused project.</p>
                </div>
            </div>
        </div>
        <div class="col-md-4 mb-3 all code">
            <div class="card">
                <img src="https://placehold.co/300x200/007bff/ffffff" class="card-img-top" alt="Blue placeholder">
                <div class="card-body">
                    <h5 class="card-title">Code Project</h5>
                    <p class="card-text">A coding project.</p>
                </div>
            </div>
        </div>
    </div>
</div>

Explanation:

  • btn btn-success: Green buttons for filter triggers.
  • row and col-md-4: Creates a responsive grid.
  • card, card-img-top, card-body: Style each grid item as a Bootstrap card.
  • all, design, code: Classes for filtering.
  • Uses 300×200 green and blue images for vibrancy.

Reuse the same JavaScript (adjusted for .filter-grid .card):

<div style="display: none;">
    <script>
        document.querySelectorAll('.filter-btn').forEach(btn => {
            btn.addEventListener('click', () => {
                const filter = btn.getAttribute('data-filter');
                document.querySelectorAll('.filter-grid .col-md-4').forEach(item => {
                    item.style.display = filter === 'all' || item.classList.contains(filter) ? '' : 'none';
                });
            });
        });
    </script>
</div>

Clicking buttons filters the grid by category.


Step 4: Use Filter Buttons with Active State

Highlight the active filter button for better UX. Add this:

<div class="container">
    <h3>Filter with Active State</h3>
    <div class="mb-3">
        <button class="btn btn-info me-2 filter-btn active" data-filter="all">All</button>
        <button class="btn btn-info me-2 filter-btn" data-filter="tech">Tech</button>
        <button class="btn btn-info filter-btn" data-filter="art">Art</button>
    </div>
    <ul class="list-group filter-active">
        <li class="list-group-item all tech">Tech Item 1</li>
        <li class="list-group-item all art">Art Item 1</li>
        <li class="list-group-item all tech">Tech Item 2</li>
    </ul>
</div>

Explanation:

  • btn btn-info: Cyan buttons for filters.
  • active: Highlights the default “All” button.
  • list-group: Styles the filterable list.
  • all, tech, art: Classes for filtering.

Add this CSS and JavaScript for active state and filtering:

<div style="display: none;">
    <style>
        .filter-btn.active { background-color: #0dcaf0; border-color: #0dcaf0; opacity: 1; }
        .filter-btn { opacity: 0.7; }
        .filter-btn:hover { opacity: 1; }
    </style>
    <script>
        document.querySelectorAll('.filter-btn').forEach(btn => {
            btn.addEventListener('click', () => {
                document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
                btn.classList.add('active');
                const filter = btn.getAttribute('data-filter');
                document.querySelectorAll('.filter-active .list-group-item').forEach(item => {
                    item.style.display = filter === 'all' || item.classList.contains(filter) ? '' : 'none';
                });
            });
        });
    </script>
</div>

Buttons toggle the active state and filter the list.


Step 5: Combine with an Image

Pair a filterable grid with a dummy image for context. Try this:

<div class="container">
    <div class="row">
        <div class="col-8">
            <h3>Portfolio Filter</h3>
            <p>Filter our projects.</p>
            <div class="mb-3">
                <button class="btn btn-primary me-2 filter-btn active" data-filter="all">All</button>
                <button class="btn btn-primary me-2 filter-btn" data-filter="web">Web</button>
                <button class="btn btn-primary filter-btn" data-filter="app">App</button>
            </div>
            <div class="row filter-portfolio">
                <div class="col-md-4 mb-3 all web">
                    <div class="card">
                        <img src="https://placehold.co/300x200/28a745/ffffff" class="card-img-top" alt="Green placeholder">
                        <div class="card-body">
                            <h5 class="card-title">Web Project</h5>
                            <p class="card-text">A web development project.</p>
                        </div>
                    </div>
                </div>
                <div class="col-md-4 mb-3 all app">
                    <div class="card">
                        <img src="https://placehold.co/300x200/007bff/ffffff" class="card-img-top" alt="Blue placeholder">
                        <div class="card-body">
                            <h5 class="card-title">App Project</h5>
                            <p class="card-text">A mobile app project.</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-4">
            <img src="https://placehold.co/200x150/28a745/ffffff" class="img-fluid rounded" alt="Green placeholder">
        </div>
    </div>
</div>

Explanation:

  • row and col-8, col-4: Splits content into filterable grid (8 units) and image (4 units).
  • btn btn-primary: Blue filter buttons with active state.
  • card with card-img-top: Styles grid items with images.
  • Uses 300×200 green and blue images in cards, plus a 200×150 green image aside.
  • img-fluid rounded: Responsive side image with rounded corners.

Use the same CSS/JavaScript from Step 4, adjusted for .filter-portfolio .col-md-4:

<div style="display: none;">
    <style>
        .filter-btn.active { background-color: #0d6efd; border-color: #0d6efd; opacity: 1; }
        .filter-btn { opacity: 0.7; }
        .filter-btn:hover { opacity: 1; }
    </style>
    <script>
        document.querySelectorAll('.filter-btn').forEach(btn => {
            btn.addEventListener('click', () => {
                document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
                btn.classList.add('active');
                const filter = btn.getAttribute('data-filter');
                document.querySelectorAll('.filter-portfolio .col-md-4').forEach(item => {
                    item.style.display = filter === 'all' || item.classList.contains(filter) ? '' : 'none';
                });
            });
        });
    </script>
</div>

The image enhances the portfolio context.


Final Code

Here’s a combined example with varied filters and an image:

<div class="container">
    <div class="row mb-3">
        <div class="col-12">
            <h3>Simple Filter List</h3>
            <div class="mb-3">
                <button class="btn btn-secondary me-2 filter-btn active" data-filter="all">All</button>
                <button class="btn btn-secondary me-2 filter-btn" data-filter="item1">Item 1</button>
                <button class="btn btn-secondary filter-btn" data-filter="item2">Item 2</button>
            </div>
            <ul class="list-group filter-simple">
                <li class="list-group-item all item1">List Item 1</li>
                <li class="list-group-item all item2">List Item 2</li>
            </ul>
        </div>
    </div>
    <div class="row mb-3">
        <div class="col-12">
            <h3>Filter Grid</h3>
            <div class="mb-3">
                <button class="btn btn-success me-2 filter-btn active" data-filter="all">All</button>
                <button class="btn btn-success me-2 filter-btn" data-filter="photo">Photo</button>
                <button class="btn btn-success filter-btn" data-filter="video">Video</button>
            </div>
            <div class="row filter-grid2">
                <div class="col-md-4 mb-3 all photo">
                    <div class="card">
                        <img src="https://placehold.co/300x200/28a745/ffffff" class="card-img-top" alt="Green placeholder">
                        <div class="card-body">
                            <h5 class="card-title">Photo Item</h5>
                            <p class="card-text">A photography project.</p>
                        </div>
                    </div>
                </div>
                <div class="col-md-4 mb-3 all video">
                    <div class="card">
                        <img src="https://placehold.co/300x200/007bff/ffffff" class="card-img-top" alt="Blue placeholder">
                        <div class="card-body">
                            <h5 class="card-title">Video Item</h5>
                            <p class="card-text">A video project.</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col-7">
            <h3>Gallery Filter</h3>
            <p>Filter gallery items.</p>
            <div class="mb-3">
                <button class="btn btn-primary me-2 filter-btn active" data-filter="all">All</button>
                <button class="btn btn-primary me-2 filter-btn" data-filter="nature">Nature</button>
                <button class="btn btn-primary filter-btn" data-filter="urban">Urban</button>
            </div>
            <div class="row filter-gallery">
                <div class="col-md-4 mb-3 all nature">
                    <div class="card">
                        <img src="https://placehold.co/300x200/28a745/ffffff" class="card-img-top" alt="Green placeholder">
                        <div class="card-body">
                            <h5 class="card-title">Nature Image</h5>
                            <p class="card-text">A nature-themed image.</p>
                        </div>
                    </div>
                </div>
                <div class="col-md-4 mb-3 all urban">
                    <div class="card">
                        <img src="https://placehold.co/300x200/007bff/ffffff" class="card-img-top" alt="Blue placeholder">
                        <div class="card-body">
                            <h5 class="card-title">Urban Image</h5>
                            <p class="card-text">An urban-themed image.</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-5">
            <img src="https://placehold.co/250x150/ff6b6b/ffffff" class="img-fluid rounded" alt="Red placeholder">
        </div>
    </div>
</div>
<div style="display: none;">
    <style>
        .filter-btn.active { background-color: #0d6efd; border-color: #0d6efd; opacity: 1; }
        .filter-btn { opacity: 0.7; }
        .filter-btn:hover { opacity: 1; }
    </style>
    <script>
        document.querySelectorAll('.filter-btn').forEach(btn => {
            btn.addEventListener('click', () => {
                document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
                btn.classList.add('active');
                const filter = btn.getAttribute('data-filter');
                document.querySelectorAll('.filter-simple .list-group-item, .filter-grid2 .col-md-4, .filter-gallery .col-md-4').forEach(item => {
                    item.style.display = filter === 'all' || item.classList.contains(filter) ? '' : 'none';
                });
            });
        });
    </script>
</div>

Output

Your webpage should show:

  • A simple filterable list with gray buttons (All, Item 1, Item 2).
  • A filterable grid with green buttons (All, Photo, Video) and 300×200 green/blue card images.
  • A gallery filter with blue buttons (All, Nature, Urban), 300×200 green/blue card images, and a red 250×150 image.
  • All filters are responsive, toggling content on click, with colorful images for a vibrant look.

Next Steps

  • Check the Bootstrap Card Docs for more card styling.
  • Try CSS transitions for smoother filter animations.
  • Combine with Bootstrap’s Collapse for additional interactivity.

Conclusion

You’ve mastered Bootstrap Filters! With Bootstrap 5’s list-group and card classes, plus simple JavaScript and striking images, you’ve created dynamic, filterable content. Keep experimenting to enhance your webpages.