ratatui::style

Trait Stylize

source
pub trait Stylize<'a, T>: Sized {
Show 55 methods // Required methods fn bg<C: Into<Color>>(self, color: C) -> T; fn fg<C: Into<Color>>(self, color: C) -> T; fn reset(self) -> T; fn add_modifier(self, modifier: Modifier) -> T; fn remove_modifier(self, modifier: Modifier) -> T; // Provided methods fn black(self) -> T { ... } fn on_black(self) -> T { ... } fn red(self) -> T { ... } fn on_red(self) -> T { ... } fn green(self) -> T { ... } fn on_green(self) -> T { ... } fn yellow(self) -> T { ... } fn on_yellow(self) -> T { ... } fn blue(self) -> T { ... } fn on_blue(self) -> T { ... } fn magenta(self) -> T { ... } fn on_magenta(self) -> T { ... } fn cyan(self) -> T { ... } fn on_cyan(self) -> T { ... } fn gray(self) -> T { ... } fn on_gray(self) -> T { ... } fn dark_gray(self) -> T { ... } fn on_dark_gray(self) -> T { ... } fn light_red(self) -> T { ... } fn on_light_red(self) -> T { ... } fn light_green(self) -> T { ... } fn on_light_green(self) -> T { ... } fn light_yellow(self) -> T { ... } fn on_light_yellow(self) -> T { ... } fn light_blue(self) -> T { ... } fn on_light_blue(self) -> T { ... } fn light_magenta(self) -> T { ... } fn on_light_magenta(self) -> T { ... } fn light_cyan(self) -> T { ... } fn on_light_cyan(self) -> T { ... } fn white(self) -> T { ... } fn on_white(self) -> T { ... } fn bold(self) -> T { ... } fn not_bold(self) -> T { ... } fn dim(self) -> T { ... } fn not_dim(self) -> T { ... } fn italic(self) -> T { ... } fn not_italic(self) -> T { ... } fn underlined(self) -> T { ... } fn not_underlined(self) -> T { ... } fn slow_blink(self) -> T { ... } fn not_slow_blink(self) -> T { ... } fn rapid_blink(self) -> T { ... } fn not_rapid_blink(self) -> T { ... } fn reversed(self) -> T { ... } fn not_reversed(self) -> T { ... } fn hidden(self) -> T { ... } fn not_hidden(self) -> T { ... } fn crossed_out(self) -> T { ... } fn not_crossed_out(self) -> T { ... }
}
Expand description

An extension trait for styling objects.

For any type that implements Stylize, the provided methods in this trait can be used to style the type further. This trait is automatically implemented for any type that implements the Styled trait which e.g.: String, &str, Span, Style and many Widget types.

This results in much more ergonomic styling of text and widgets. For example, instead of writing:

let text = Span::styled("Hello", Style::default().fg(Color::Red).bg(Color::Blue));

You can write:

let text = "Hello".red().on_blue();

This trait implements a provided method for every color as both foreground and background (prefixed by on_), and all modifiers as both an additive and subtractive modifier (prefixed by not_). The reset() method is also provided to reset the style.

§Examples

use ratatui::{
    style::{Color, Modifier, Style, Stylize},
    text::Line,
    widgets::{Block, Paragraph},
};

let span = "hello".red().on_blue().bold();
let line = Line::from(vec![
    "hello".red().on_blue().bold(),
    "world".green().on_yellow().not_bold(),
]);
let paragraph = Paragraph::new(line).italic().underlined();
let block = Block::bordered().title("Title").on_white().bold();

Required Methods§

source

fn bg<C: Into<Color>>(self, color: C) -> T

source

fn fg<C: Into<Color>>(self, color: C) -> T

source

fn reset(self) -> T

source

fn add_modifier(self, modifier: Modifier) -> T

source

fn remove_modifier(self, modifier: Modifier) -> T

Provided Methods§

source

fn black(self) -> T

Sets the foreground color to black.

Examples found in repository?
examples/paragraph.rs (line 145)
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
fn create_lines(area: Rect) -> Vec<Line<'static>> {
    let short_line = "A long line to demonstrate line wrapping. ";
    let long_line = short_line.repeat(usize::from(area.width) / short_line.len() + 4);
    let mut styled_spans = vec![];
    for span in [
        "Styled".blue(),
        "Spans".red().on_white(),
        "Bold".bold(),
        "Italic".italic(),
        "Underlined".underlined(),
        "Strikethrough".crossed_out(),
    ] {
        styled_spans.push(span);
        styled_spans.push(" ".into());
    }
    vec![
        Line::raw("Unstyled Line"),
        Line::raw("Styled Line").black().on_red().bold().italic(),
        Line::from(styled_spans),
        Line::from(long_line.green().italic()),
        Line::from_iter([
            "Masked text: ".into(),
            Span::styled(Masked::new("my secret password", '*'), Color::Red),
        ]),
    ]
}
source

fn on_black(self) -> T

Sets the background color to black.

source

fn red(self) -> T

Sets the foreground color to red.

Examples found in repository?
examples/block.rs (line 149)
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
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);
}
More examples
Hide additional examples
examples/demo2/tabs/weather.rs (line 68)
66
67
68
69
70
71
72
73
fn render_calendar(area: Rect, buf: &mut Buffer) {
    let date = OffsetDateTime::now_utc().date();
    Monthly::new(date, CalendarEventStore::today(Style::new().red().bold()))
        .block(Block::new().padding(Padding::new(0, 0, 2, 0)))
        .show_month_header(Style::new().bold())
        .show_weekdays_header(Style::new().italic())
        .render(area, buf);
}
examples/paragraph.rs (line 134)
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
fn create_lines(area: Rect) -> Vec<Line<'static>> {
    let short_line = "A long line to demonstrate line wrapping. ";
    let long_line = short_line.repeat(usize::from(area.width) / short_line.len() + 4);
    let mut styled_spans = vec![];
    for span in [
        "Styled".blue(),
        "Spans".red().on_white(),
        "Bold".bold(),
        "Italic".italic(),
        "Underlined".underlined(),
        "Strikethrough".crossed_out(),
    ] {
        styled_spans.push(span);
        styled_spans.push(" ".into());
    }
    vec![
        Line::raw("Unstyled Line"),
        Line::raw("Styled Line").black().on_red().bold().italic(),
        Line::from(styled_spans),
        Line::from(long_line.green().italic()),
        Line::from_iter([
            "Masked text: ".into(),
            Span::styled(Masked::new("my secret password", '*'), Color::Red),
        ]),
    ]
}
examples/scrollbar.rs (line 112)
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
    fn draw(&mut self, frame: &mut Frame) {
        let area = frame.area();

        // Words made "loooong" to demonstrate line breaking.
        let s =
            "Veeeeeeeeeeeeeeeery    loooooooooooooooooong   striiiiiiiiiiiiiiiiiiiiiiiiiing.   ";
        let mut long_line = s.repeat(usize::from(area.width) / s.len() + 4);
        long_line.push('\n');

        let chunks = Layout::vertical([
            Constraint::Min(1),
            Constraint::Percentage(25),
            Constraint::Percentage(25),
            Constraint::Percentage(25),
            Constraint::Percentage(25),
        ])
        .split(area);

        let text = vec![
            Line::from("This is a line "),
            Line::from("This is a line   ".red()),
            Line::from("This is a line".on_dark_gray()),
            Line::from("This is a longer line".crossed_out()),
            Line::from(long_line.clone()),
            Line::from("This is a line".reset()),
            Line::from(vec![
                Span::raw("Masked text: "),
                Span::styled(Masked::new("password", '*'), Style::new().fg(Color::Red)),
            ]),
            Line::from("This is a line "),
            Line::from("This is a line   ".red()),
            Line::from("This is a line".on_dark_gray()),
            Line::from("This is a longer line".crossed_out()),
            Line::from(long_line.clone()),
            Line::from("This is a line".reset()),
            Line::from(vec![
                Span::raw("Masked text: "),
                Span::styled(Masked::new("password", '*'), Style::new().fg(Color::Red)),
            ]),
        ];
        self.vertical_scroll_state = self.vertical_scroll_state.content_length(text.len());
        self.horizontal_scroll_state = self.horizontal_scroll_state.content_length(long_line.len());

        let create_block = |title: &'static str| Block::bordered().gray().title(title.bold());

        let title = Block::new()
            .title_alignment(Alignment::Center)
            .title("Use h j k l or ◄ ▲ ▼ ► to scroll ".bold());
        frame.render_widget(title, chunks[0]);

        let paragraph = Paragraph::new(text.clone())
            .gray()
            .block(create_block("Vertical scrollbar with arrows"))
            .scroll((self.vertical_scroll as u16, 0));
        frame.render_widget(paragraph, chunks[1]);
        frame.render_stateful_widget(
            Scrollbar::new(ScrollbarOrientation::VerticalRight)
                .begin_symbol(Some("↑"))
                .end_symbol(Some("↓")),
            chunks[1],
            &mut self.vertical_scroll_state,
        );

        let paragraph = Paragraph::new(text.clone())
            .gray()
            .block(create_block(
                "Vertical scrollbar without arrows, without track symbol and mirrored",
            ))
            .scroll((self.vertical_scroll as u16, 0));
        frame.render_widget(paragraph, chunks[2]);
        frame.render_stateful_widget(
            Scrollbar::new(ScrollbarOrientation::VerticalLeft)
                .symbols(scrollbar::VERTICAL)
                .begin_symbol(None)
                .track_symbol(None)
                .end_symbol(None),
            chunks[2].inner(Margin {
                vertical: 1,
                horizontal: 0,
            }),
            &mut self.vertical_scroll_state,
        );

        let paragraph = Paragraph::new(text.clone())
            .gray()
            .block(create_block(
                "Horizontal scrollbar with only begin arrow & custom thumb symbol",
            ))
            .scroll((0, self.horizontal_scroll as u16));
        frame.render_widget(paragraph, chunks[3]);
        frame.render_stateful_widget(
            Scrollbar::new(ScrollbarOrientation::HorizontalBottom)
                .thumb_symbol("🬋")
                .end_symbol(None),
            chunks[3].inner(Margin {
                vertical: 0,
                horizontal: 1,
            }),
            &mut self.horizontal_scroll_state,
        );

        let paragraph = Paragraph::new(text.clone())
            .gray()
            .block(create_block(
                "Horizontal scrollbar without arrows & custom thumb and track symbol",
            ))
            .scroll((0, self.horizontal_scroll as u16));
        frame.render_widget(paragraph, chunks[4]);
        frame.render_stateful_widget(
            Scrollbar::new(ScrollbarOrientation::HorizontalBottom)
                .thumb_symbol("░")
                .track_symbol(Some("─")),
            chunks[4].inner(Margin {
                vertical: 0,
                horizontal: 1,
            }),
            &mut self.horizontal_scroll_state,
        );
    }
source

fn on_red(self) -> T

Sets the background color to red.

Examples found in repository?
examples/layout.rs (line 169)
168
169
170
171
172
173
174
175
176
177
fn render_single_example(frame: &mut Frame, area: Rect, constraints: Vec<Constraint>) {
    let red = Paragraph::new(constraint_label(constraints[0])).on_red();
    let blue = Paragraph::new(constraint_label(constraints[1])).on_blue();
    let green = Paragraph::new("·".repeat(12)).on_green();
    let horizontal = Layout::horizontal(constraints);
    let [r, b, g] = horizontal.areas(area);
    frame.render_widget(red, r);
    frame.render_widget(blue, b);
    frame.render_widget(green, g);
}
More examples
Hide additional examples
examples/paragraph.rs (line 145)
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
fn create_lines(area: Rect) -> Vec<Line<'static>> {
    let short_line = "A long line to demonstrate line wrapping. ";
    let long_line = short_line.repeat(usize::from(area.width) / short_line.len() + 4);
    let mut styled_spans = vec![];
    for span in [
        "Styled".blue(),
        "Spans".red().on_white(),
        "Bold".bold(),
        "Italic".italic(),
        "Underlined".underlined(),
        "Strikethrough".crossed_out(),
    ] {
        styled_spans.push(span);
        styled_spans.push(" ".into());
    }
    vec![
        Line::raw("Unstyled Line"),
        Line::raw("Styled Line").black().on_red().bold().italic(),
        Line::from(styled_spans),
        Line::from(long_line.green().italic()),
        Line::from_iter([
            "Masked text: ".into(),
            Span::styled(Masked::new("my secret password", '*'), Color::Red),
        ]),
    ]
}
source

fn green(self) -> T

Sets the foreground color to green.

Examples found in repository?
examples/paragraph.rs (line 147)
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
fn create_lines(area: Rect) -> Vec<Line<'static>> {
    let short_line = "A long line to demonstrate line wrapping. ";
    let long_line = short_line.repeat(usize::from(area.width) / short_line.len() + 4);
    let mut styled_spans = vec![];
    for span in [
        "Styled".blue(),
        "Spans".red().on_white(),
        "Bold".bold(),
        "Italic".italic(),
        "Underlined".underlined(),
        "Strikethrough".crossed_out(),
    ] {
        styled_spans.push(span);
        styled_spans.push(" ".into());
    }
    vec![
        Line::raw("Unstyled Line"),
        Line::raw("Styled Line").black().on_red().bold().italic(),
        Line::from(styled_spans),
        Line::from(long_line.green().italic()),
        Line::from_iter([
            "Masked text: ".into(),
            Span::styled(Masked::new("my secret password", '*'), Color::Red),
        ]),
    ]
}
source

fn on_green(self) -> T

Sets the background color to green.

Examples found in repository?
examples/layout.rs (line 171)
168
169
170
171
172
173
174
175
176
177
fn render_single_example(frame: &mut Frame, area: Rect, constraints: Vec<Constraint>) {
    let red = Paragraph::new(constraint_label(constraints[0])).on_red();
    let blue = Paragraph::new(constraint_label(constraints[1])).on_blue();
    let green = Paragraph::new("·".repeat(12)).on_green();
    let horizontal = Layout::horizontal(constraints);
    let [r, b, g] = horizontal.areas(area);
    frame.render_widget(red, r);
    frame.render_widget(blue, b);
    frame.render_widget(green, g);
}
source

fn yellow(self) -> T

Sets the foreground color to yellow.

Examples found in repository?
examples/canvas.rs (line 185)
176
177
178
179
180
181
182
183
184
185
186
187
188
189
    fn map_canvas(&self) -> impl Widget + '_ {
        Canvas::default()
            .block(Block::bordered().title("World"))
            .marker(self.marker)
            .paint(|ctx| {
                ctx.draw(&Map {
                    color: Color::Green,
                    resolution: MapResolution::High,
                });
                ctx.print(self.x, -self.y, "You are here".yellow());
            })
            .x_bounds([-180.0, 180.0])
            .y_bounds([-90.0, 90.0])
    }
More examples
Hide additional examples
examples/chart.rs (line 253)
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
fn render_scatter(frame: &mut Frame, area: Rect) {
    let datasets = vec![
        Dataset::default()
            .name("Heavy")
            .marker(Marker::Dot)
            .graph_type(GraphType::Scatter)
            .style(Style::new().yellow())
            .data(&HEAVY_PAYLOAD_DATA),
        Dataset::default()
            .name("Medium".underlined())
            .marker(Marker::Braille)
            .graph_type(GraphType::Scatter)
            .style(Style::new().magenta())
            .data(&MEDIUM_PAYLOAD_DATA),
        Dataset::default()
            .name("Small")
            .marker(Marker::Dot)
            .graph_type(GraphType::Scatter)
            .style(Style::new().cyan())
            .data(&SMALL_PAYLOAD_DATA),
    ];

    let chart = Chart::new(datasets)
        .block(Block::bordered().title(Line::from("Scatter chart").cyan().bold().centered()))
        .x_axis(
            Axis::default()
                .title("Year")
                .bounds([1960., 2020.])
                .style(Style::default().fg(Color::Gray))
                .labels(["1960", "1990", "2020"]),
        )
        .y_axis(
            Axis::default()
                .title("Cost")
                .bounds([0., 75000.])
                .style(Style::default().fg(Color::Gray))
                .labels(["0", "37 500", "75 000"]),
        )
        .hidden_legend_constraints((Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)));

    frame.render_widget(chart, area);
}
source

fn on_yellow(self) -> T

Sets the background color to yellow.

source

fn blue(self) -> T

Sets the foreground color to blue.

Examples found in repository?
examples/hyperlink.rs (line 45)
44
45
46
47
48
    fn new() -> Self {
        let text = Line::from(vec!["Example ".into(), "hyperlink".blue()]);
        let hyperlink = Hyperlink::new(text, "https://example.com");
        Self { hyperlink }
    }
More examples
Hide additional examples
examples/block.rs (line 127)
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
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())
        .title("Styled block");
    frame.render_widget(paragraph.clone().block(block), area);
}

fn render_styled_title(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
    let block = Block::bordered()
        .title("Styled title")
        .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);
}
examples/paragraph.rs (line 133)
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
fn create_lines(area: Rect) -> Vec<Line<'static>> {
    let short_line = "A long line to demonstrate line wrapping. ";
    let long_line = short_line.repeat(usize::from(area.width) / short_line.len() + 4);
    let mut styled_spans = vec![];
    for span in [
        "Styled".blue(),
        "Spans".red().on_white(),
        "Bold".bold(),
        "Italic".italic(),
        "Underlined".underlined(),
        "Strikethrough".crossed_out(),
    ] {
        styled_spans.push(span);
        styled_spans.push(" ".into());
    }
    vec![
        Line::raw("Unstyled Line"),
        Line::raw("Styled Line").black().on_red().bold().italic(),
        Line::from(styled_spans),
        Line::from(long_line.green().italic()),
        Line::from_iter([
            "Masked text: ".into(),
            Span::styled(Masked::new("my secret password", '*'), Color::Red),
        ]),
    ]
}
source

fn on_blue(self) -> T

Sets the background color to blue.

Examples found in repository?
examples/layout.rs (line 170)
168
169
170
171
172
173
174
175
176
177
fn render_single_example(frame: &mut Frame, area: Rect, constraints: Vec<Constraint>) {
    let red = Paragraph::new(constraint_label(constraints[0])).on_red();
    let blue = Paragraph::new(constraint_label(constraints[1])).on_blue();
    let green = Paragraph::new("·".repeat(12)).on_green();
    let horizontal = Layout::horizontal(constraints);
    let [r, b, g] = horizontal.areas(area);
    frame.render_widget(red, r);
    frame.render_widget(blue, b);
    frame.render_widget(green, g);
}
More examples
Hide additional examples
examples/popup.rs (line 74)
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
    fn draw(&self, frame: &mut Frame) {
        let area = frame.area();

        let vertical = Layout::vertical([Constraint::Percentage(20), Constraint::Percentage(80)]);
        let [instructions, content] = vertical.areas(area);

        let text = if self.show_popup {
            "Press p to close the popup"
        } else {
            "Press p to show the popup"
        };
        let paragraph = Paragraph::new(text.slow_blink())
            .centered()
            .wrap(Wrap { trim: true });
        frame.render_widget(paragraph, instructions);

        let block = Block::bordered().title("Content").on_blue();
        frame.render_widget(block, content);

        if self.show_popup {
            let block = Block::bordered().title("Popup");
            let area = popup_area(area, 60, 20);
            frame.render_widget(Clear, area); //this clears out the background
            frame.render_widget(block, area);
        }
    }
examples/async.rs (line 247)
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
    fn render(self, area: Rect, buf: &mut Buffer) {
        let mut state = self.state.write().unwrap();

        // a block with a right aligned title with the loading state on the right
        let loading_state = Line::from(format!("{:?}", state.loading_state)).right_aligned();
        let block = Block::bordered()
            .title("Pull Requests")
            .title(loading_state)
            .title_bottom("j/k to scroll, q to quit");

        // a table with the list of pull requests
        let rows = state.pull_requests.iter();
        let widths = [
            Constraint::Length(5),
            Constraint::Fill(1),
            Constraint::Max(49),
        ];
        let table = Table::new(rows, widths)
            .block(block)
            .highlight_spacing(HighlightSpacing::Always)
            .highlight_symbol(">>")
            .row_highlight_style(Style::new().on_blue());

        StatefulWidget::render(table, area, buf, &mut state.table_state);
    }
source

fn magenta(self) -> T

Sets the foreground color to magenta.

Examples found in repository?
examples/chart.rs (line 259)
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
fn render_scatter(frame: &mut Frame, area: Rect) {
    let datasets = vec![
        Dataset::default()
            .name("Heavy")
            .marker(Marker::Dot)
            .graph_type(GraphType::Scatter)
            .style(Style::new().yellow())
            .data(&HEAVY_PAYLOAD_DATA),
        Dataset::default()
            .name("Medium".underlined())
            .marker(Marker::Braille)
            .graph_type(GraphType::Scatter)
            .style(Style::new().magenta())
            .data(&MEDIUM_PAYLOAD_DATA),
        Dataset::default()
            .name("Small")
            .marker(Marker::Dot)
            .graph_type(GraphType::Scatter)
            .style(Style::new().cyan())
            .data(&SMALL_PAYLOAD_DATA),
    ];

    let chart = Chart::new(datasets)
        .block(Block::bordered().title(Line::from("Scatter chart").cyan().bold().centered()))
        .x_axis(
            Axis::default()
                .title("Year")
                .bounds([1960., 2020.])
                .style(Style::default().fg(Color::Gray))
                .labels(["1960", "1990", "2020"]),
        )
        .y_axis(
            Axis::default()
                .title("Cost")
                .bounds([0., 75000.])
                .style(Style::default().fg(Color::Gray))
                .labels(["0", "37 500", "75 000"]),
        )
        .hidden_legend_constraints((Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)));

    frame.render_widget(chart, area);
}
source

fn on_magenta(self) -> T

Sets the background color to magenta.

source

fn cyan(self) -> T

Sets the foreground color to cyan.

Examples found in repository?
examples/chart.rs (line 199)
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
fn render_barchart(frame: &mut Frame, bar_chart: Rect) {
    let dataset = Dataset::default()
        .marker(symbols::Marker::HalfBlock)
        .style(Style::new().fg(Color::Blue))
        .graph_type(GraphType::Bar)
        // a bell curve
        .data(&[
            (0., 0.4),
            (10., 2.9),
            (20., 13.5),
            (30., 41.1),
            (40., 80.1),
            (50., 100.0),
            (60., 80.1),
            (70., 41.1),
            (80., 13.5),
            (90., 2.9),
            (100., 0.4),
        ]);

    let chart = Chart::new(vec![dataset])
        .block(Block::bordered().title_top(Line::from("Bar chart").cyan().bold().centered()))
        .x_axis(
            Axis::default()
                .style(Style::default().gray())
                .bounds([0.0, 100.0])
                .labels(["0".bold(), "50".into(), "100.0".bold()]),
        )
        .y_axis(
            Axis::default()
                .style(Style::default().gray())
                .bounds([0.0, 100.0])
                .labels(["0".bold(), "50".into(), "100.0".bold()]),
        )
        .hidden_legend_constraints((Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)));

    frame.render_widget(chart, bar_chart);
}

fn render_line_chart(frame: &mut Frame, area: Rect) {
    let datasets = vec![Dataset::default()
        .name("Line from only 2 points".italic())
        .marker(symbols::Marker::Braille)
        .style(Style::default().fg(Color::Yellow))
        .graph_type(GraphType::Line)
        .data(&[(1., 1.), (4., 4.)])];

    let chart = Chart::new(datasets)
        .block(Block::bordered().title(Line::from("Line chart").cyan().bold().centered()))
        .x_axis(
            Axis::default()
                .title("X Axis")
                .style(Style::default().gray())
                .bounds([0.0, 5.0])
                .labels(["0".bold(), "2.5".into(), "5.0".bold()]),
        )
        .y_axis(
            Axis::default()
                .title("Y Axis")
                .style(Style::default().gray())
                .bounds([0.0, 5.0])
                .labels(["0".bold(), "2.5".into(), "5.0".bold()]),
        )
        .legend_position(Some(LegendPosition::TopLeft))
        .hidden_legend_constraints((Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)));

    frame.render_widget(chart, area);
}

fn render_scatter(frame: &mut Frame, area: Rect) {
    let datasets = vec![
        Dataset::default()
            .name("Heavy")
            .marker(Marker::Dot)
            .graph_type(GraphType::Scatter)
            .style(Style::new().yellow())
            .data(&HEAVY_PAYLOAD_DATA),
        Dataset::default()
            .name("Medium".underlined())
            .marker(Marker::Braille)
            .graph_type(GraphType::Scatter)
            .style(Style::new().magenta())
            .data(&MEDIUM_PAYLOAD_DATA),
        Dataset::default()
            .name("Small")
            .marker(Marker::Dot)
            .graph_type(GraphType::Scatter)
            .style(Style::new().cyan())
            .data(&SMALL_PAYLOAD_DATA),
    ];

    let chart = Chart::new(datasets)
        .block(Block::bordered().title(Line::from("Scatter chart").cyan().bold().centered()))
        .x_axis(
            Axis::default()
                .title("Year")
                .bounds([1960., 2020.])
                .style(Style::default().fg(Color::Gray))
                .labels(["1960", "1990", "2020"]),
        )
        .y_axis(
            Axis::default()
                .title("Cost")
                .bounds([0., 75000.])
                .style(Style::default().fg(Color::Gray))
                .labels(["0", "37 500", "75 000"]),
        )
        .hidden_legend_constraints((Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)));

    frame.render_widget(chart, area);
}
source

fn on_cyan(self) -> T

Sets the background color to cyan.

source

fn gray(self) -> T

Sets the foreground color to gray.

Examples found in repository?
examples/demo2/tabs/recipe.rs (line 151)
148
149
150
151
152
153
154
155
156
157
fn render_recipe(area: Rect, buf: &mut Buffer) {
    let lines = RECIPE
        .iter()
        .map(|(step, text)| Line::from(vec![step.white().bold(), text.gray()]))
        .collect_vec();
    Paragraph::new(lines)
        .wrap(Wrap { trim: true })
        .block(Block::new().padding(Padding::new(0, 1, 0, 0)))
        .render(area, buf);
}
More examples
Hide additional examples
examples/layout.rs (line 153)
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
fn render_example_combination(
    frame: &mut Frame,
    area: Rect,
    title: &str,
    constraints: impl ExactSizeIterator<Item = (Constraint, Constraint)>,
) {
    let block = Block::bordered()
        .title(title.gray())
        .style(Style::reset())
        .border_style(Style::default().fg(Color::DarkGray));
    let inner = block.inner(area);
    frame.render_widget(block, area);
    let layout = Layout::vertical(vec![Length(1); constraints.len() + 1]).split(inner);
    for ((a, b), &area) in constraints.into_iter().zip(layout.iter()) {
        render_single_example(frame, area, vec![a, b, Min(0)]);
    }
    // This is to make it easy to visually see the alignment of the examples
    // with the constraints.
    frame.render_widget(Paragraph::new("123456789012"), layout[6]);
}
examples/paragraph.rs (line 97)
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
    fn render(self, area: Rect, buf: &mut Buffer) {
        let areas = Layout::vertical([Constraint::Max(9); 4]).split(area);
        Paragraph::new(create_lines(area))
            .block(title_block("Default alignment (Left), no wrap"))
            .gray()
            .render(areas[0], buf);
        Paragraph::new(create_lines(area))
            .block(title_block("Default alignment (Left), with wrap"))
            .gray()
            .wrap(Wrap { trim: true })
            .render(areas[1], buf);
        Paragraph::new(create_lines(area))
            .block(title_block("Right alignment, with wrap"))
            .gray()
            .right_aligned()
            .wrap(Wrap { trim: true })
            .render(areas[2], buf);
        Paragraph::new(create_lines(area))
            .block(title_block("Center alignment, with wrap, with scroll"))
            .gray()
            .centered()
            .wrap(Wrap { trim: true })
            .scroll((self.scroll, 0))
            .render(areas[3], buf);
    }
}

/// Create a bordered block with a title.
fn title_block(title: &str) -> Block {
    Block::bordered()
        .gray()
        .title(title.bold().into_centered_line())
}
examples/chart.rs (line 202)
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
fn render_barchart(frame: &mut Frame, bar_chart: Rect) {
    let dataset = Dataset::default()
        .marker(symbols::Marker::HalfBlock)
        .style(Style::new().fg(Color::Blue))
        .graph_type(GraphType::Bar)
        // a bell curve
        .data(&[
            (0., 0.4),
            (10., 2.9),
            (20., 13.5),
            (30., 41.1),
            (40., 80.1),
            (50., 100.0),
            (60., 80.1),
            (70., 41.1),
            (80., 13.5),
            (90., 2.9),
            (100., 0.4),
        ]);

    let chart = Chart::new(vec![dataset])
        .block(Block::bordered().title_top(Line::from("Bar chart").cyan().bold().centered()))
        .x_axis(
            Axis::default()
                .style(Style::default().gray())
                .bounds([0.0, 100.0])
                .labels(["0".bold(), "50".into(), "100.0".bold()]),
        )
        .y_axis(
            Axis::default()
                .style(Style::default().gray())
                .bounds([0.0, 100.0])
                .labels(["0".bold(), "50".into(), "100.0".bold()]),
        )
        .hidden_legend_constraints((Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)));

    frame.render_widget(chart, bar_chart);
}

fn render_line_chart(frame: &mut Frame, area: Rect) {
    let datasets = vec![Dataset::default()
        .name("Line from only 2 points".italic())
        .marker(symbols::Marker::Braille)
        .style(Style::default().fg(Color::Yellow))
        .graph_type(GraphType::Line)
        .data(&[(1., 1.), (4., 4.)])];

    let chart = Chart::new(datasets)
        .block(Block::bordered().title(Line::from("Line chart").cyan().bold().centered()))
        .x_axis(
            Axis::default()
                .title("X Axis")
                .style(Style::default().gray())
                .bounds([0.0, 5.0])
                .labels(["0".bold(), "2.5".into(), "5.0".bold()]),
        )
        .y_axis(
            Axis::default()
                .title("Y Axis")
                .style(Style::default().gray())
                .bounds([0.0, 5.0])
                .labels(["0".bold(), "2.5".into(), "5.0".bold()]),
        )
        .legend_position(Some(LegendPosition::TopLeft))
        .hidden_legend_constraints((Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)));

    frame.render_widget(chart, area);
}
examples/scrollbar.rs (line 135)
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
    fn draw(&mut self, frame: &mut Frame) {
        let area = frame.area();

        // Words made "loooong" to demonstrate line breaking.
        let s =
            "Veeeeeeeeeeeeeeeery    loooooooooooooooooong   striiiiiiiiiiiiiiiiiiiiiiiiiing.   ";
        let mut long_line = s.repeat(usize::from(area.width) / s.len() + 4);
        long_line.push('\n');

        let chunks = Layout::vertical([
            Constraint::Min(1),
            Constraint::Percentage(25),
            Constraint::Percentage(25),
            Constraint::Percentage(25),
            Constraint::Percentage(25),
        ])
        .split(area);

        let text = vec![
            Line::from("This is a line "),
            Line::from("This is a line   ".red()),
            Line::from("This is a line".on_dark_gray()),
            Line::from("This is a longer line".crossed_out()),
            Line::from(long_line.clone()),
            Line::from("This is a line".reset()),
            Line::from(vec![
                Span::raw("Masked text: "),
                Span::styled(Masked::new("password", '*'), Style::new().fg(Color::Red)),
            ]),
            Line::from("This is a line "),
            Line::from("This is a line   ".red()),
            Line::from("This is a line".on_dark_gray()),
            Line::from("This is a longer line".crossed_out()),
            Line::from(long_line.clone()),
            Line::from("This is a line".reset()),
            Line::from(vec![
                Span::raw("Masked text: "),
                Span::styled(Masked::new("password", '*'), Style::new().fg(Color::Red)),
            ]),
        ];
        self.vertical_scroll_state = self.vertical_scroll_state.content_length(text.len());
        self.horizontal_scroll_state = self.horizontal_scroll_state.content_length(long_line.len());

        let create_block = |title: &'static str| Block::bordered().gray().title(title.bold());

        let title = Block::new()
            .title_alignment(Alignment::Center)
            .title("Use h j k l or ◄ ▲ ▼ ► to scroll ".bold());
        frame.render_widget(title, chunks[0]);

        let paragraph = Paragraph::new(text.clone())
            .gray()
            .block(create_block("Vertical scrollbar with arrows"))
            .scroll((self.vertical_scroll as u16, 0));
        frame.render_widget(paragraph, chunks[1]);
        frame.render_stateful_widget(
            Scrollbar::new(ScrollbarOrientation::VerticalRight)
                .begin_symbol(Some("↑"))
                .end_symbol(Some("↓")),
            chunks[1],
            &mut self.vertical_scroll_state,
        );

        let paragraph = Paragraph::new(text.clone())
            .gray()
            .block(create_block(
                "Vertical scrollbar without arrows, without track symbol and mirrored",
            ))
            .scroll((self.vertical_scroll as u16, 0));
        frame.render_widget(paragraph, chunks[2]);
        frame.render_stateful_widget(
            Scrollbar::new(ScrollbarOrientation::VerticalLeft)
                .symbols(scrollbar::VERTICAL)
                .begin_symbol(None)
                .track_symbol(None)
                .end_symbol(None),
            chunks[2].inner(Margin {
                vertical: 1,
                horizontal: 0,
            }),
            &mut self.vertical_scroll_state,
        );

        let paragraph = Paragraph::new(text.clone())
            .gray()
            .block(create_block(
                "Horizontal scrollbar with only begin arrow & custom thumb symbol",
            ))
            .scroll((0, self.horizontal_scroll as u16));
        frame.render_widget(paragraph, chunks[3]);
        frame.render_stateful_widget(
            Scrollbar::new(ScrollbarOrientation::HorizontalBottom)
                .thumb_symbol("🬋")
                .end_symbol(None),
            chunks[3].inner(Margin {
                vertical: 0,
                horizontal: 1,
            }),
            &mut self.horizontal_scroll_state,
        );

        let paragraph = Paragraph::new(text.clone())
            .gray()
            .block(create_block(
                "Horizontal scrollbar without arrows & custom thumb and track symbol",
            ))
            .scroll((0, self.horizontal_scroll as u16));
        frame.render_widget(paragraph, chunks[4]);
        frame.render_stateful_widget(
            Scrollbar::new(ScrollbarOrientation::HorizontalBottom)
                .thumb_symbol("░")
                .track_symbol(Some("─")),
            chunks[4].inner(Margin {
                vertical: 0,
                horizontal: 1,
            }),
            &mut self.horizontal_scroll_state,
        );
    }
source

fn on_gray(self) -> T

Sets the background color to gray.

source

fn dark_gray(self) -> T

Sets the foreground color to dark_gray.

Examples found in repository?
examples/block.rs (line 96)
93
94
95
96
97
98
99
100
101
102
103
104
105
fn render_title(frame: &mut Frame, area: Rect) {
    frame.render_widget(
        Paragraph::new("Block example. Press q to quit")
            .dark_gray()
            .alignment(Alignment::Center),
        area,
    );
}

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 })
}
More examples
Hide additional examples
examples/flex.rs (line 297)
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
    fn axis(width: u16, spacing: u16) -> impl Widget {
        let width = width as usize;
        // only show gap when spacing is not zero
        let label = if spacing != 0 {
            format!("{width} px (gap: {spacing} px)")
        } else {
            format!("{width} px")
        };
        let bar_width = width.saturating_sub(2); // we want to `<` and `>` at the ends
        let width_bar = format!("<{label:-^bar_width$}>");
        Paragraph::new(width_bar.dark_gray()).centered()
    }

    /// Render the demo content
    ///
    /// This function renders the demo content into a separate buffer and then splices the buffer
    /// into the main buffer. This is done to make it possible to handle scrolling easily.
    ///
    /// Returns bool indicating whether scroll was needed
    #[allow(clippy::cast_possible_truncation)]
    fn render_demo(self, area: Rect, buf: &mut Buffer) -> bool {
        // render demo content into a separate buffer so all examples fit we add an extra
        // area.height to make sure the last example is fully visible even when the scroll offset is
        // at the max
        let height = example_height();
        let demo_area = Rect::new(0, 0, area.width, height);
        let mut demo_buf = Buffer::empty(demo_area);

        let scrollbar_needed = self.scroll_offset != 0 || height > area.height;
        let content_area = if scrollbar_needed {
            Rect {
                width: demo_area.width - 1,
                ..demo_area
            }
        } else {
            demo_area
        };

        let mut spacing = self.spacing;
        self.selected_tab
            .render(content_area, &mut demo_buf, &mut spacing);

        let visible_content = demo_buf
            .content
            .into_iter()
            .skip((area.width * self.scroll_offset) as usize)
            .take(area.area() as usize);
        for (i, cell) in visible_content.enumerate() {
            let x = i as u16 % area.width;
            let y = i as u16 / area.width;
            buf[(area.x + x, area.y + y)] = cell;
        }

        if scrollbar_needed {
            let area = area.intersection(buf.area);
            let mut state = ScrollbarState::new(max_scroll_offset() as usize)
                .position(self.scroll_offset as usize);
            Scrollbar::new(ScrollbarOrientation::VerticalRight).render(area, buf, &mut state);
        }
        scrollbar_needed
    }
}

impl SelectedTab {
    /// Get the previous tab, if there is no previous tab return the current tab.
    fn previous(self) -> Self {
        let current_index: usize = self as usize;
        let previous_index = current_index.saturating_sub(1);
        Self::from_repr(previous_index).unwrap_or(self)
    }

    /// Get the next tab, if there is no next tab return the current tab.
    fn next(self) -> Self {
        let current_index = self as usize;
        let next_index = current_index.saturating_add(1);
        Self::from_repr(next_index).unwrap_or(self)
    }

    /// Convert a `SelectedTab` into a `Line` to display it by the `Tabs` widget.
    fn to_tab_title(value: Self) -> Line<'static> {
        use tailwind::{INDIGO, ORANGE, SKY};
        let text = value.to_string();
        let color = match value {
            Self::Legacy => ORANGE.c400,
            Self::Start => SKY.c400,
            Self::Center => SKY.c300,
            Self::End => SKY.c200,
            Self::SpaceAround => INDIGO.c400,
            Self::SpaceBetween => INDIGO.c300,
        };
        format!(" {text} ").fg(color).bg(Color::Black).into()
    }
}

impl StatefulWidget for SelectedTab {
    type State = u16;
    fn render(self, area: Rect, buf: &mut Buffer, spacing: &mut Self::State) {
        let spacing = *spacing;
        match self {
            Self::Legacy => Self::render_examples(area, buf, Flex::Legacy, spacing),
            Self::Start => Self::render_examples(area, buf, Flex::Start, spacing),
            Self::Center => Self::render_examples(area, buf, Flex::Center, spacing),
            Self::End => Self::render_examples(area, buf, Flex::End, spacing),
            Self::SpaceAround => Self::render_examples(area, buf, Flex::SpaceAround, spacing),
            Self::SpaceBetween => Self::render_examples(area, buf, Flex::SpaceBetween, spacing),
        }
    }
}

impl SelectedTab {
    fn render_examples(area: Rect, buf: &mut Buffer, flex: Flex, spacing: u16) {
        let heights = EXAMPLE_DATA
            .iter()
            .map(|(desc, _)| get_description_height(desc) + 4);
        let areas = Layout::vertical(heights).flex(Flex::Start).split(area);
        for (area, (description, constraints)) in areas.iter().zip(EXAMPLE_DATA.iter()) {
            Example::new(constraints, description, flex, spacing).render(*area, buf);
        }
    }
}

impl Example {
    fn new(constraints: &[Constraint], description: &str, flex: Flex, spacing: u16) -> Self {
        Self {
            constraints: constraints.into(),
            description: description.into(),
            flex,
            spacing,
        }
    }
}

impl Widget for Example {
    fn render(self, area: Rect, buf: &mut Buffer) {
        let title_height = get_description_height(&self.description);
        let layout = Layout::vertical([Length(title_height), Fill(0)]);
        let [title, illustrations] = layout.areas(area);

        let (blocks, spacers) = Layout::horizontal(&self.constraints)
            .flex(self.flex)
            .spacing(self.spacing)
            .split_with_spacers(illustrations);

        if !self.description.is_empty() {
            Paragraph::new(
                self.description
                    .split('\n')
                    .map(|s| format!("// {s}").italic().fg(tailwind::SLATE.c400))
                    .map(Line::from)
                    .collect::<Vec<Line>>(),
            )
            .render(title, buf);
        }

        for (block, constraint) in blocks.iter().zip(&self.constraints) {
            Self::illustration(*constraint, block.width).render(*block, buf);
        }

        for spacer in spacers.iter() {
            Self::render_spacer(*spacer, buf);
        }
    }
}

impl Example {
    fn render_spacer(spacer: Rect, buf: &mut Buffer) {
        if spacer.width > 1 {
            let corners_only = symbols::border::Set {
                top_left: line::NORMAL.top_left,
                top_right: line::NORMAL.top_right,
                bottom_left: line::NORMAL.bottom_left,
                bottom_right: line::NORMAL.bottom_right,
                vertical_left: " ",
                vertical_right: " ",
                horizontal_top: " ",
                horizontal_bottom: " ",
            };
            Block::bordered()
                .border_set(corners_only)
                .border_style(Style::reset().dark_gray())
                .render(spacer, buf);
        } else {
            Paragraph::new(Text::from(vec![
                Line::from(""),
                Line::from("│"),
                Line::from("│"),
                Line::from(""),
            ]))
            .style(Style::reset().dark_gray())
            .render(spacer, buf);
        }
        let width = spacer.width;
        let label = if width > 4 {
            format!("{width} px")
        } else if width > 2 {
            format!("{width}")
        } else {
            String::new()
        };
        let text = Text::from(vec![
            Line::raw(""),
            Line::raw(""),
            Line::styled(label, Style::reset().dark_gray()),
        ]);
        Paragraph::new(text)
            .style(Style::reset().dark_gray())
            .alignment(Alignment::Center)
            .render(spacer, buf);
    }
examples/layout.rs (line 60)
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
fn draw(frame: &mut Frame) {
    let vertical = Layout::vertical([
        Length(4),  // text
        Length(50), // examples
        Min(0),     // fills remaining space
    ]);
    let [text_area, examples_area, _] = vertical.areas(frame.area());

    // title
    frame.render_widget(
        Paragraph::new(vec![
            Line::from("Horizontal Layout Example. Press q to quit".dark_gray()).centered(),
            Line::from("Each line has 2 constraints, plus Min(0) to fill the remaining space."),
            Line::from("E.g. the second line of the Len/Min box is [Length(2), Min(2), Min(0)]"),
            Line::from("Note: constraint labels that don't fit are truncated"),
        ]),
        text_area,
    );

    let example_rows = Layout::vertical([
        Length(9),
        Length(9),
        Length(9),
        Length(9),
        Length(9),
        Min(0), // fills remaining space
    ])
    .split(examples_area);
    let example_areas = example_rows.iter().flat_map(|area| {
        Layout::horizontal([
            Length(14),
            Length(14),
            Length(14),
            Length(14),
            Length(14),
            Min(0), // fills remaining space
        ])
        .split(*area)
        .iter()
        .copied()
        .take(5) // ignore Min(0)
        .collect_vec()
    });

    // the examples are a cartesian product of the following constraints
    // e.g. Len/Len, Len/Min, Len/Max, Len/Perc, Len/Ratio, Min/Len, Min/Min, ...
    let examples = [
        (
            "Len",
            [
                Length(0),
                Length(2),
                Length(3),
                Length(6),
                Length(10),
                Length(15),
            ],
        ),
        ("Min", [Min(0), Min(2), Min(3), Min(6), Min(10), Min(15)]),
        ("Max", [Max(0), Max(2), Max(3), Max(6), Max(10), Max(15)]),
        (
            "Perc",
            [
                Percentage(0),
                Percentage(25),
                Percentage(50),
                Percentage(75),
                Percentage(100),
                Percentage(150),
            ],
        ),
        (
            "Ratio",
            [
                Ratio(0, 4),
                Ratio(1, 4),
                Ratio(2, 4),
                Ratio(3, 4),
                Ratio(4, 4),
                Ratio(6, 4),
            ],
        ),
    ];

    for ((a, b), area) in examples
        .iter()
        .cartesian_product(examples.iter())
        .zip(example_areas)
    {
        let (name_a, examples_a) = a;
        let (name_b, examples_b) = b;
        let constraints = examples_a.iter().copied().zip(examples_b.iter().copied());
        render_example_combination(frame, area, &format!("{name_a}/{name_b}"), constraints);
    }
}
source

fn on_dark_gray(self) -> T

Sets the background color to dark_gray.

Examples found in repository?
examples/scrollbar.rs (line 113)
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
    fn draw(&mut self, frame: &mut Frame) {
        let area = frame.area();

        // Words made "loooong" to demonstrate line breaking.
        let s =
            "Veeeeeeeeeeeeeeeery    loooooooooooooooooong   striiiiiiiiiiiiiiiiiiiiiiiiiing.   ";
        let mut long_line = s.repeat(usize::from(area.width) / s.len() + 4);
        long_line.push('\n');

        let chunks = Layout::vertical([
            Constraint::Min(1),
            Constraint::Percentage(25),
            Constraint::Percentage(25),
            Constraint::Percentage(25),
            Constraint::Percentage(25),
        ])
        .split(area);

        let text = vec![
            Line::from("This is a line "),
            Line::from("This is a line   ".red()),
            Line::from("This is a line".on_dark_gray()),
            Line::from("This is a longer line".crossed_out()),
            Line::from(long_line.clone()),
            Line::from("This is a line".reset()),
            Line::from(vec![
                Span::raw("Masked text: "),
                Span::styled(Masked::new("password", '*'), Style::new().fg(Color::Red)),
            ]),
            Line::from("This is a line "),
            Line::from("This is a line   ".red()),
            Line::from("This is a line".on_dark_gray()),
            Line::from("This is a longer line".crossed_out()),
            Line::from(long_line.clone()),
            Line::from("This is a line".reset()),
            Line::from(vec![
                Span::raw("Masked text: "),
                Span::styled(Masked::new("password", '*'), Style::new().fg(Color::Red)),
            ]),
        ];
        self.vertical_scroll_state = self.vertical_scroll_state.content_length(text.len());
        self.horizontal_scroll_state = self.horizontal_scroll_state.content_length(long_line.len());

        let create_block = |title: &'static str| Block::bordered().gray().title(title.bold());

        let title = Block::new()
            .title_alignment(Alignment::Center)
            .title("Use h j k l or ◄ ▲ ▼ ► to scroll ".bold());
        frame.render_widget(title, chunks[0]);

        let paragraph = Paragraph::new(text.clone())
            .gray()
            .block(create_block("Vertical scrollbar with arrows"))
            .scroll((self.vertical_scroll as u16, 0));
        frame.render_widget(paragraph, chunks[1]);
        frame.render_stateful_widget(
            Scrollbar::new(ScrollbarOrientation::VerticalRight)
                .begin_symbol(Some("↑"))
                .end_symbol(Some("↓")),
            chunks[1],
            &mut self.vertical_scroll_state,
        );

        let paragraph = Paragraph::new(text.clone())
            .gray()
            .block(create_block(
                "Vertical scrollbar without arrows, without track symbol and mirrored",
            ))
            .scroll((self.vertical_scroll as u16, 0));
        frame.render_widget(paragraph, chunks[2]);
        frame.render_stateful_widget(
            Scrollbar::new(ScrollbarOrientation::VerticalLeft)
                .symbols(scrollbar::VERTICAL)
                .begin_symbol(None)
                .track_symbol(None)
                .end_symbol(None),
            chunks[2].inner(Margin {
                vertical: 1,
                horizontal: 0,
            }),
            &mut self.vertical_scroll_state,
        );

        let paragraph = Paragraph::new(text.clone())
            .gray()
            .block(create_block(
                "Horizontal scrollbar with only begin arrow & custom thumb symbol",
            ))
            .scroll((0, self.horizontal_scroll as u16));
        frame.render_widget(paragraph, chunks[3]);
        frame.render_stateful_widget(
            Scrollbar::new(ScrollbarOrientation::HorizontalBottom)
                .thumb_symbol("🬋")
                .end_symbol(None),
            chunks[3].inner(Margin {
                vertical: 0,
                horizontal: 1,
            }),
            &mut self.horizontal_scroll_state,
        );

        let paragraph = Paragraph::new(text.clone())
            .gray()
            .block(create_block(
                "Horizontal scrollbar without arrows & custom thumb and track symbol",
            ))
            .scroll((0, self.horizontal_scroll as u16));
        frame.render_widget(paragraph, chunks[4]);
        frame.render_stateful_widget(
            Scrollbar::new(ScrollbarOrientation::HorizontalBottom)
                .thumb_symbol("░")
                .track_symbol(Some("─")),
            chunks[4].inner(Margin {
                vertical: 0,
                horizontal: 1,
            }),
            &mut self.horizontal_scroll_state,
        );
    }
source

fn light_red(self) -> T

Sets the foreground color to light_red.

source

fn on_light_red(self) -> T

Sets the background color to light_red.

source

fn light_green(self) -> T

Sets the foreground color to light_green.

source

fn on_light_green(self) -> T

Sets the background color to light_green.

source

fn light_yellow(self) -> T

Sets the foreground color to light_yellow.

Examples found in repository?
examples/demo2/tabs/recipe.rs (line 167)
159
160
161
162
163
164
165
166
167
168
169
170
171
172
fn render_ingredients(selected_row: usize, area: Rect, buf: &mut Buffer) {
    let mut state = TableState::default().with_selected(Some(selected_row));
    let rows = INGREDIENTS.iter().copied();
    let theme = THEME.recipe;
    StatefulWidget::render(
        Table::new(rows, [Constraint::Length(7), Constraint::Length(30)])
            .block(Block::new().style(theme.ingredients))
            .header(Row::new(vec!["Qty", "Ingredient"]).style(theme.ingredients_header))
            .row_highlight_style(Style::new().light_yellow()),
        area,
        buf,
        &mut state,
    );
}
source

fn on_light_yellow(self) -> T

Sets the background color to light_yellow.

source

fn light_blue(self) -> T

Sets the foreground color to light_blue.

Examples found in repository?
examples/demo2/tabs/weather.rs (line 159)
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
fn render_line_gauge(percent: f64, area: Rect, buf: &mut Buffer) {
    // cycle color hue based on the percent for a neat effect yellow -> red
    let hue = 90.0 - (percent as f32 * 0.6);
    let value = Okhsv::max_value();
    let filled_color = color_from_oklab(hue, Okhsv::max_saturation(), value);
    let unfilled_color = color_from_oklab(hue, Okhsv::max_saturation(), value * 0.5);
    let label = if percent < 100.0 {
        format!("Downloading: {percent}%")
    } else {
        "Download Complete!".into()
    };
    LineGauge::default()
        .ratio(percent / 100.0)
        .label(label)
        .style(Style::new().light_blue())
        .filled_style(Style::new().fg(filled_color))
        .unfilled_style(Style::new().fg(unfilled_color))
        .line_set(symbols::line::THICK)
        .render(area, buf);
}
source

fn on_light_blue(self) -> T

Sets the background color to light_blue.

source

fn light_magenta(self) -> T

Sets the foreground color to light_magenta.

source

fn on_light_magenta(self) -> T

Sets the background color to light_magenta.

source

fn light_cyan(self) -> T

Sets the foreground color to light_cyan.

source

fn on_light_cyan(self) -> T

Sets the background color to light_cyan.

source

fn white(self) -> T

Sets the foreground color to white.

Examples found in repository?
examples/demo2/tabs/recipe.rs (line 123)
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    fn render(self, area: Rect, buf: &mut Buffer) {
        RgbSwatch.render(area, buf);
        let area = area.inner(Margin {
            vertical: 1,
            horizontal: 2,
        });
        Clear.render(area, buf);
        Block::new()
            .title("Ratatouille Recipe".bold().white())
            .title_alignment(Alignment::Center)
            .style(THEME.content)
            .padding(Padding::new(1, 1, 2, 1))
            .render(area, buf);

        let scrollbar_area = Rect {
            y: area.y + 2,
            height: area.height - 3,
            ..area
        };
        render_scrollbar(self.row_index, scrollbar_area, buf);

        let area = area.inner(Margin {
            horizontal: 2,
            vertical: 1,
        });
        let [recipe, ingredients] =
            Layout::horizontal([Constraint::Length(44), Constraint::Min(0)]).areas(area);

        render_recipe(recipe, buf);
        render_ingredients(self.row_index, ingredients, buf);
    }
}

fn render_recipe(area: Rect, buf: &mut Buffer) {
    let lines = RECIPE
        .iter()
        .map(|(step, text)| Line::from(vec![step.white().bold(), text.gray()]))
        .collect_vec();
    Paragraph::new(lines)
        .wrap(Wrap { trim: true })
        .block(Block::new().padding(Padding::new(0, 1, 0, 0)))
        .render(area, buf);
}
More examples
Hide additional examples
examples/demo2/tabs/traceroute.rs (line 59)
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
fn render_hops(selected_row: usize, area: Rect, buf: &mut Buffer) {
    let mut state = TableState::default().with_selected(Some(selected_row));
    let rows = HOPS.iter().map(|hop| Row::new(vec![hop.host, hop.address]));
    let block = Block::new()
        .padding(Padding::new(1, 1, 1, 1))
        .title_alignment(Alignment::Center)
        .title("Traceroute bad.horse".bold().white());
    StatefulWidget::render(
        Table::new(rows, [Constraint::Max(100), Constraint::Length(15)])
            .header(Row::new(vec!["Host", "Address"]).set_style(THEME.traceroute.header))
            .row_highlight_style(THEME.traceroute.selected)
            .block(block),
        area,
        buf,
        &mut state,
    );
    let mut scrollbar_state = ScrollbarState::default()
        .content_length(HOPS.len())
        .position(selected_row);
    let area = Rect {
        width: area.width + 1,
        y: area.y + 3,
        height: area.height - 4,
        ..area
    };
    Scrollbar::default()
        .orientation(ScrollbarOrientation::VerticalLeft)
        .begin_symbol(None)
        .end_symbol(None)
        .track_symbol(None)
        .thumb_symbol("▌")
        .render(area, buf, &mut scrollbar_state);
}
source

fn on_white(self) -> T

Sets the background color to white.

Examples found in repository?
examples/block.rs (line 127)
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
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())
        .title("Styled block");
    frame.render_widget(paragraph.clone().block(block), area);
}

fn render_styled_title(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
    let block = Block::bordered()
        .title("Styled title")
        .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);
}
More examples
Hide additional examples
examples/paragraph.rs (line 134)
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
fn create_lines(area: Rect) -> Vec<Line<'static>> {
    let short_line = "A long line to demonstrate line wrapping. ";
    let long_line = short_line.repeat(usize::from(area.width) / short_line.len() + 4);
    let mut styled_spans = vec![];
    for span in [
        "Styled".blue(),
        "Spans".red().on_white(),
        "Bold".bold(),
        "Italic".italic(),
        "Underlined".underlined(),
        "Strikethrough".crossed_out(),
    ] {
        styled_spans.push(span);
        styled_spans.push(" ".into());
    }
    vec![
        Line::raw("Unstyled Line"),
        Line::raw("Styled Line").black().on_red().bold().italic(),
        Line::from(styled_spans),
        Line::from(long_line.green().italic()),
        Line::from_iter([
            "Masked text: ".into(),
            Span::styled(Masked::new("my secret password", '*'), Color::Red),
        ]),
    ]
}
source

fn bold(self) -> T

Adds the BOLD modifier.

Examples found in repository?
examples/tabs.rs (line 146)
145
146
147
fn render_title(area: Rect, buf: &mut Buffer) {
    "Ratatui Tabs Example".bold().render(area, buf);
}
More examples
Hide additional examples
examples/paragraph.rs (line 124)
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
fn title_block(title: &str) -> Block {
    Block::bordered()
        .gray()
        .title(title.bold().into_centered_line())
}

/// Create some lines to display in the paragraph.
fn create_lines(area: Rect) -> Vec<Line<'static>> {
    let short_line = "A long line to demonstrate line wrapping. ";
    let long_line = short_line.repeat(usize::from(area.width) / short_line.len() + 4);
    let mut styled_spans = vec![];
    for span in [
        "Styled".blue(),
        "Spans".red().on_white(),
        "Bold".bold(),
        "Italic".italic(),
        "Underlined".underlined(),
        "Strikethrough".crossed_out(),
    ] {
        styled_spans.push(span);
        styled_spans.push(" ".into());
    }
    vec![
        Line::raw("Unstyled Line"),
        Line::raw("Styled Line").black().on_red().bold().italic(),
        Line::from(styled_spans),
        Line::from(long_line.green().italic()),
        Line::from_iter([
            "Masked text: ".into(),
            Span::styled(Masked::new("my secret password", '*'), Color::Red),
        ]),
    ]
}
examples/constraint-explorer.rs (line 279)
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
    fn header() -> impl Widget {
        let text = "Constraint Explorer";
        text.bold().fg(Self::HEADER_COLOR).into_centered_line()
    }

    fn instructions() -> impl Widget {
        let text = "◄ ►: select, ▲ ▼: edit, 1-6: swap, a: add, x: delete, q: quit, + -: spacing";
        Paragraph::new(text)
            .fg(Self::TEXT_COLOR)
            .centered()
            .wrap(Wrap { trim: false })
    }

    fn swap_legend() -> impl Widget {
        #[allow(unstable_name_collisions)]
        Paragraph::new(
            Line::from(
                [
                    ConstraintName::Min,
                    ConstraintName::Max,
                    ConstraintName::Length,
                    ConstraintName::Percentage,
                    ConstraintName::Ratio,
                    ConstraintName::Fill,
                ]
                .iter()
                .enumerate()
                .map(|(i, name)| {
                    format!("  {i}: {name}  ", i = i + 1)
                        .fg(SLATE.c200)
                        .bg(name.color())
                })
                .intersperse(Span::from(" "))
                .collect_vec(),
            )
            .centered(),
        )
        .wrap(Wrap { trim: false })
    }

    /// A bar like `<----- 80 px (gap: 2 px) ----->`
    ///
    /// Only shows the gap when spacing is not zero
    fn axis(&self, width: u16) -> impl Widget {
        let label = if self.spacing != 0 {
            format!("{} px (gap: {} px)", width, self.spacing)
        } else {
            format!("{width} px")
        };
        let bar_width = width.saturating_sub(2) as usize; // we want to `<` and `>` at the ends
        let width_bar = format!("<{label:-^bar_width$}>");
        Paragraph::new(width_bar).fg(Self::AXIS_COLOR).centered()
    }

    fn render_layout_blocks(&self, area: Rect, buf: &mut Buffer) {
        let [user_constraints, area] = Layout::vertical([Length(3), Fill(1)])
            .spacing(1)
            .areas(area);

        self.render_user_constraints_legend(user_constraints, buf);

        let [start, center, end, space_around, space_between] =
            Layout::vertical([Length(7); 5]).areas(area);

        self.render_layout_block(Flex::Start, start, buf);
        self.render_layout_block(Flex::Center, center, buf);
        self.render_layout_block(Flex::End, end, buf);
        self.render_layout_block(Flex::SpaceAround, space_around, buf);
        self.render_layout_block(Flex::SpaceBetween, space_between, buf);
    }

    fn render_user_constraints_legend(&self, area: Rect, buf: &mut Buffer) {
        let constraints = self.constraints.iter().map(|_| Constraint::Fill(1));
        let blocks = Layout::horizontal(constraints).split(area);

        for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
            let selected = self.selected_index == i;
            ConstraintBlock::new(*constraint, selected, true).render(*area, buf);
        }
    }

    fn render_layout_block(&self, flex: Flex, area: Rect, buf: &mut Buffer) {
        let [label_area, axis_area, blocks_area] =
            Layout::vertical([Length(1), Max(1), Length(4)]).areas(area);

        if label_area.height > 0 {
            format!("Flex::{flex:?}").bold().render(label_area, buf);
        }

        self.axis(area.width).render(axis_area, buf);

        let (blocks, spacers) = Layout::horizontal(&self.constraints)
            .flex(flex)
            .spacing(self.spacing)
            .split_with_spacers(blocks_area);

        for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
            let selected = self.selected_index == i;
            ConstraintBlock::new(*constraint, selected, false).render(*area, buf);
        }

        for area in spacers.iter() {
            SpacerBlock.render(*area, buf);
        }
    }
examples/line_gauge.rs (line 118)
116
117
118
119
120
121
122
123
124
125
126
127
128
fn header() -> impl Widget {
    Paragraph::new("Ratatui Line Gauge Example")
        .bold()
        .alignment(Alignment::Center)
        .fg(CUSTOM_LABEL_COLOR)
}

fn footer() -> impl Widget {
    Paragraph::new("Press ENTER / SPACE to start")
        .alignment(Alignment::Center)
        .fg(CUSTOM_LABEL_COLOR)
        .bold()
}
examples/list.rs (line 197)
195
196
197
198
199
200
    fn render_header(area: Rect, buf: &mut Buffer) {
        Paragraph::new("Ratatui List Example")
            .bold()
            .centered()
            .render(area, buf);
    }
examples/gauge.rs (line 136)
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
fn render_header(area: Rect, buf: &mut Buffer) {
    Paragraph::new("Ratatui Gauge Example")
        .bold()
        .alignment(Alignment::Center)
        .fg(CUSTOM_LABEL_COLOR)
        .render(area, buf);
}

fn render_footer(area: Rect, buf: &mut Buffer) {
    Paragraph::new("Press ENTER to start")
        .alignment(Alignment::Center)
        .fg(CUSTOM_LABEL_COLOR)
        .bold()
        .render(area, buf);
}

impl App {
    fn render_gauge1(&self, area: Rect, buf: &mut Buffer) {
        let title = title_block("Gauge with percentage");
        Gauge::default()
            .block(title)
            .gauge_style(GAUGE1_COLOR)
            .percent(self.progress1)
            .render(area, buf);
    }

    fn render_gauge2(&self, area: Rect, buf: &mut Buffer) {
        let title = title_block("Gauge with ratio and custom label");
        let label = Span::styled(
            format!("{:.1}/100", self.progress2),
            Style::new().italic().bold().fg(CUSTOM_LABEL_COLOR),
        );
        Gauge::default()
            .block(title)
            .gauge_style(GAUGE2_COLOR)
            .ratio(self.progress2 / 100.0)
            .label(label)
            .render(area, buf);
    }
source

fn not_bold(self) -> T

Removes the BOLD modifier.

source

fn dim(self) -> T

Adds the DIM modifier.

Examples found in repository?
examples/demo2/tabs/email.rs (line 146)
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
fn render_email(selected_index: usize, area: Rect, buf: &mut Buffer) {
    let theme = THEME.email;
    let email = EMAILS.get(selected_index);
    let block = Block::new()
        .style(theme.body)
        .padding(Padding::new(2, 2, 0, 0))
        .borders(Borders::TOP)
        .border_type(BorderType::Thick);
    let inner = block.inner(area);
    block.render(area, buf);
    if let Some(email) = email {
        let vertical = Layout::vertical([Constraint::Length(3), Constraint::Min(0)]);
        let [headers_area, body_area] = vertical.areas(inner);
        let headers = vec![
            Line::from(vec![
                "From: ".set_style(theme.header),
                email.from.set_style(theme.header_value),
            ]),
            Line::from(vec![
                "Subject: ".set_style(theme.header),
                email.subject.set_style(theme.header_value),
            ]),
            "-".repeat(inner.width as usize).dim().into(),
        ];
        Paragraph::new(headers)
            .style(theme.body)
            .render(headers_area, buf);
        let body = email.body.lines().map(Line::from).collect_vec();
        Paragraph::new(body)
            .style(theme.body)
            .render(body_area, buf);
    } else {
        Paragraph::new("No email selected").render(inner, buf);
    }
}
source

fn not_dim(self) -> T

Removes the DIM modifier.

source

fn italic(self) -> T

Adds the ITALIC modifier.

Examples found in repository?
examples/block.rs (line 127)
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
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())
        .title("Styled block");
    frame.render_widget(paragraph.clone().block(block), area);
}

fn render_styled_title(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
    let block = Block::bordered()
        .title("Styled title")
        .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);
}
More examples
Hide additional examples
examples/demo2/tabs/weather.rs (line 71)
66
67
68
69
70
71
72
73
fn render_calendar(area: Rect, buf: &mut Buffer) {
    let date = OffsetDateTime::now_utc().date();
    Monthly::new(date, CalendarEventStore::today(Style::new().red().bold()))
        .block(Block::new().padding(Padding::new(0, 0, 2, 0)))
        .show_month_header(Style::new().bold())
        .show_weekdays_header(Style::new().italic())
        .render(area, buf);
}
examples/gauge.rs (line 164)
160
161
162
163
164
165
166
167
168
169
170
171
172
    fn render_gauge2(&self, area: Rect, buf: &mut Buffer) {
        let title = title_block("Gauge with ratio and custom label");
        let label = Span::styled(
            format!("{:.1}/100", self.progress2),
            Style::new().italic().bold().fg(CUSTOM_LABEL_COLOR),
        );
        Gauge::default()
            .block(title)
            .gauge_style(GAUGE2_COLOR)
            .ratio(self.progress2 / 100.0)
            .label(label)
            .render(area, buf);
    }
examples/paragraph.rs (line 136)
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
fn create_lines(area: Rect) -> Vec<Line<'static>> {
    let short_line = "A long line to demonstrate line wrapping. ";
    let long_line = short_line.repeat(usize::from(area.width) / short_line.len() + 4);
    let mut styled_spans = vec![];
    for span in [
        "Styled".blue(),
        "Spans".red().on_white(),
        "Bold".bold(),
        "Italic".italic(),
        "Underlined".underlined(),
        "Strikethrough".crossed_out(),
    ] {
        styled_spans.push(span);
        styled_spans.push(" ".into());
    }
    vec![
        Line::raw("Unstyled Line"),
        Line::raw("Styled Line").black().on_red().bold().italic(),
        Line::from(styled_spans),
        Line::from(long_line.green().italic()),
        Line::from_iter([
            "Masked text: ".into(),
            Span::styled(Masked::new("my secret password", '*'), Color::Red),
        ]),
    ]
}
examples/flex.rs (line 434)
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
    fn render(self, area: Rect, buf: &mut Buffer) {
        let title_height = get_description_height(&self.description);
        let layout = Layout::vertical([Length(title_height), Fill(0)]);
        let [title, illustrations] = layout.areas(area);

        let (blocks, spacers) = Layout::horizontal(&self.constraints)
            .flex(self.flex)
            .spacing(self.spacing)
            .split_with_spacers(illustrations);

        if !self.description.is_empty() {
            Paragraph::new(
                self.description
                    .split('\n')
                    .map(|s| format!("// {s}").italic().fg(tailwind::SLATE.c400))
                    .map(Line::from)
                    .collect::<Vec<Line>>(),
            )
            .render(title, buf);
        }

        for (block, constraint) in blocks.iter().zip(&self.constraints) {
            Self::illustration(*constraint, block.width).render(*block, buf);
        }

        for spacer in spacers.iter() {
            Self::render_spacer(*spacer, buf);
        }
    }
examples/chart.rs (line 219)
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
fn render_line_chart(frame: &mut Frame, area: Rect) {
    let datasets = vec![Dataset::default()
        .name("Line from only 2 points".italic())
        .marker(symbols::Marker::Braille)
        .style(Style::default().fg(Color::Yellow))
        .graph_type(GraphType::Line)
        .data(&[(1., 1.), (4., 4.)])];

    let chart = Chart::new(datasets)
        .block(Block::bordered().title(Line::from("Line chart").cyan().bold().centered()))
        .x_axis(
            Axis::default()
                .title("X Axis")
                .style(Style::default().gray())
                .bounds([0.0, 5.0])
                .labels(["0".bold(), "2.5".into(), "5.0".bold()]),
        )
        .y_axis(
            Axis::default()
                .title("Y Axis")
                .style(Style::default().gray())
                .bounds([0.0, 5.0])
                .labels(["0".bold(), "2.5".into(), "5.0".bold()]),
        )
        .legend_position(Some(LegendPosition::TopLeft))
        .hidden_legend_constraints((Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)));

    frame.render_widget(chart, area);
}
source

fn not_italic(self) -> T

Removes the ITALIC modifier.

source

fn underlined(self) -> T

Adds the UNDERLINED modifier.

Examples found in repository?
examples/paragraph.rs (line 137)
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
fn create_lines(area: Rect) -> Vec<Line<'static>> {
    let short_line = "A long line to demonstrate line wrapping. ";
    let long_line = short_line.repeat(usize::from(area.width) / short_line.len() + 4);
    let mut styled_spans = vec![];
    for span in [
        "Styled".blue(),
        "Spans".red().on_white(),
        "Bold".bold(),
        "Italic".italic(),
        "Underlined".underlined(),
        "Strikethrough".crossed_out(),
    ] {
        styled_spans.push(span);
        styled_spans.push(" ".into());
    }
    vec![
        Line::raw("Unstyled Line"),
        Line::raw("Styled Line").black().on_red().bold().italic(),
        Line::from(styled_spans),
        Line::from(long_line.green().italic()),
        Line::from_iter([
            "Masked text: ".into(),
            Span::styled(Masked::new("my secret password", '*'), Color::Red),
        ]),
    ]
}
More examples
Hide additional examples
examples/chart.rs (line 256)
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
fn render_scatter(frame: &mut Frame, area: Rect) {
    let datasets = vec![
        Dataset::default()
            .name("Heavy")
            .marker(Marker::Dot)
            .graph_type(GraphType::Scatter)
            .style(Style::new().yellow())
            .data(&HEAVY_PAYLOAD_DATA),
        Dataset::default()
            .name("Medium".underlined())
            .marker(Marker::Braille)
            .graph_type(GraphType::Scatter)
            .style(Style::new().magenta())
            .data(&MEDIUM_PAYLOAD_DATA),
        Dataset::default()
            .name("Small")
            .marker(Marker::Dot)
            .graph_type(GraphType::Scatter)
            .style(Style::new().cyan())
            .data(&SMALL_PAYLOAD_DATA),
    ];

    let chart = Chart::new(datasets)
        .block(Block::bordered().title(Line::from("Scatter chart").cyan().bold().centered()))
        .x_axis(
            Axis::default()
                .title("Year")
                .bounds([1960., 2020.])
                .style(Style::default().fg(Color::Gray))
                .labels(["1960", "1990", "2020"]),
        )
        .y_axis(
            Axis::default()
                .title("Cost")
                .bounds([0., 75000.])
                .style(Style::default().fg(Color::Gray))
                .labels(["0", "37 500", "75 000"]),
        )
        .hidden_legend_constraints((Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)));

    frame.render_widget(chart, area);
}
source

fn not_underlined(self) -> T

Removes the UNDERLINED modifier.

Adds the SLOW_BLINK modifier.

Examples found in repository?
examples/popup.rs (line 69)
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
    fn draw(&self, frame: &mut Frame) {
        let area = frame.area();

        let vertical = Layout::vertical([Constraint::Percentage(20), Constraint::Percentage(80)]);
        let [instructions, content] = vertical.areas(area);

        let text = if self.show_popup {
            "Press p to close the popup"
        } else {
            "Press p to show the popup"
        };
        let paragraph = Paragraph::new(text.slow_blink())
            .centered()
            .wrap(Wrap { trim: true });
        frame.render_widget(paragraph, instructions);

        let block = Block::bordered().title("Content").on_blue();
        frame.render_widget(block, content);

        if self.show_popup {
            let block = Block::bordered().title("Popup");
            let area = popup_area(area, 60, 20);
            frame.render_widget(Clear, area); //this clears out the background
            frame.render_widget(block, area);
        }
    }

Removes the SLOW_BLINK modifier.

Adds the RAPID_BLINK modifier.

Removes the RAPID_BLINK modifier.

source

fn reversed(self) -> T

Adds the REVERSED modifier.

Examples found in repository?
examples/barchart.rs (line 102)
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
fn vertical_bar(hour: usize, temperature: &u8) -> Bar {
    Bar::default()
        .value(u64::from(*temperature))
        .label(Line::from(format!("{hour:>02}:00")))
        .text_value(format!("{temperature:>3}°"))
        .style(temperature_style(*temperature))
        .value_style(temperature_style(*temperature).reversed())
}

/// Create a horizontal bar chart from the temperatures data.
fn horizontal_barchart(temperatures: &[u8]) -> BarChart {
    let bars: Vec<Bar> = temperatures
        .iter()
        .enumerate()
        .map(|(hour, value)| horizontal_bar(hour, value))
        .collect();
    let title = Line::from("Weather (Horizontal)").centered();
    BarChart::default()
        .block(Block::new().title(title))
        .data(BarGroup::default().bars(&bars))
        .bar_width(1)
        .bar_gap(0)
        .direction(Direction::Horizontal)
}

fn horizontal_bar(hour: usize, temperature: &u8) -> Bar {
    let style = temperature_style(*temperature);
    Bar::default()
        .value(u64::from(*temperature))
        .label(Line::from(format!("{hour:>02}:00")))
        .text_value(format!("{temperature:>3}°"))
        .style(style)
        .value_style(style.reversed())
}
More examples
Hide additional examples
examples/constraint-explorer.rs (line 444)
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
    fn render_2px(&self, area: Rect, buf: &mut Buffer) {
        let lighter_color = ConstraintName::from(self.constraint).lighter_color();
        let main_color = ConstraintName::from(self.constraint).color();
        let selected_color = if self.selected {
            lighter_color
        } else {
            main_color
        };
        Block::bordered()
            .border_set(symbols::border::QUADRANT_OUTSIDE)
            .border_style(Style::reset().fg(selected_color).reversed())
            .render(area, buf);
    }

    fn render_4px(&self, area: Rect, buf: &mut Buffer) {
        let lighter_color = ConstraintName::from(self.constraint).lighter_color();
        let main_color = ConstraintName::from(self.constraint).color();
        let selected_color = if self.selected {
            lighter_color
        } else {
            main_color
        };
        let color = if self.legend {
            selected_color
        } else {
            main_color
        };
        let label = self.label(area.width);
        let block = Block::bordered()
            .border_set(symbols::border::QUADRANT_OUTSIDE)
            .border_style(Style::reset().fg(color).reversed())
            .fg(Self::TEXT_COLOR)
            .bg(color);
        Paragraph::new(label)
            .centered()
            .fg(Self::TEXT_COLOR)
            .bg(color)
            .block(block)
            .render(area, buf);

        if !self.legend {
            let border_color = if self.selected {
                lighter_color
            } else {
                main_color
            };
            if let Some(last_row) = area.rows().last() {
                buf.set_style(last_row, border_color);
            }
        }
    }
examples/flex.rs (line 505)
497
498
499
500
501
502
503
504
505
506
507
508
    fn illustration(constraint: Constraint, width: u16) -> impl Widget {
        let main_color = color_for_constraint(constraint);
        let fg_color = Color::White;
        let title = format!("{constraint}");
        let content = format!("{width} px");
        let text = format!("{title}\n{content}");
        let block = Block::bordered()
            .border_set(symbols::border::QUADRANT_OUTSIDE)
            .border_style(Style::reset().fg(main_color).reversed())
            .style(Style::default().fg(fg_color).bg(main_color));
        Paragraph::new(text).centered().block(block)
    }
source

fn not_reversed(self) -> T

Removes the REVERSED modifier.

source

fn hidden(self) -> T

Adds the HIDDEN modifier.

source

fn not_hidden(self) -> T

Removes the HIDDEN modifier.

source

fn crossed_out(self) -> T

Adds the CROSSED_OUT modifier.

Examples found in repository?
examples/paragraph.rs (line 138)
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
fn create_lines(area: Rect) -> Vec<Line<'static>> {
    let short_line = "A long line to demonstrate line wrapping. ";
    let long_line = short_line.repeat(usize::from(area.width) / short_line.len() + 4);
    let mut styled_spans = vec![];
    for span in [
        "Styled".blue(),
        "Spans".red().on_white(),
        "Bold".bold(),
        "Italic".italic(),
        "Underlined".underlined(),
        "Strikethrough".crossed_out(),
    ] {
        styled_spans.push(span);
        styled_spans.push(" ".into());
    }
    vec![
        Line::raw("Unstyled Line"),
        Line::raw("Styled Line").black().on_red().bold().italic(),
        Line::from(styled_spans),
        Line::from(long_line.green().italic()),
        Line::from_iter([
            "Masked text: ".into(),
            Span::styled(Masked::new("my secret password", '*'), Color::Red),
        ]),
    ]
}
More examples
Hide additional examples
examples/scrollbar.rs (line 114)
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
    fn draw(&mut self, frame: &mut Frame) {
        let area = frame.area();

        // Words made "loooong" to demonstrate line breaking.
        let s =
            "Veeeeeeeeeeeeeeeery    loooooooooooooooooong   striiiiiiiiiiiiiiiiiiiiiiiiiing.   ";
        let mut long_line = s.repeat(usize::from(area.width) / s.len() + 4);
        long_line.push('\n');

        let chunks = Layout::vertical([
            Constraint::Min(1),
            Constraint::Percentage(25),
            Constraint::Percentage(25),
            Constraint::Percentage(25),
            Constraint::Percentage(25),
        ])
        .split(area);

        let text = vec![
            Line::from("This is a line "),
            Line::from("This is a line   ".red()),
            Line::from("This is a line".on_dark_gray()),
            Line::from("This is a longer line".crossed_out()),
            Line::from(long_line.clone()),
            Line::from("This is a line".reset()),
            Line::from(vec![
                Span::raw("Masked text: "),
                Span::styled(Masked::new("password", '*'), Style::new().fg(Color::Red)),
            ]),
            Line::from("This is a line "),
            Line::from("This is a line   ".red()),
            Line::from("This is a line".on_dark_gray()),
            Line::from("This is a longer line".crossed_out()),
            Line::from(long_line.clone()),
            Line::from("This is a line".reset()),
            Line::from(vec![
                Span::raw("Masked text: "),
                Span::styled(Masked::new("password", '*'), Style::new().fg(Color::Red)),
            ]),
        ];
        self.vertical_scroll_state = self.vertical_scroll_state.content_length(text.len());
        self.horizontal_scroll_state = self.horizontal_scroll_state.content_length(long_line.len());

        let create_block = |title: &'static str| Block::bordered().gray().title(title.bold());

        let title = Block::new()
            .title_alignment(Alignment::Center)
            .title("Use h j k l or ◄ ▲ ▼ ► to scroll ".bold());
        frame.render_widget(title, chunks[0]);

        let paragraph = Paragraph::new(text.clone())
            .gray()
            .block(create_block("Vertical scrollbar with arrows"))
            .scroll((self.vertical_scroll as u16, 0));
        frame.render_widget(paragraph, chunks[1]);
        frame.render_stateful_widget(
            Scrollbar::new(ScrollbarOrientation::VerticalRight)
                .begin_symbol(Some("↑"))
                .end_symbol(Some("↓")),
            chunks[1],
            &mut self.vertical_scroll_state,
        );

        let paragraph = Paragraph::new(text.clone())
            .gray()
            .block(create_block(
                "Vertical scrollbar without arrows, without track symbol and mirrored",
            ))
            .scroll((self.vertical_scroll as u16, 0));
        frame.render_widget(paragraph, chunks[2]);
        frame.render_stateful_widget(
            Scrollbar::new(ScrollbarOrientation::VerticalLeft)
                .symbols(scrollbar::VERTICAL)
                .begin_symbol(None)
                .track_symbol(None)
                .end_symbol(None),
            chunks[2].inner(Margin {
                vertical: 1,
                horizontal: 0,
            }),
            &mut self.vertical_scroll_state,
        );

        let paragraph = Paragraph::new(text.clone())
            .gray()
            .block(create_block(
                "Horizontal scrollbar with only begin arrow & custom thumb symbol",
            ))
            .scroll((0, self.horizontal_scroll as u16));
        frame.render_widget(paragraph, chunks[3]);
        frame.render_stateful_widget(
            Scrollbar::new(ScrollbarOrientation::HorizontalBottom)
                .thumb_symbol("🬋")
                .end_symbol(None),
            chunks[3].inner(Margin {
                vertical: 0,
                horizontal: 1,
            }),
            &mut self.horizontal_scroll_state,
        );

        let paragraph = Paragraph::new(text.clone())
            .gray()
            .block(create_block(
                "Horizontal scrollbar without arrows & custom thumb and track symbol",
            ))
            .scroll((0, self.horizontal_scroll as u16));
        frame.render_widget(paragraph, chunks[4]);
        frame.render_stateful_widget(
            Scrollbar::new(ScrollbarOrientation::HorizontalBottom)
                .thumb_symbol("░")
                .track_symbol(Some("─")),
            chunks[4].inner(Margin {
                vertical: 0,
                horizontal: 1,
            }),
            &mut self.horizontal_scroll_state,
        );
    }
source

fn not_crossed_out(self) -> T

Removes the CROSSED_OUT modifier.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§

source§

impl<'a, T, U> Stylize<'a, T> for U
where U: Styled<Item = T>,