Description
Describe the bug
When creating a new list, width is a required argument. This value does absolutely nothing unless it is set to a value smaller than the width of the widest list item. Looking through the code that implements list, I could not find anywhere in which the width member of the list.Model
struct is used to force the rendering to the specified width. It does appear to be used in some capacity when rendering the filter input and the help section, but that's it. Even then, it does not appear to have an effect from my testing.
Setup
Please complete the following information along with version numbers, if applicable.
- OS: KDE Neon
- Shell: zsh
- Terminal Emulator: Kitty
- Terminal Multiplexer: N/A
- Locale: US/UTF-8
To Reproduce
Steps to reproduce the behavior:
- Use
list.New
to create a new list. Set the width to a value larger than the width of your widest list item. - render the list in your view function.
- Observe that list does not respect tha value of the
width
argument.
Source Code
This is the source code from following the tutorial in this video:
package main
import (
"log"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
type status int
const layoutDivisor int = 4
const (
todo status = iota
inProgress
done
)
/* Styling */
var (
columnStyle = lipgloss.NewStyle().
Padding(2, 1).
Border(lipgloss.HiddenBorder())
focusedStyle = lipgloss.NewStyle().
Padding(2, 1).
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("62"))
helpStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("41"))
)
/* Task List Item */
type Task struct {
title string
description string
status status
}
func (t *Task) Title() string { return t.title }
func (t *Task) Description() string { return t.description }
func (t *Task) FilterValue() string { return t.title }
/* Main Model */
type Model struct {
focused status
lists []list.Model
err error
loaded bool
}
func NewModel() *Model {
m := new(Model)
return m
}
func (m *Model) onNextList() {
if m.focused == done {
m.focused = todo
} else {
m.focused++
}
}
func (m *Model) onPrevList() {
if m.focused == todo {
m.focused = done
} else {
m.focused--
}
}
func (m *Model) initLists(width, height int) {
_, heightOffset := columnStyle.GetFrameSize()
// listWidth := (width - (widthOffset * 3)) / 3
listHeight := height - heightOffset
defaultList := list.New([]list.Item{}, list.NewDefaultDelegate(), 10, listHeight)
defaultList.SetShowHelp(false)
m.lists = []list.Model{defaultList, defaultList, defaultList}
m.lists[todo].Title = "Todo"
m.lists[todo].SetItems([]list.Item{
&Task{status: todo, title: "Buy Milk", description: "Strawberry Milk"},
&Task{status: todo, title: "Eat Sushi", description: "California Roll"},
&Task{status: todo, title: "Do Laundry", description: "Or have wrinkles"},
})
m.lists[inProgress].Title = "In Progress"
m.lists[inProgress].SetItems([]list.Item{
&Task{status: todo, title: "Be Cool", description: "You know it baby!"},
})
m.lists[done].Title = "Done"
m.lists[done].SetItems([]list.Item{
&Task{status: todo, title: "VetRec Interview 2", description: "Went well"},
&Task{status: todo, title: "Learn Go", description: "Language Learned"},
})
m.loaded = true
}
func (m Model) Init() tea.Cmd {
return nil
}
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.initLists(msg.Width, msg.Height)
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c":
return m, tea.Quit
case "left":
m.onPrevList()
case "right":
m.onNextList()
case "tab":
m.onNextList()
}
}
m.lists[m.focused], cmd = m.lists[m.focused].Update(msg)
return m, cmd
}
func (m Model) View() string {
if !m.loaded {
return "Loading..."
}
todoList := m.lists[todo].View()
inProgressList := m.lists[inProgress].View()
doneList := m.lists[done].View()
switch m.focused {
case todo:
todoList = focusedStyle.Render(todoList)
inProgressList = columnStyle.Render(inProgressList)
doneList = columnStyle.Render(doneList)
case inProgress:
todoList = columnStyle.Render(todoList)
inProgressList = focusedStyle.Render(inProgressList)
doneList = columnStyle.Render(doneList)
case done:
todoList = columnStyle.Render(todoList)
inProgressList = columnStyle.Render(inProgressList)
doneList = focusedStyle.Render(doneList)
}
return lipgloss.JoinHorizontal(
lipgloss.Center,
todoList,
inProgressList,
doneList,
)
}
func main() {
model := NewModel()
p := tea.NewProgram(model, tea.WithAltScreen())
_, err := p.Run()
if err != nil {
log.Fatal(err)
}
}
Expected behavior
The value passed to width when creating a new list via list.New
should set the width of the rendered list component.
Screenshots
Screencast_20250226_141745.webm
Additional context
Add any other context about the problem here.