Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Blade Alpine Instantsearch Laravel Package

internachi/blade-alpine-instantsearch

Blade-Alpine InstantSearch integrates Algolia InstantSearch into Laravel using Blade components and Alpine.js directives. Build reactive search UIs—hits, facets, pagination, and more—while staying in a familiar Blade workflow.

View on GitHub
Deep Wiki
Context7

Getting Started

This package wraps Algolia's InstantSearch.js in Blade components on top of Alpine.js — so you get a search UI without writing a Vue/React SPA, but you keep the full InstantSearch widget vocabulary.

  1. Install and publish.

    composer require internachi/blade-alpine-instantsearch
    php artisan vendor:publish --tag="blade-alpine-instantsearch-config"
    

    Check the README for whether assets are published separately (--tag=...-assets) or pulled from a CDN — the two paths have different cache-busting implications (see Gotchas).

  2. Credentials. Put your search-only API key and app ID in config/services.php under an algolia key, sourced from .env. Never let the admin key reach the browser bundle.

  3. First render. Drop the search root component into a Blade view, set the index name, and add two children — a search box and a hits list. This is the smallest thing that proves the plumbing (Algolia app ID, index name, asset loading, Alpine boot) all works end-to-end before you start styling.

  4. Where to look first. The package's Blade component namespace (usually resources/views/components after publish, or vendor/.../resources/views if not publishable) is the real documentation — each component maps to a single InstantSearch widget, and the prop names mirror InstantSearch's widgetParams. Read one component's Blade file and you can infer the rest.

First real use case: a /search page with searchbox → stats → hits → pagination. Get that working, then layer on refinement lists and URL state.

Implementation Patterns

One root, many children. Treat the search root component as a provider: it owns the Algolia client and index, and every child widget inside it joins that context. Don't nest two roots inside the same DOM subtree, and don't try to share widgets across roots.

URL state is now first-class (0.8.0). Prior to 0.8.0 the query-string mapping was effectively fixed; 0.8.0 lets you customize URL params. The practical pattern:

  • Define your param names once (e.g. q, page, brand, category) and make them match what you actually want to read server-side, in analytics, or in marketing links.
  • Prefer named params for primary facets (brand) and InstantSearch's default dotted form (refinementList.category) only for facets you'll never hand-write. Human-readable URLs are shareable URLs.
  • Because the mapping is configurable, this is the right place to stabilize your public URL contract. Decide the names now, document them, and treat them as an API — sitemap entries and ad landing pages will depend on them.
  • Pair URL params with the routing/state-sync option so back/forward and page refreshes restore filters. Deep-linking to a filtered result set is the single highest-value thing this feature unlocks.

Compose, don't fork. Build custom widgets as an Alpine component that reads the InstantSearch helper (instantsearch instance exposed on the Alpine scope) and calls helper.setQueryParameter(...) / helper.search() with a debounce. This survives package upgrades far better than copying a vendor Blade file into your app.

Server-side fallback. The hits are client-rendered; crawlers mostly aren't. If search result pages need to rank, render a small server-side list of top results (a direct Algolia PHP client call in the controller, cached) behind the interactive widget, and let Alpine replace it on load.

Multiple search instances. Search-within-search (e.g. a docs sidebar and a main results pane) works if each root has a distinct index name and distinct URL param namespaces — otherwise the two instances will fight over q in the query string.

Scoped indexes for multi-tenant. Rather than one index with a tenant facet filter, prefer passing a tenant-suffixed index name into the root component from the controller. It keeps the URL params clean and avoids leaking cross-tenant facet counts.

Gotchas and Tips

0.8.0 is a pre-1.0 minor bump. Under semver, 0.x minor releases are allowed to break. bencarr's URL-params change is additive in intent, but if you had existing deep links with default param names, verify they still resolve after upgrading. Check any tests or marketing links that hardcode ?q= or ?page=.

Alpine double-boot. If you're using Livewire wire:navigate, Turbo, or Inertia, the search root will be re-mounted without re-initializing InstantSearch, and you'll get stale results or silent no-ops. Either exclude the search page from SPA navigation, or hook into the navigation lifecycle to tear down and rebuild the search instance.

Asset loading order. Alpine must be defined before the package's directives register. If you load the package's JS from a <script> in @stack('scripts') but Alpine comes from Vite with defer, you get intermittent "widget did nothing" failures that only reproduce on cold cache. Confirm the loading strategy and pin it.

Config caching. php artisan config:cache will freeze your Algolia credentials at deploy time. If you rotate the search key, you must re-cache. Also: never resolve env() inside a package component — you'll get null in production with a cached config.

Search-only key, and restrict it. A search-only key is public by definition, but it should still be scoped with restrictIndices and, where applicable, secured API keys with a tenant filter. If you're doing per-user filtering (e.g. "only my org's documents"), you need a secured API key generated server-side per session — a client-side facet filter is not a security boundary.

URL params and sensitive filters. Anything in the query string is in browser history, referrer headers, and server logs. Don't map private filters into URL params. This is the most common way this feature gets misused.

Hit template escaping. Hits render via {!! !!} in many of these wrappers so you can put HTML in the template. Since the content comes from your Algolia index (which may contain user-generated text), either use {{{ }}}-style escaping or sanitize the indexed attributes at index time. Highlighted attributes in particular can carry markup.

Extension point: custom widgets. Most of the friction in this package shows up when you need a widget it doesn't ship (geo search, range slider with custom formatting, a "no results" fallback with query suggestions). The durable pattern is an Alpine component using the exposed helper — reach for that before patching vendor files, and keep a note of which helper methods you depend on, since those are the most likely thing to shift in a 0.x upgrade.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo