Introduction to Widgets
Widgets are the building blocks of user interfaces in Ratatui. They are used to create and manage the layout and style of the terminal interface. Widgets can be combined and nested to create complex UIs, and can be easily customized to suit the needs of your application.
Ratatui provides a wide variety of built-in widgets that can be used to quickly create UIs. These widgets include:
Block
|Example
: A basic Widget that draws a block with optional borders, titles, and styles.BarChart
|Example
: Displays multiple datasets as bars with optional grouping.Calendar
|Example
: Displays a single month.Canvas
|Example
: Draws arbitrary shapes using drawing characters.Chart
|Example
: Displays multiple datasets as a lines or scatter graph.Clear
: Clears the area it occupies. Useful to render over previously drawn widgets.Gauge
|Example
: Displays progress percentage using block characters.LineGauge
: Display progress as a line.List
|Example
: Displays a list of items and allows selection.Paragraph
|Example
: Displays a paragraph of optionally styled and wrapped text.Scrollbar
|Example
: Displays a scrollbar.Sparkline
|Example
: Display a single data set as a sparkline.Table
|Example
: Displays multiple rows and columns in a grid and allows selection.Tabs
|Example
: Displays a tab bar and allows selection.
Additionally, String
, &str
, Span
, Line
, and Text
can be used as widgets (though
it’s common to use Paragraph
instead of these directly).
For more information on these widgets, you can view the Widgets API docs and the Widget showcase. Additionally, there are several third-party widgets available that can be used with Ratatui, which can be found on the third-party widgets showcase and in the Awesome Ratatui repository.
Widget Traits
In Ratatui, widgets are implemented as Rust traits, which allow for easy implementation and
extension. The two main traits for widgets are Widget
and StatefulWidget
, which provide the
basic functionality for rendering and managing the state of a Widget.
Additionally, the WidgetRef
and StatefulWidgetRef
traits allow for rendering widgets by
reference, which can be useful for storing and rendering collections of widgets. The latter two
traits were added in Ratatui 0.26 and are at the time of writing, gated by an unstable feature flag,
so there may be limited third party use of these traits. All the internal widgets have been updated
to implement the ref traits and there is also a blanket implementation of
Widget for &T where T: WidgetRef
.
Widget
The Widget
trait is the most basic trait for widgets in Ratatui. It provides the basic
functionality for rendering a Widget onto a buffer.
StatefulWidget
The StatefulWidget
trait is similar to the Widget
trait, but also includes a state that can
be managed and updated during rendering.
WidgetRef and StatefulWidgetRef
The WidgetRef
trait allows for rendering a Widget by reference instead of consuming the widget,
which can be useful for storing and rendering individual or collections of widgets.
The StatefulWidgetRef
trait is similar to the WidgetRef
trait, but also includes a state
that can be managed and updated during rendering.
These two traits were introduced in Ratatui 0.26.0 to help avoid a shortcoming that meant that
widgets were always consumed on rendering while not breaking all code that has previously been built
with that assumption. These two widgets are currently marked as unstable and gated behind the
unstable-widget-ref
feature flag.
Using Widgets
In Ratatui, widgets are used to create and manage the layout and style of the terminal interface. widgets can be combined and nested to create complex UIs, and can be easily customized to suit the needs of your application.
To use widgets in your application, you will typically use the Frame
type, which has two methods
for rendering widgets: render_widget
and render_stateful_widget
(and the corresponding
_ref
methods). These methods are the entry points for an application to draw widgets and are
usually called from the closure that is passed to the [Terminal::draw
] method.
Here’s an example of using the render_widget
method to draw a Widget:
And here’s an example of using the render_stateful_widget
method to draw a StatefulWidget:
These methods internally call the render
function on the Widget
or StatefulWidget
trait,
which will then call the render
function on the specific WidgetRef
or StatefulWidgetRef
that you have implemented.
A common compositional pattern is to only have a single root widget (the App
struct in the example
below) that is passed to Frame::render_widget()
and then within that and other widgets, you call
the render methods directly passing in the area which you want to render the widgets to.
Implementing Widgets
In Ratatui, widgets are implemented as Rust traits, which allow for easy implementation and
extension. The two main traits for widgets are Widget
and StatefulWidget
, which provide the
basic functionality for rendering and managing the state of a Widget.
Here’s an example of implementing the Widget
trait for a simple greeting Widget:
In this example, the GreetingWidget
struct has a single field, name
, which is a String
. The
render
function takes a Rect
and a mutable reference to a Buffer
, and sets the string at the
specified coordinates in the buffer.
Widgets are not restricted to just calling methods on Buffer
. They can also create and render
other widgets within their render
method. For example, instead of directly calling methods on
buf
, a Widget can create a Line
widget with a vector of Span
s, where the Span
for the name
is styled. This Line
widget can then be rendered within the Widget’s render
method.
Here’s the same greeting example using nested widgets:
This approach allows for composing and reusing widgets. For example, the Line
widget can be used
in other widgets or even in other parts of the application. Additionally, it allows for easier
testing and maintenance of widgets as the code related to rendering is organized in a consistent
place (the impl Widget
blocks).
Implementing Stateful Widgets
In some situations, a widget might need to be able to mutate some extra state while rendering
itself. An example of this is how the built-in List
widget works. During rendering the List
updates the scroll position in the state to ensure that the selected item is visible in the
rendering area.
Here’s an example of implementing the StatefulWidget
trait for a frame count Widget:
In this example, the FrameCount
widget increments the state every time it is rendered, counting
the number of frames.
Implementing WidgetRef
In Ratatui 0.26.0, we added the WidgetRef
(and similarly StatefulWidgetRef
) traits. These
allow widgets to be created that are rendering by reference, which can be useful for storing a
widget which can be rendered multiple times instead of constructing it on every frame. This also
makes it easy to create dynamic collections of widgets (e.g. Panes in a layout) by boxing the
widgets using Box<dyn T>
.
Implementing WidgetRef
/ StatefulWidgetRef
is similar to implementing the consuming versions of
the traits (with the difference being that the method name is render_ref
and self is a reference).
This can be useful as a way to store the widgets between frames. E.g.:
In situations where there is a collection of widgets of different types, or a single widget that
doesn’t have a type known at compile time, the ref traits make it possible to store widgets as trait
objects by using Box<T>
.
E.g. the following code shows how you might have two different widgets stored in a Vec
that are
later rendered without knowing the type of each widget at runtime.