Hack for Creating Universal Search

Hi everyone!
I thought I’d post this just in case any of you were looking for the same functionality. I recently used Softr and Airtable to create a documentation app for our team. I needed a non-third-party search function located throughout the app (i.e., the header/nav bar) that could search the data source, including data from synced tables, and return results with links to the corresponding page. With a lot of Softr gymnastics I was able to come up with a workable solution, detailed below.

First, I created a Search page that would be opened in a modal window. The page is simply a List Item block, limited to 3 items, with list items configured to look like I want the search results to look, and a search bar enabled and configured to search relevant fields.

The following JS ensures focus on the search input when the modal window is opened, and hides the list items until the user begins typing in the search input. I made several, mostly unsuccessful, attempts at hiding the list items before settling on this one. It isn’t perfect and maybe one of you JS masters out there can suggest something better/more elegant, but this works for the moment. It’s added to the Page’s Custom Footer Code.

<script>
document.addEventListener("DOMContentLoaded", function() {    
    var interval = setInterval(function () {
        if (typeof $ !== 'undefined') {
            
            $("input:text")[0].focus();
            $(".filters-middle-section").addClass("d-none");
            
            $("input:text").keyup(function() {
                var value = $(this).val();
                if (!value.trim()) {
                    $(".filters-middle-section").addClass("d-none");
                } else {
                     $(".filters-middle-section").removeClass("d-none");
                }
            }).keyup();
            
            clearInterval(interval);
        }
    }, 100);
});
</script>

Quick note about the Airtable base structure:
The base is basically made up of a table of Articles, and a table of Sections. Each article belongs to, and is linked to, a section. Each section (e.g., Introduction, Guides, etc.) represents its own page in the Softr app.

For each article, I created a formula field that dynamically creates a link for each article/list item. It simply concatenates the anchor HTML, the Section name (which corresponds with a page in Softr), and the article’s title/heading as the link text. I used this field as the Heading in the Search page list items, so that when the user clicks on the results Heading, they will be taken to the articles’ corresponding Section page. If needed, the href could be altered to direct the user to the specific ID of the article, but our articles are pretty short and for the time being it’s enough just to get them to the page.

In order for the link(s) to direct the user to the site’s page from the modal window without opening a new browser window (i.e., for clicking the link to seem like native functionality and not the hack that it is) it is necessary to include the <base> tag in the Page Custom Header Code (NOT the App-wide Custom Header Code).

<base target="_parent" />

Here are the CSS styles I used to clean up the list items/results that show up in the modal window.

<style>
body, #list1 > section {
    background-color: transparent !important;
}
.filter-container {
    background-color: transparent !important;
    overflow-y: hidden;
}
.filters-top-section {
    background-color: #fff !important;
    border-radius: 0.5rem;
}
.filters-top-section .container {
    padding: 0 !important;
}
.filters-top-section .container > div {
    margin: 0.5rem 0 !important;
}
.filters-top-section fieldset, .filters-top-section fieldset:hover {
    border: none !important;
}
.filters-middle-section {
    background-color: #fff !important;
    margin-top: 0.5rem;
    padding: 1rem;
    overflow-y: auto;
}
.filters-middle-section button {
    font-weight: normal;
    box-shadow: none;
}
.horizontal-list-item {
    padding: 0.75rem !important;
    transition: background-color 0.875s !important;
}
.horizontal-list-item:hover {
    background-color: #ececf1;
}
</style>

Next, I used JS to create a link in the App-wide header, styled with CSS to look like a search input form (I was inspired by various other documentation/wiki solutions), that opens the Search page in a modal window. This could also be done using a button in the header, but I wanted to add the META key functionality. I did try it with a button, though, and it worked fine.

<script>
document.addEventListener("DOMContentLoaded", function() {
    var interval = setInterval(function() {
        if (typeof $ !== "undefined") {

            $(() => {
                let html = `<div id="search-wrapper">
                            <div id="search">
                            <a id="openSearch" href="javascript:void(0);" onclick="openSwModal(\'/search\', \'md\');">
                            <svg style="width: 16px; height: 16px; margin-right: 0.5rem;" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round">
                            <circle cx="11" cy="11" r="8"></circle>
                            <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
                            </svg>
                            Search
                            </a>
                            <kbd>
                            <span class="ua-mac">⌘K</span>
                            <span class="ua-win">WIN + K</span>
                            </kbd>
                            </div>
                            </div>`;
                            
                $(".navbar-brand + div").after(html);
                
                if (navigator.userAgent.indexOf("Mac") != -1) {
                    $(".ua-mac").show() && $(".ua-win").hide();
                } else {
                    $(".ua-mac").hide() && $(".ua-win").show();
                }
            });
            /**
             * If user presses META key + K, call click handler 
             * attached to search bar link and open modal.
             * Else if user presses ESCAPE key, call click handler 
             * attached to modal button and close modal.
             */
            $(document).keydown(function(event) {
                if (event.metaKey && event.which === 75) {
                    //alert('Cmd + K pressed!');
                    $("a#openSearch").trigger("click");
                    event.preventDefault();
                } else if (event.metaKey && event.which === 27) {
                    $("button.sw-modal-close").click();
                }
            });

            clearInterval(interval);
        }
    }, 100);
});
</script>

And finally, some CSS to style the search bar and the modal windows.

<style>
/*Search bar*/
#search-wrapper {
    flex-grow: 1;
    order: 3;
    margin-left: 1rem;
    font-family: "Fira Sans";
    font-weight: 300;
    font-size: 0.875rem;
}
.navbar-brand {
    order: 1;
}
div:nth-child(2) {
    order: 2;
    flex-grow: 4;
}
div:nth-child(4) {
    order: 4;
}
#search {
    background-color: inherit;
    border: 1px solid #ececf1;
    border-radius: 0.375rem;
    cursor: pointer;
    display: flex;
    flex-direction: row;
    align-items: stretch;
    justify-content: space-around;
    transition: box-shadow 0.875s;
}
#search:hover {
    box-shadow: 0 0 30px rgba(0,0,0,.2);
}
#search > * {
    margin: .5rem;
}
#search a {
    width: clamp(8rem, 12rem, 15vw);
    color: #0a0a0a;
    flex: 10 1 8rem; 
    order: 1;
    display: flex;
    align-items: center;
    text-decoration: none;
}
#search kbd {
    order: 2;
    display: flex;
    justify-content: center;
    align-items: center;
}
/*Modal styles*/
.sw-modal .sw-modal-overlay {
    background: rgba(68,68,68,.2235294117647059);
    backdrop-filter: saturate(130%) blur(6px);
    -webkit-backdrop-filter: saturate(130%) blur(6px);
}
.sw-modal .sw-modal-container {
    background-color: transparent;
    overflow-y: hidden;
}
.sw-modal .sw-modal-container > div {
    border-radius: 0.5rem;
}
.sw-modal .sw-modal-container * {
    border-radius: inherit;
}
.sw-modal .sw-modal-close {
    color: #0a0a0a;
}
</style> 

That’s it! I know t’s not pretty, but I hope it helps anyone looking for a universal search bar. I might have forgotten something, so please feel free to reach out or comment with any questions. And maybe some of you can suggest some improvements.