# Exploring built-in Kinos
```elixir
Mix.install([
{:kino, "~> 0.18.0"}
])
```
## Introduction
Throughout the Learning section, we have used Kino several times.
Sometimes we use built-in Kinos, such as using `Kino.Control` and
`Kino.Frame` to [deploy applications](/learn/notebooks/deploy-apps)
or for [plotting](/learn/notebooks/intro-to-vega-lite).
In this notebook, we will explore several of the built-in Kinos.
`kino` is already listed as a dependency, so let's get started.
<!-- livebook:{"branch_parent_index":0} -->
## Kino.Input
The [`Kino.Input`](https://hexdocs.pm/kino/Kino.Input.html)
module contains the most common kinos you will use. They are
used to define inputs in one cell, which you can read in a
future cell:
```elixir
name = Kino.Input.text("Your name")
```
and now we can greet the user back:
```elixir
IO.puts("Hello, #{Kino.Input.read(name)}!")
```
There are multiple types of inputs, such as text areas,
color dialogs, selects, and more. Feel free to explore them.
One important feature of inputs is that they are shared.
Once someone changes an input, it will reflect on all users
currently seeing the notebook.
<!-- livebook:{"branch_parent_index":0} -->
## Kino.Control
The [`Kino.Control`](https://hexdocs.pm/kino/Kino.Control.html)
module represents forms, buttons, and other interactive controls.
Opposite to `Kino.Input`, each user has their own control and
the main way to interact with controls is by listening to their
events.
```elixir
button = Kino.Control.button("Click me!")
```
```elixir
Kino.listen(button, fn event -> IO.inspect(event) end)
```
<!-- livebook:{"branch_parent_index":0} -->
## Kino.Markdown
Given our notebooks already know how to render Markdown,
you won't be surprised to find we can also render Markdown
directly from our Code cells. This is done by wrapping
the Markdown contents in [`Kino.Markdown.new/1`](https://hexdocs.pm/kino/Kino.Markdown.html):
````elixir
Kino.Markdown.new("""
# Example
A regular Markdown file.
## Code
```elixir
"Elixir" |> String.graphemes() |> Enum.frequencies()
```
## Table
| ID | Name | Website |
| -- | ------ | ----------------------- |
| 1 | Elixir | https://elixir-lang.org |
| 2 | Erlang | https://www.erlang.org |
""")
````
The way it works is that Livebook automatically detects
the output is a kino and renders it in Markdown. That's
the first of many kinos we will explore today. Let's move
forward.
<!-- livebook:{"branch_parent_index":0} -->
## Kino.Mermaid
You can include Mermaid diagrams in Markdown, however when generating diagrams dynamically, use `Kino.Mermaid.new/1`. This way the graphs will appear in the notebook source, if the user chooses to persist outputs.
```elixir
Kino.Mermaid.new("""
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
""")
```
<!-- livebook:{"branch_parent_index":0} -->
## Kino.DataTable
You can render arbitrary tabular data using [`Kino.DataTable.new/1`](https://hexdocs.pm/kino/Kino.DataTable.html), let's have a look:
```elixir
data = [
%{id: 1, name: "Elixir", website: "https://elixir-lang.org"},
%{id: 2, name: "Erlang", website: "https://www.erlang.org"}
]
Kino.DataTable.new(data)
```
The data must be an enumerable, with records being maps or
keyword lists.
Now, let's get some more realistic data. Whenever you run
Elixir code, you have several lightweight processes running
side-by-side. We can actually gather information about these
processes and render it as a table:
```elixir
keys = [:registered_name, :initial_call, :reductions, :stack_size]
processes =
for pid <- Process.list(),
info = Process.info(pid, keys),
do: info
Kino.DataTable.new(processes)
```
Now you can use the table above to sort by the number of
reductions and identify the most busy processes!
<!-- livebook:{"branch_parent_index":0} -->
## Kino.ETS
Kino supports multiple other data structures to be rendered
as tables. For example, you can use [`Kino.ETS`](https://hexdocs.pm/kino/Kino.ETS.html)
to render ETS tables and easily browse their contents.
Let's first create our own table:
```elixir
tid = :ets.new(:users, [:set, :public])
Kino.ETS.new(tid)
```
In fact, Livebook automatically recognises an ETS table and
renders it as such:
```elixir
tid
```
Currently the table is empty, so it's time to insert some rows.
```elixir
for id <- 1..24 do
:ets.insert(tid, {id, "User #{id}", :rand.uniform(100), "Description #{id}"})
end
```
Having the rows inserted, click on the "Refetch" icon in the table output
above to see them.
<!-- livebook:{"branch_parent_index":0} -->
## Kino.Tree
By default cell results are inspected with a limit on the text size. Inspecting large data structures with no limit makes the representation impractical to read, that's where `Kino.Tree` comes in!
```elixir
data = Process.info(self())
Kino.Tree.new(data)
```
<!-- livebook:{"branch_parent_index":0} -->
## Kino.render/1 and Kino.Frame
As we saw, Livebook automatically recognises widgets returned
from each cell and renders them accordingly. However, sometimes
it's useful to explicitly render a widget in the middle of the cell,
similarly to `IO.puts/1`, and that's exactly what `Kino.render/1`
does! It works with any type and tells Livebook to render the value
in its special manner.
```elixir
# Arbitrary data structures
Kino.render([%{name: "Ada Lovelace"}, %{name: "Alan Turing"}])
Kino.render("Plain text")
# Some kinos
Kino.render(Kino.Markdown.new("**Hello world**"))
"Cell result 🚀"
```
The `Kino.Frame` construct we used when deploying our chat app is a
generalization of `Kino.render`, which gives us more control over when
to update, append, or clear the output:
```elixir
frame = Kino.Frame.new()
```
By default, a frame will update in place. Try running the cell below
several times:
```elixir
Kino.Frame.render(frame, "Got: #{Enum.random(1..100)}")
```
but you can use `append` and `clear` to get different results.
<!-- livebook:{"branch_parent_index":0} -->
## Kino.Layout
In case you need to arrange multiple kinos, `Kino.Layout` gives you some options!
For one, you can create tabs to show just one thing at a time:
```elixir
data = [
%{id: 1, name: "Elixir", website: "https://elixir-lang.org"},
%{id: 2, name: "Erlang", website: "https://www.erlang.org"}
]
Kino.Layout.tabs(
Table: Kino.DataTable.new(data),
Raw: data
)
```
Then, there is a simple grid that you can use for laying out multiple elements:
```elixir
Kino.Layout.grid(["1", "2", "3", "4"], columns: 2)
```
And you can nest grid any way you like:
```elixir
urls = [
"https://images.unsplash.com/photo-1603203040743-24aced6793b4?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=580&h=580&q=80",
"https://images.unsplash.com/photo-1578339850459-76b0ac239aa2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=580&h=580&q=80",
"https://images.unsplash.com/photo-1633479397973-4e69efa75df2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=580&h=580&q=80",
"https://images.unsplash.com/photo-1597838816882-4435b1977fbe?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=580&h=580&q=80",
"https://images.unsplash.com/photo-1629778712393-4f316eee143e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=580&h=580&q=80",
"https://images.unsplash.com/photo-1638667168629-58c2516fbd22?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=580&h=580&q=80"
]
images =
for {url, i} <- Enum.with_index(urls, 1) do
# For in-memory photo we would use Kino.Image
image = Kino.Markdown.new("")
label = Kino.Markdown.new("**Image #{i}**")
Kino.Layout.grid([image, label], boxed: true)
end
Kino.Layout.grid(images, columns: 3)
```
<!-- livebook:{"branch_parent_index":0} -->
## Kino.Shorts
The `Kino` library also provides a [`Kino.Shorts`](https://hexdocs.pm/kino/Kino.Shorts.html)
module, which wraps and unifies most of the functionality we've seen so far.
Let's import it and give it a try:
```elixir
import Kino.Shorts
```
For example, we use `Kino.Input` to render and then read an input.
With `Kino.Shorts`, this can be achieved with a single step:
```elixir
name = read_text("Your name: ")
```
Once you execute the cell, the input will appear and, the first time
around, the value with be an empty string. You can pair this with
`Kino.interrupt!/2` to read and validate inputs:
```elixir
name = read_text("Your name: ")
if name == "" do
Kino.interrupt!(:error, "You must fill in your name")
end
```
There are several other helpers in `Kino.Shorts`. For example,
in the previous section we used grids with markdown to display
and link several images. Using `Kino.Shorts`, we can simplify it as:
```elixir
urls = [
"https://images.unsplash.com/photo-1603203040743-24aced6793b4?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=580&h=580&q=80",
"https://images.unsplash.com/photo-1578339850459-76b0ac239aa2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=580&h=580&q=80",
"https://images.unsplash.com/photo-1633479397973-4e69efa75df2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=580&h=580&q=80",
"https://images.unsplash.com/photo-1597838816882-4435b1977fbe?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=580&h=580&q=80",
"https://images.unsplash.com/photo-1629778712393-4f316eee143e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=580&h=580&q=80",
"https://images.unsplash.com/photo-1638667168629-58c2516fbd22?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=580&h=580&q=80"
]
images =
for {url, i} <- Enum.with_index(urls, 1) do
image = markdown("")
label = markdown("**Image #{i}**")
grid([image, label], boxed: true)
end
grid(images, columns: 3)
```
<!-- livebook:{"branch_parent_index":0} -->
## dbg
Kino hijacks Elixir's [`dbg/2`](https://hexdocs.pm/elixir/Kernel.html#dbg/2)
to provide Kino-based debugging:
```elixir
dbg(Atom.to_string(:hello))
```
When debugging a pipeline, Kino will render each step of the pipeline, allowing
to inspect, toggle, and swap each operation along the way:
```elixir
"Elixir is cool!"
|> String.trim_trailing("!")
|> String.split()
|> List.first()
|> dbg()
```
## Next steps
We have learned many new Kinos in this section. In the next guide,
we will put some of our new found knowledge into practice [by rendering
inputs, plotting graphs, and drawing diagrams with information retrieved
from the notebook runtime](/learn/notebooks/vm-introspection).