List + Tabs widgets switching keeps character artifact upon rendering

hello, i am trying to switch with keys between tabs and j + k up/down within list widget, it works fine but when i switch between tabs it keeps some of the old characters of the list from a different tab

i attached photos of what happens when rendering and switching between tabs

(backend crossterm)

.

i also tried using the clear widget before calling frame. render_widget / render_stateful
here is my implementation:

tabs:

fn render(
    frame: &mut Frame,
    list_state: &mut ListState,
    filter_input: &mut tui_input::TuiInput,
    nextkey: Option<KeyEvent>,
) {
  ..
    let main_chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints([
            Constraint::Length(1), // Header text
            Constraint::Min(1),    // Main Body (List + Table)
            Constraint::Length(2), // Application metadata footer
        ])
        .split(frame.size());

    // --- STEP 2: Body (Horizontal Split) ---
    let body_chunks = Layout::default()
        .direction(Direction::Horizontal)
        .constraints([
            Constraint::Ratio(1, 4), // Services List
            Constraint::Ratio(3, 4), // Logs Table (and its headers)
        ])
        .split(main_chunks[1]);
...

    render_buffer_tabs(frame, body_chunks[1], nextkey);
    if (filter_input.render_input(servicechunk[1], frame, nextkey)) {
        list_state.select(Some(0 as usize));
    }
}


fn render_buffer_tabs(frame: &mut Frame, area: Rect, nextkey: Option) {
let tab_chunks = Layout::default().direction(Direction::Vertical).constraints([Constraint::Length(1),Constraint::Min(0),]).split(area);
let mut buffers = get_buffers().lock().unwrap();

let tab_titles: Vec<String> = buffers
    .iter()
    .map(|b| format!("📝{}", b.unit.clone()))
    .collect();

let tabs = Tabs::new(tab_titles)
    .highlight_style(Style::new().fg(SEETui::FOCUSED_COLOR).bold())
    .select(SELECTED_BUFFER.load(Ordering::SeqCst))
    .divider("|")
    .padding(" ", " ");
frame.render_widget(tabs, tab_chunks[0]);
}

list:

    fn render(&mut self, area: Rect, frame: &mut Frame, key: Option<KeyEvent>) {
...
        let main_chunks = Layout::default()
            .direction(Direction::Vertical)
            .constraints([
                Constraint::Min(3),
               ...
            ])
            .split(area);
...
  self.render_logs(frame, main_chunks[0]);
}
 pub fn render_logs(&mut self, frame: &mut Frame, area: Rect) {
        if self.pull_data() {
            self.lstate.select_last();
        }
        let cool_block = Block::default()
            .borders(Borders::ALL)
            .padding(Padding::new(0, 1, 0, 0))
            .bg(Color::Rgb(20, 20, 25))
            .border_type(BorderType::Rounded)
            .border_style(if self.inputstate == InputMode::SelectLog {
                SEETui::FOCUSED_COLOR
            } else {
                SEETui::UNFOCUSED_COLOR
            });

        let list = List::new(self.log_data.clone())
            .block(cool_block)
            .highlight_symbol(">>")
            .bg(Color::Rgb(20, 20, 25))
            .highlight_style(Style::new().white().bg(SEETui::FOCUSED_COLOR));
        frame.render_stateful_widget(list, area, &mut self.lstate);
    }

Where are you calling the clear widget? I don’t see it in your code snippets, and I think that is the solution you are looking for. Ideally, you would put the clear widget either at a top level, or as close to the layout split declaration as you can be, but it can go anywhere. Behind the scenes Ratatui runs a diff on the rendered buffer before sending draw commands to the terminal, so clearing and redrawing isn’t as bad as it sounds performance wise.

I’m surprised you are only having the last character redraw issues based only on the code provided.

i tried in both before

frame.render_stateful_widget(list, area, &mut self.lstate);

in render logs and also before

frame.render_widget(tabs, tab_chunks[0]);

in render_buffer_tabs

its not in the snippets because it did not fix the problem so i removed unnecessary calls

i was calling the clear widget like this:

frame.render_widget(Clear, /*tab_chunks[0] / area */);

found out what the problem was Emojis in List item.

atm i did not find a workaround to the problem (unless removing the emojis)

it seems to break the render engine and miscalculate character length and then push the last characters a bit off in rendering in relation from where they are actually positioned

this problem relates to these:

1 Like