Struct ratatui::widgets::Scrollbar

source ·
pub struct Scrollbar<'a> { /* private fields */ }
Expand description

A widget to display a scrollbar

The following components of the scrollbar are customizable in symbol and style. Note the scrollbar is represented horizontally but it can also be set vertically (which is actually the default).

<--▮------->
^  ^   ^   ^
│  │   │   └ end
│  │   └──── track
│  └──────── thumb
└─────────── begin

§Important

You must specify the ScrollbarState::content_length before rendering the Scrollbar, or else the Scrollbar will render blank.

§Examples

use ratatui::{prelude::*, widgets::*};

let vertical_scroll = 0; // from app state

let items = vec![
    Line::from("Item 1"),
    Line::from("Item 2"),
    Line::from("Item 3"),
];
let paragraph = Paragraph::new(items.clone())
    .scroll((vertical_scroll as u16, 0))
    .block(Block::new().borders(Borders::RIGHT)); // to show a background for the scrollbar

let scrollbar = Scrollbar::new(ScrollbarOrientation::VerticalRight)
    .begin_symbol(Some("↑"))
    .end_symbol(Some("↓"));

let mut scrollbar_state = ScrollbarState::new(items.len()).position(vertical_scroll);

let area = frame.size();
// Note we render the paragraph
frame.render_widget(paragraph, area);
// and the scrollbar, those are separate widgets
frame.render_stateful_widget(
    scrollbar,
    area.inner(&Margin {
        // using an inner vertical margin of 1 unit makes the scrollbar inside the block
        vertical: 1,
        horizontal: 0,
    }),
    &mut scrollbar_state,
);

Implementations§

source§

impl<'a> Scrollbar<'a>

source

pub const fn new(orientation: ScrollbarOrientation) -> Self

Creates a new scrollbar with the given orientation.

Most of the time you’ll want ScrollbarOrientation::VerticalRight or ScrollbarOrientation::HorizontalBottom. See ScrollbarOrientation for more options.

Examples found in repository?
examples/demo2/tabs/recipe.rs (line 170)
165
166
167
168
169
170
171
172
173
174
175
176
fn render_scrollbar(position: usize, area: Rect, buf: &mut Buffer) {
    let mut state = ScrollbarState::default()
        .content_length(INGREDIENTS.len())
        .viewport_content_length(6)
        .position(position);
    Scrollbar::new(ScrollbarOrientation::VerticalRight)
        .begin_symbol(None)
        .end_symbol(None)
        .track_symbol(None)
        .thumb_symbol("▐")
        .render(area, buf, &mut state);
}
More examples
Hide additional examples
examples/flex.rs (line 344)
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
    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.get_mut(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
    }
examples/scrollbar.rs (line 169)
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
fn ui(f: &mut Frame, app: &mut App) {
    let size = f.size();

    // Words made "loooong" to demonstrate line breaking.
    let s = "Veeeeeeeeeeeeeeeery    loooooooooooooooooong   striiiiiiiiiiiiiiiiiiiiiiiiiing.   ";
    let mut long_line = s.repeat(usize::from(size.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(size);

    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)),
        ]),
    ];
    app.vertical_scroll_state = app.vertical_scroll_state.content_length(text.len());
    app.horizontal_scroll_state = app.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());
    f.render_widget(title, chunks[0]);

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

    let paragraph = Paragraph::new(text.clone())
        .gray()
        .block(create_block(
            "Vertical scrollbar without arrows, without track symbol and mirrored",
        ))
        .scroll((app.vertical_scroll as u16, 0));
    f.render_widget(paragraph, chunks[2]);
    f.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 app.vertical_scroll_state,
    );

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

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

pub const fn orientation(self, orientation: ScrollbarOrientation) -> Self

Sets the position of the scrollbar.

The orientation of the scrollbar is the position it will take around a Rect. See ScrollbarOrientation for more details.

Resets the symbols to DOUBLE_VERTICAL or DOUBLE_HORIZONTAL based on orientation.

This is a fluent setter method which must be chained or used as it consumes self

Examples found in repository?
examples/table.rs (line 318)
315
316
317
318
319
320
321
322
323
324
325
326
327
fn render_scrollbar(f: &mut Frame, app: &mut App, area: Rect) {
    f.render_stateful_widget(
        Scrollbar::default()
            .orientation(ScrollbarOrientation::VerticalRight)
            .begin_symbol(None)
            .end_symbol(None),
        area.inner(&Margin {
            vertical: 1,
            horizontal: 1,
        }),
        &mut app.scroll_state,
    );
}
More examples
Hide additional examples
examples/demo2/tabs/traceroute.rs (line 75)
46
47
48
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
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]))
        .collect_vec();
    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))
            .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

pub const fn orientation_and_symbol( self, orientation: ScrollbarOrientation, symbols: Set ) -> Self

Sets the orientation and symbols for the scrollbar from a Set.

This has the same effect as calling Scrollbar::orientation and then Scrollbar::symbols. See those for more details.

This is a fluent setter method which must be chained or used as it consumes self

source

pub const fn thumb_symbol(self, thumb_symbol: &'a str) -> Self

Sets the symbol that represents the thumb of the scrollbar.

The thumb is the handle representing the progression on the scrollbar. See Scrollbar for a visual example of what this represents.

This is a fluent setter method which must be chained or used as it consumes self

Examples found in repository?
examples/demo2/tabs/recipe.rs (line 174)
165
166
167
168
169
170
171
172
173
174
175
176
fn render_scrollbar(position: usize, area: Rect, buf: &mut Buffer) {
    let mut state = ScrollbarState::default()
        .content_length(INGREDIENTS.len())
        .viewport_content_length(6)
        .position(position);
    Scrollbar::new(ScrollbarOrientation::VerticalRight)
        .begin_symbol(None)
        .end_symbol(None)
        .track_symbol(None)
        .thumb_symbol("▐")
        .render(area, buf, &mut state);
}
More examples
Hide additional examples
examples/demo2/tabs/traceroute.rs (line 79)
46
47
48
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
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]))
        .collect_vec();
    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))
            .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);
}
examples/demo2/tabs/email.rs (line 114)
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
fn render_inbox(selected_index: usize, area: Rect, buf: &mut Buffer) {
    let vertical = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
    let [tabs, inbox] = vertical.areas(area);
    let theme = THEME.email;
    Tabs::new(vec![" Inbox ", " Sent ", " Drafts "])
        .style(theme.tabs)
        .highlight_style(theme.tabs_selected)
        .select(0)
        .divider("")
        .render(tabs, buf);

    let highlight_symbol = ">>";
    let from_width = EMAILS
        .iter()
        .map(|e| e.from.width())
        .max()
        .unwrap_or_default();
    let items = EMAILS
        .iter()
        .map(|e| {
            let from = format!("{:width$}", e.from, width = from_width).into();
            ListItem::new(Line::from(vec![from, " ".into(), e.subject.into()]))
        })
        .collect_vec();
    let mut state = ListState::default().with_selected(Some(selected_index));
    StatefulWidget::render(
        List::new(items)
            .style(theme.inbox)
            .highlight_style(theme.selected_item)
            .highlight_symbol(highlight_symbol),
        inbox,
        buf,
        &mut state,
    );
    let mut scrollbar_state = ScrollbarState::default()
        .content_length(EMAILS.len())
        .position(selected_index);
    Scrollbar::default()
        .begin_symbol(None)
        .end_symbol(None)
        .track_symbol(None)
        .thumb_symbol("▐")
        .render(inbox, buf, &mut scrollbar_state);
}
examples/scrollbar.rs (line 205)
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
fn ui(f: &mut Frame, app: &mut App) {
    let size = f.size();

    // Words made "loooong" to demonstrate line breaking.
    let s = "Veeeeeeeeeeeeeeeery    loooooooooooooooooong   striiiiiiiiiiiiiiiiiiiiiiiiiing.   ";
    let mut long_line = s.repeat(usize::from(size.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(size);

    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)),
        ]),
    ];
    app.vertical_scroll_state = app.vertical_scroll_state.content_length(text.len());
    app.horizontal_scroll_state = app.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());
    f.render_widget(title, chunks[0]);

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

    let paragraph = Paragraph::new(text.clone())
        .gray()
        .block(create_block(
            "Vertical scrollbar without arrows, without track symbol and mirrored",
        ))
        .scroll((app.vertical_scroll as u16, 0));
    f.render_widget(paragraph, chunks[2]);
    f.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 app.vertical_scroll_state,
    );

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

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

pub fn thumb_style<S: Into<Style>>(self, thumb_style: S) -> Self

Sets the style on the scrollbar thumb.

The thumb is the handle representing the progression on the scrollbar. See Scrollbar for a visual example of what this represents.

style accepts any type that is convertible to Style (e.g. Style, Color, or your own type that implements Into<Style>).

This is a fluent setter method which must be chained or used as it consumes self

source

pub const fn track_symbol(self, track_symbol: Option<&'a str>) -> Self

Sets the symbol that represents the track of the scrollbar.

See Scrollbar for a visual example of what this represents.

This is a fluent setter method which must be chained or used as it consumes self

Examples found in repository?
examples/demo2/tabs/recipe.rs (line 173)
165
166
167
168
169
170
171
172
173
174
175
176
fn render_scrollbar(position: usize, area: Rect, buf: &mut Buffer) {
    let mut state = ScrollbarState::default()
        .content_length(INGREDIENTS.len())
        .viewport_content_length(6)
        .position(position);
    Scrollbar::new(ScrollbarOrientation::VerticalRight)
        .begin_symbol(None)
        .end_symbol(None)
        .track_symbol(None)
        .thumb_symbol("▐")
        .render(area, buf, &mut state);
}
More examples
Hide additional examples
examples/demo2/tabs/traceroute.rs (line 78)
46
47
48
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
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]))
        .collect_vec();
    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))
            .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);
}
examples/demo2/tabs/email.rs (line 113)
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
fn render_inbox(selected_index: usize, area: Rect, buf: &mut Buffer) {
    let vertical = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
    let [tabs, inbox] = vertical.areas(area);
    let theme = THEME.email;
    Tabs::new(vec![" Inbox ", " Sent ", " Drafts "])
        .style(theme.tabs)
        .highlight_style(theme.tabs_selected)
        .select(0)
        .divider("")
        .render(tabs, buf);

    let highlight_symbol = ">>";
    let from_width = EMAILS
        .iter()
        .map(|e| e.from.width())
        .max()
        .unwrap_or_default();
    let items = EMAILS
        .iter()
        .map(|e| {
            let from = format!("{:width$}", e.from, width = from_width).into();
            ListItem::new(Line::from(vec![from, " ".into(), e.subject.into()]))
        })
        .collect_vec();
    let mut state = ListState::default().with_selected(Some(selected_index));
    StatefulWidget::render(
        List::new(items)
            .style(theme.inbox)
            .highlight_style(theme.selected_item)
            .highlight_symbol(highlight_symbol),
        inbox,
        buf,
        &mut state,
    );
    let mut scrollbar_state = ScrollbarState::default()
        .content_length(EMAILS.len())
        .position(selected_index);
    Scrollbar::default()
        .begin_symbol(None)
        .end_symbol(None)
        .track_symbol(None)
        .thumb_symbol("▐")
        .render(inbox, buf, &mut scrollbar_state);
}
examples/scrollbar.rs (line 187)
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
fn ui(f: &mut Frame, app: &mut App) {
    let size = f.size();

    // Words made "loooong" to demonstrate line breaking.
    let s = "Veeeeeeeeeeeeeeeery    loooooooooooooooooong   striiiiiiiiiiiiiiiiiiiiiiiiiing.   ";
    let mut long_line = s.repeat(usize::from(size.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(size);

    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)),
        ]),
    ];
    app.vertical_scroll_state = app.vertical_scroll_state.content_length(text.len());
    app.horizontal_scroll_state = app.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());
    f.render_widget(title, chunks[0]);

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

    let paragraph = Paragraph::new(text.clone())
        .gray()
        .block(create_block(
            "Vertical scrollbar without arrows, without track symbol and mirrored",
        ))
        .scroll((app.vertical_scroll as u16, 0));
    f.render_widget(paragraph, chunks[2]);
    f.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 app.vertical_scroll_state,
    );

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

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

pub fn track_style<S: Into<Style>>(self, track_style: S) -> Self

Sets the style that is used for the track of the scrollbar.

See Scrollbar for a visual example of what this represents.

style accepts any type that is convertible to Style (e.g. Style, Color, or your own type that implements Into<Style>).

This is a fluent setter method which must be chained or used as it consumes self

source

pub const fn begin_symbol(self, begin_symbol: Option<&'a str>) -> Self

Sets the symbol that represents the beginning of the scrollbar.

See Scrollbar for a visual example of what this represents.

This is a fluent setter method which must be chained or used as it consumes self

Examples found in repository?
examples/table.rs (line 319)
315
316
317
318
319
320
321
322
323
324
325
326
327
fn render_scrollbar(f: &mut Frame, app: &mut App, area: Rect) {
    f.render_stateful_widget(
        Scrollbar::default()
            .orientation(ScrollbarOrientation::VerticalRight)
            .begin_symbol(None)
            .end_symbol(None),
        area.inner(&Margin {
            vertical: 1,
            horizontal: 1,
        }),
        &mut app.scroll_state,
    );
}
More examples
Hide additional examples
examples/demo2/tabs/recipe.rs (line 171)
165
166
167
168
169
170
171
172
173
174
175
176
fn render_scrollbar(position: usize, area: Rect, buf: &mut Buffer) {
    let mut state = ScrollbarState::default()
        .content_length(INGREDIENTS.len())
        .viewport_content_length(6)
        .position(position);
    Scrollbar::new(ScrollbarOrientation::VerticalRight)
        .begin_symbol(None)
        .end_symbol(None)
        .track_symbol(None)
        .thumb_symbol("▐")
        .render(area, buf, &mut state);
}
examples/demo2/tabs/traceroute.rs (line 76)
46
47
48
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
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]))
        .collect_vec();
    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))
            .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);
}
examples/demo2/tabs/email.rs (line 111)
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
fn render_inbox(selected_index: usize, area: Rect, buf: &mut Buffer) {
    let vertical = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
    let [tabs, inbox] = vertical.areas(area);
    let theme = THEME.email;
    Tabs::new(vec![" Inbox ", " Sent ", " Drafts "])
        .style(theme.tabs)
        .highlight_style(theme.tabs_selected)
        .select(0)
        .divider("")
        .render(tabs, buf);

    let highlight_symbol = ">>";
    let from_width = EMAILS
        .iter()
        .map(|e| e.from.width())
        .max()
        .unwrap_or_default();
    let items = EMAILS
        .iter()
        .map(|e| {
            let from = format!("{:width$}", e.from, width = from_width).into();
            ListItem::new(Line::from(vec![from, " ".into(), e.subject.into()]))
        })
        .collect_vec();
    let mut state = ListState::default().with_selected(Some(selected_index));
    StatefulWidget::render(
        List::new(items)
            .style(theme.inbox)
            .highlight_style(theme.selected_item)
            .highlight_symbol(highlight_symbol),
        inbox,
        buf,
        &mut state,
    );
    let mut scrollbar_state = ScrollbarState::default()
        .content_length(EMAILS.len())
        .position(selected_index);
    Scrollbar::default()
        .begin_symbol(None)
        .end_symbol(None)
        .track_symbol(None)
        .thumb_symbol("▐")
        .render(inbox, buf, &mut scrollbar_state);
}
examples/scrollbar.rs (line 170)
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
fn ui(f: &mut Frame, app: &mut App) {
    let size = f.size();

    // Words made "loooong" to demonstrate line breaking.
    let s = "Veeeeeeeeeeeeeeeery    loooooooooooooooooong   striiiiiiiiiiiiiiiiiiiiiiiiiing.   ";
    let mut long_line = s.repeat(usize::from(size.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(size);

    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)),
        ]),
    ];
    app.vertical_scroll_state = app.vertical_scroll_state.content_length(text.len());
    app.horizontal_scroll_state = app.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());
    f.render_widget(title, chunks[0]);

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

    let paragraph = Paragraph::new(text.clone())
        .gray()
        .block(create_block(
            "Vertical scrollbar without arrows, without track symbol and mirrored",
        ))
        .scroll((app.vertical_scroll as u16, 0));
    f.render_widget(paragraph, chunks[2]);
    f.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 app.vertical_scroll_state,
    );

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

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

pub fn begin_style<S: Into<Style>>(self, begin_style: S) -> Self

Sets the style that is used for the beginning of the scrollbar.

See Scrollbar for a visual example of what this represents.

style accepts any type that is convertible to Style (e.g. Style, Color, or your own type that implements Into<Style>).

This is a fluent setter method which must be chained or used as it consumes self

source

pub const fn end_symbol(self, end_symbol: Option<&'a str>) -> Self

Sets the symbol that represents the end of the scrollbar.

See Scrollbar for a visual example of what this represents.

This is a fluent setter method which must be chained or used as it consumes self

Examples found in repository?
examples/table.rs (line 320)
315
316
317
318
319
320
321
322
323
324
325
326
327
fn render_scrollbar(f: &mut Frame, app: &mut App, area: Rect) {
    f.render_stateful_widget(
        Scrollbar::default()
            .orientation(ScrollbarOrientation::VerticalRight)
            .begin_symbol(None)
            .end_symbol(None),
        area.inner(&Margin {
            vertical: 1,
            horizontal: 1,
        }),
        &mut app.scroll_state,
    );
}
More examples
Hide additional examples
examples/demo2/tabs/recipe.rs (line 172)
165
166
167
168
169
170
171
172
173
174
175
176
fn render_scrollbar(position: usize, area: Rect, buf: &mut Buffer) {
    let mut state = ScrollbarState::default()
        .content_length(INGREDIENTS.len())
        .viewport_content_length(6)
        .position(position);
    Scrollbar::new(ScrollbarOrientation::VerticalRight)
        .begin_symbol(None)
        .end_symbol(None)
        .track_symbol(None)
        .thumb_symbol("▐")
        .render(area, buf, &mut state);
}
examples/demo2/tabs/traceroute.rs (line 77)
46
47
48
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
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]))
        .collect_vec();
    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))
            .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);
}
examples/demo2/tabs/email.rs (line 112)
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
fn render_inbox(selected_index: usize, area: Rect, buf: &mut Buffer) {
    let vertical = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
    let [tabs, inbox] = vertical.areas(area);
    let theme = THEME.email;
    Tabs::new(vec![" Inbox ", " Sent ", " Drafts "])
        .style(theme.tabs)
        .highlight_style(theme.tabs_selected)
        .select(0)
        .divider("")
        .render(tabs, buf);

    let highlight_symbol = ">>";
    let from_width = EMAILS
        .iter()
        .map(|e| e.from.width())
        .max()
        .unwrap_or_default();
    let items = EMAILS
        .iter()
        .map(|e| {
            let from = format!("{:width$}", e.from, width = from_width).into();
            ListItem::new(Line::from(vec![from, " ".into(), e.subject.into()]))
        })
        .collect_vec();
    let mut state = ListState::default().with_selected(Some(selected_index));
    StatefulWidget::render(
        List::new(items)
            .style(theme.inbox)
            .highlight_style(theme.selected_item)
            .highlight_symbol(highlight_symbol),
        inbox,
        buf,
        &mut state,
    );
    let mut scrollbar_state = ScrollbarState::default()
        .content_length(EMAILS.len())
        .position(selected_index);
    Scrollbar::default()
        .begin_symbol(None)
        .end_symbol(None)
        .track_symbol(None)
        .thumb_symbol("▐")
        .render(inbox, buf, &mut scrollbar_state);
}
examples/scrollbar.rs (line 171)
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
fn ui(f: &mut Frame, app: &mut App) {
    let size = f.size();

    // Words made "loooong" to demonstrate line breaking.
    let s = "Veeeeeeeeeeeeeeeery    loooooooooooooooooong   striiiiiiiiiiiiiiiiiiiiiiiiiing.   ";
    let mut long_line = s.repeat(usize::from(size.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(size);

    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)),
        ]),
    ];
    app.vertical_scroll_state = app.vertical_scroll_state.content_length(text.len());
    app.horizontal_scroll_state = app.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());
    f.render_widget(title, chunks[0]);

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

    let paragraph = Paragraph::new(text.clone())
        .gray()
        .block(create_block(
            "Vertical scrollbar without arrows, without track symbol and mirrored",
        ))
        .scroll((app.vertical_scroll as u16, 0));
    f.render_widget(paragraph, chunks[2]);
    f.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 app.vertical_scroll_state,
    );

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

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

pub fn end_style<S: Into<Style>>(self, end_style: S) -> Self

Sets the style that is used for the end of the scrollbar.

See Scrollbar for a visual example of what this represents.

style accepts any type that is convertible to Style (e.g. Style, Color, or your own type that implements Into<Style>).

This is a fluent setter method which must be chained or used as it consumes self

source

pub const fn symbols(self, symbols: Set) -> Self

Sets the symbols used for the various parts of the scrollbar from a Set.

<--▮------->
^  ^   ^   ^
│  │   │   └ end
│  │   └──── track
│  └──────── thumb
└─────────── begin

Only sets begin_symbol, end_symbol and track_symbol if they already contain a value. If they were set to None explicitly, this function will respect that choice. Use their respective setters to change their value.

This is a fluent setter method which must be chained or used as it consumes self

Examples found in repository?
examples/scrollbar.rs (line 185)
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
fn ui(f: &mut Frame, app: &mut App) {
    let size = f.size();

    // Words made "loooong" to demonstrate line breaking.
    let s = "Veeeeeeeeeeeeeeeery    loooooooooooooooooong   striiiiiiiiiiiiiiiiiiiiiiiiiing.   ";
    let mut long_line = s.repeat(usize::from(size.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(size);

    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)),
        ]),
    ];
    app.vertical_scroll_state = app.vertical_scroll_state.content_length(text.len());
    app.horizontal_scroll_state = app.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());
    f.render_widget(title, chunks[0]);

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

    let paragraph = Paragraph::new(text.clone())
        .gray()
        .block(create_block(
            "Vertical scrollbar without arrows, without track symbol and mirrored",
        ))
        .scroll((app.vertical_scroll as u16, 0));
    f.render_widget(paragraph, chunks[2]);
    f.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 app.vertical_scroll_state,
    );

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

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

pub fn style<S: Into<Style>>(self, style: S) -> Self

Sets the style used for the various parts of the scrollbar from a Style.

style accepts any type that is convertible to Style (e.g. Style, Color, or your own type that implements Into<Style>).

<--▮------->
^  ^   ^   ^
│  │   │   └ end
│  │   └──── track
│  └──────── thumb
└─────────── begin

This is a fluent setter method which must be chained or used as it consumes self

Trait Implementations§

source§

impl<'a> Clone for Scrollbar<'a>

source§

fn clone(&self) -> Scrollbar<'a>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<'a> Debug for Scrollbar<'a>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<'a> Default for Scrollbar<'a>

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl<'a> Hash for Scrollbar<'a>

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl<'a> PartialEq for Scrollbar<'a>

source§

fn eq(&self, other: &Scrollbar<'a>) -> bool

This method tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl<'a> StatefulWidget for Scrollbar<'a>

§

type State = ScrollbarState

State associated with the stateful widget. Read more
source§

fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State)

Draws the current state of the widget in the given buffer. That is the only method required to implement a custom stateful widget.
source§

impl<'a> Eq for Scrollbar<'a>

source§

impl<'a> StructuralPartialEq for Scrollbar<'a>

Auto Trait Implementations§

§

impl<'a> Freeze for Scrollbar<'a>

§

impl<'a> RefUnwindSafe for Scrollbar<'a>

§

impl<'a> Send for Scrollbar<'a>

§

impl<'a> Sync for Scrollbar<'a>

§

impl<'a> Unpin for Scrollbar<'a>

§

impl<'a> UnwindSafe for Scrollbar<'a>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> IntoEither for T

source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.