//! # [Ratatui] Block example
//! The latest version of this example is available in the [examples] folder in the repository.
//! Please note that the examples are designed to be run against the `main` branch of the Github
//! repository. This means that you may not be able to compile with the latest release version on
//! crates.io, or the one that you have installed locally.
//! See the [examples readme] for more information on finding examples that match the version of the
//! library you are using.
//! [Ratatui]: https://github.com/ratatui-org/ratatui
//! [examples]: https://github.com/ratatui-org/ratatui/blob/main/examples
//! [examples readme]: https://github.com/ratatui-org/ratatui/blob/main/examples/README.md
use itertools::Itertools;
event::{self, Event, KeyCode},
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
block::{Position, Title},
Block, BorderType, Borders, Padding, Paragraph, Wrap,
// These type aliases are used to make the code more readable by reducing repetition of the generic
// types. They are not necessary for the functionality of the code.
type Terminal = ratatui::Terminal<CrosstermBackend<Stdout>>;
type Result<T> = std::result::Result<T, Box<dyn Error>>;
fn main() -> Result<()> {
let mut terminal = setup_terminal()?;
let result = run(&mut terminal);
restore_terminal(terminal)?;
if let Err(err) = result {
fn setup_terminal() -> Result<Terminal> {
let mut stdout = stdout();
execute!(stdout, EnterAlternateScreen)?;
let backend = CrosstermBackend::new(stdout);
let terminal = Terminal::new(backend)?;
fn restore_terminal(mut terminal: Terminal) -> Result<()> {
execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
fn run(terminal: &mut Terminal) -> Result<()> {
if handle_events()?.is_break() {
fn handle_events() -> Result<ControlFlow<()>> {
if event::poll(Duration::from_millis(100))? {
if let Event::Key(key) = event::read()? {
if key.code == KeyCode::Char('q') {
return Ok(ControlFlow::Break(()));
Ok(ControlFlow::Continue(()))
fn ui(frame: &mut Frame) {
let (title_area, layout) = calculate_layout(frame.size());
render_title(frame, title_area);
let paragraph = placeholder_paragraph();
render_borders(¶graph, Borders::ALL, frame, layout[0][0]);
render_borders(¶graph, Borders::NONE, frame, layout[0][1]);
render_borders(¶graph, Borders::LEFT, frame, layout[1][0]);
render_borders(¶graph, Borders::RIGHT, frame, layout[1][1]);
render_borders(¶graph, Borders::TOP, frame, layout[2][0]);
render_borders(¶graph, Borders::BOTTOM, frame, layout[2][1]);
render_border_type(¶graph, BorderType::Plain, frame, layout[3][0]);
render_border_type(¶graph, BorderType::Rounded, frame, layout[3][1]);
render_border_type(¶graph, BorderType::Double, frame, layout[4][0]);
render_border_type(¶graph, BorderType::Thick, frame, layout[4][1]);
render_styled_block(¶graph, frame, layout[5][0]);
render_styled_borders(¶graph, frame, layout[5][1]);
render_styled_title(¶graph, frame, layout[6][0]);
render_styled_title_content(¶graph, frame, layout[6][1]);
render_multiple_titles(¶graph, frame, layout[7][0]);
render_multiple_title_positions(¶graph, frame, layout[7][1]);
render_padding(¶graph, frame, layout[8][0]);
render_nested_blocks(¶graph, frame, layout[8][1]);
/// Calculate the layout of the UI elements.
/// Returns a tuple of the title area and the main areas.
fn calculate_layout(area: Rect) -> (Rect, Vec<Vec<Rect>>) {
let main_layout = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
let block_layout = Layout::vertical([Constraint::Max(4); 9]);
let [title_area, main_area] = main_layout.areas(area);
let main_areas = block_layout
Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
fn render_title(frame: &mut Frame, area: Rect) {
Paragraph::new("Block example. Press q to quit")
.alignment(Alignment::Center),
fn placeholder_paragraph() -> Paragraph<'static> {
let text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
Paragraph::new(text.dark_gray()).wrap(Wrap { trim: true })
fn render_borders(paragraph: &Paragraph, border: Borders, frame: &mut Frame, area: Rect) {
.title(format!("Borders::{border:#?}"));
frame.render_widget(paragraph.clone().block(block), area);
let block = Block::bordered()
.border_type(border_type)
.title(format!("BorderType::{border_type:#?}"));
frame.render_widget(paragraph.clone().block(block), area);
fn render_styled_borders(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
let block = Block::bordered()
.border_style(Style::new().blue().on_white().bold().italic())
.title("Styled borders");
frame.render_widget(paragraph.clone().block(block), area);
fn render_styled_block(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
let block = Block::bordered()
.style(Style::new().blue().on_white().bold().italic())
frame.render_widget(paragraph.clone().block(block), area);
// Note: this currently renders incorrectly, see https://github.com/ratatui-org/ratatui/issues/349
fn render_styled_title(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
let block = Block::bordered()
.title_style(Style::new().blue().on_white().bold().italic());
frame.render_widget(paragraph.clone().block(block), area);
fn render_styled_title_content(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
let title = Line::from(vec![
"Styled ".blue().on_white().bold().italic(),
"title content".red().on_white().bold().italic(),
let block = Block::bordered().title(title);
frame.render_widget(paragraph.clone().block(block), area);
fn render_multiple_titles(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
let block = Block::bordered()
.title("Multiple".blue().on_white().bold().italic())
.title("Titles".red().on_white().bold().italic());
frame.render_widget(paragraph.clone().block(block), area);
fn render_multiple_title_positions(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
let block = Block::bordered()
.alignment(Alignment::Left),
Title::from("top center")
.alignment(Alignment::Center),
.alignment(Alignment::Right),
Title::from("bottom left")
.position(Position::Bottom)
.alignment(Alignment::Left),
Title::from("bottom center")
.position(Position::Bottom)
.alignment(Alignment::Center),
Title::from("bottom right")
.position(Position::Bottom)
.alignment(Alignment::Right),
frame.render_widget(paragraph.clone().block(block), area);
fn render_padding(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
let block = Block::bordered()
.padding(Padding::new(5, 10, 1, 2))
frame.render_widget(paragraph.clone().block(block), area);
fn render_nested_blocks(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
let outer_block = Block::bordered().title("Outer block");
let inner_block = Block::bordered().title("Inner block");
let inner = outer_block.inner(area);
frame.render_widget(outer_block, area);
frame.render_widget(paragraph.clone().block(inner_block), inner);