caspg

caspg

Real-time Search with Phoenix LiveView and Tailwind

Hi everyone,

I recently implemented a real-time search feature in a Phoenix application using LiveView and Tailwind, and I wanted to share the code with the community.

The code includes an example of how to use LiveView to dynamically update the search results based on user input, as well as some optional TypeScript code to allow users to navigate the search results using the keyboard (up and down arrow keys).

You can check out a demo of the feature in action at travelermap.net (search bar is in top right corner), and I have to say, the results are super cool :sweat_smile:! The real-time updates are seamless and make the search experience much more intuitive.

:point_right: Here’s a link to the code on GitHub:

Let me know if you have any questions or feedback!

Most Liked

milangupta

milangupta

Really neat ! Thank you …
I have been trying to figure out a fuzzier search than ilike … try adding this … helps with spelling mistakes etc.

    |> where(fragment("SIMILARITY(p.name, ?) > .30", ^search_query))
    |> order_by(fragment("LEVENSHTEIN(p.name, ?)", ^search_query))
caspg

caspg

Wikipedia modal is pure JS. I created this website as a static, non-live phoenix app. Now, I’m in the process of migrating to live views. But still, I think modals should be opened with JS commands to avoid round trips to the server.

caspg

caspg

@ghenry I’m using 1.7 :slight_smile: I was just referencing the previous comment asking if I’m using send_update.

@maz I’m just using MapLibre - MapLibre GL JS. The map is rendered as separate LiveView with sticky: true option so it’s not re-rendered between navigations.

addstar

addstar

Nice one! I recently made a similar feature. A couple of things I noticed.

You can have multiple items highlighted if your mouse is in the results section and if you use the arrow keys. Prob not really an issue but the way I approached this was to set the attribute aria-selected on the item using a combination of keydown and mouseenter/mouseleave events.

If you have a long list of results and you use the arrow keys it doesn’t auto scroll. Look into scrollIntoView.

You should probably also use <.focus_wrap /> around your modal for accessibility.

How did did you approach changing the keyboard shortcut icon e.g. the command icon to a windows icon based on the users OS?

caspg

caspg

You just need to render SearchbarLive somewhere in your app.html.heex. In my case, I’m using live_render in my navbar:

<%= live_render(
  @conn,
  TravelerWeb.SearchbarLive,
  id: "searchbar",
  container: {:div, class: "flex items-center lg:w-full"}
) %>

You don’t need to add anything to your router. You only need to install and setup LiveView but it’s probably already done by phx generator.

Where to put files? It doesn’t really matter where you put files but there is specific phoenix convention (and Phoenix 1.7 introduced a new concepts).

My search bar “live” files are in lib/traveler_web/live/ and my module responsible for DB search is in lib/traveler/places/ (not in the traveler_web folder).

lib/traveler/places.ex
lib/traveler_web/live/searchbar_live.ex

In your case it should be:

lib/mono_phoenix_v01/monologues.ex

lib/mono_phoenix_v01_web/live/searchbar_live.ex
lib/mono_phoenix_v01_web/live/searchbar_live.html.heex

Hope that helps. You can read more about directory structure here.

Where Next?

Popular in Guides/Tuts Top

tfwright
I thought I’d share a small project I’m working on to gain some familiarty with LiveView in a Phoenix app. Github Repo Deployment It’s...
New
Logan
Here is an example of a Mix application that utilizes Cowboy to handle websocket connections. If anyone has an idea about making this wor...
New
sergio
I couldn’t find any guides that worked well with Phoenix 1.6.0 and esbuild. I hope this helps people test the waters and eases you into t...
New
WolfDan
So my main OS is Windows, I do must of my work with it, Elixir and vscode elixirls works just fine when you’re working only with elixir, ...
New
dkuku
I Created a blog post about setting up svelte with phoenix. I found it a bit tricky and the only blog post I found was written using som...
New
TwistingTwists
This is a thread to note down things/best practices encountered in LiveBeats App as I explore the source code. Found this usage of r...
New
wfgilman
I'm writing up this quick "How to" because what I thought was going to be an easy implementation of a Plug to validate a webhook request ...
New
lukertty
Install web-mode and mmm-mode first and put this in your config file: (require 'mmm-mode) (require 'web-mode) (setq mmm-global-mode 'may...
New
thetechnologyvault
One of our team members just published this getting started guide for Elixir/Phoenix devs to use the Nanobox platform: https://content.n...
New
slouchpie
Warmest greetings, comrades. I recently started using :dns_cluster (GitHub - phoenixframework/dns_cluster: Simple DNS clustering for dis...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3268 119930 1237
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

We're in Beta

About us Mission Statement