bgoosman

bgoosman

It’s easy to create a Kino.frame and render some status text like “Loading” or “Idle”. Ideally I’d like to disable the submit button in my form and display a spinner inside it.

I’m wondering what elixirforum friendly folks do in their Livebooks! :slight_smile:

Showing Posts 1 to 10

joelpaulkoch

joelpaulkoch

Hey, looks like you’re really lucky: Elixir Blog Posts - #1129 by tommica

bgoosman

bgoosman OP

I’m not sure - that blog post was written for Liveview. Is it applicable to Livebook? :thinking:

joelpaulkoch

joelpaulkoch

Oh, you’re right.. I think you could do something similar with Kino.HTML?

bgoosman

bgoosman OP

Yeah, I think Kino.HTML might be it. I could create a reusable spinner component, then render it into a Frame whenever there is some async task.

adammokan

adammokan

There is a little bit of prior art in the form of hex.pm/packages/kino_progress_bar.

Even if it doesn’t meet your needs, it may serve as inspiration for a new solution.

hugobarauna

hugobarauna

Livebook Core Team

You can build your own spinner UI component based on Kino.HTML like that:

defmodule KinoSpinner do
  def new(dimensions \\ "30px") do
    Kino.HTML.new("""
    <div class="loader"></div>

    <style>
      .loader {
        border: 16px solid #f3f3f3; /* Light grey */
        border-top: 16px solid #3498db; /* Blue */
        border-radius: 50%;
        width: #{dimensions};
        height: #{dimensions};
        animation: spin 2s linear infinite;
      }

      @keyframes spin {
        0% { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
      }
    </style>
    """)
  end
end

And use like this in a form:

form =
  Kino.Control.form(
    [
      name: Kino.Input.text("Data", default: "some data to process")
    ],
    submit: "Submit"
  )

output_frame = frame()

Kino.listen(form, fn _event ->
  Kino.Frame.render(output_frame, grid([text("Processing..."), KinoSpinner.new()]))
  Process.sleep(2_000)
  Kino.Frame.render(output_frame, "Processing is done. ✅")
end)

grid([form, output_frame])

Here’s a quick video demo: CleanShot 2024-09-18 at 13.47.38 · CleanShot Cloud

Or you can use a custom kino from the community, like this one from Andrés Alejos:

form =
  Kino.Control.form(
    [
      name: Kino.Input.text("Data", default: "some data to process")
    ],
    submit: "Submit"
  )

output_frame = frame()

Kino.listen(form, fn _event ->
  progress_bar = KinoProgressBar.new(max: 100)
  Kino.Frame.render(output_frame, progress_bar)

  Enum.each(1..100, fn index ->
    KinoProgressBar.update(progress_bar, index, 100)
    Process.sleep(50)
  end)

  Kino.Frame.render(output_frame, "Processing is done. ✅")
end)

grid([form, output_frame])

Here’s a quick video demo: CleanShot 2024-09-18 at 13.49.15 · CleanShot Cloud

Here’s the notebook with both demos: How to display progress using Kino · GitHub

bgoosman

bgoosman OP

Wow, thanks for the high effort post Hugo!

bgoosman

bgoosman OP

~btw I think you meant to write Kino.Frame.new() instead of frame()? Where does frame() come from?~

Nevermind, import Kino.Shorts is the answer.

bgoosman

bgoosman OP

It seems that grid() breaks the <enter> key behavior in the form’s text input. Where should I report that?

hugobarauna

hugobarauna

Livebook Core Team
— All posts loaded —

Where Next? Top

Trending in Questions Top

katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
apz
I’m new to elixir and just tried to install the elixirLS extension for VScode(ium) and it is throwing some errors that I would like help ...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews