@@ -56,7 +56,6 @@ const (
 type renderedItem struct {
 	id     string
 	view   string
-	dirty  bool
 	height int
 	start  int
 	end    int
@@ -84,6 +83,8 @@ type list[T Item] struct {
 	renderedItems map[string]renderedItem
 
 	rendered string
+
+	movingByItem bool
 }
 
 type listOption func(*confOptions)
@@ -209,7 +210,9 @@ func (l *list[T]) View() string {
 	lines := strings.Split(view, "\n")
 
 	start, end := l.viewPosition()
-	lines = lines[start : end+1]
+	viewStart := max(0, start)
+	viewEnd := min(len(lines), end+1)
+	lines = lines[viewStart:viewEnd]
 	return strings.Join(lines, "\n")
 }
 
@@ -245,7 +248,13 @@ func (l *list[T]) render() tea.Cmd {
 		return nil
 	}
 	l.setDefaultSelected()
-	focusCmd := l.focusSelectedItem()
+
+	var focusChangeCmd tea.Cmd
+	if l.focused {
+		focusChangeCmd = l.focusSelectedItem()
+	} else {
+		focusChangeCmd = l.blurSelectedItem()
+	}
 	// we are not rendering the first time
 	if l.rendered != "" {
 		l.rendered = ""
@@ -258,7 +267,7 @@ func (l *list[T]) render() tea.Cmd {
 		if l.focused {
 			l.scrollToSelection()
 		}
-		return focusCmd
+		return focusChangeCmd
 	}
 	finishIndex := l.renderIterator(0, true)
 	// recalculate for the initial items
@@ -276,9 +285,10 @@ func (l *list[T]) render() tea.Cmd {
 		if l.focused {
 			l.scrollToSelection()
 		}
+
 		return renderedMsg{}
 	}
-	return tea.Batch(focusCmd, renderCmd)
+	return tea.Batch(focusChangeCmd, renderCmd)
 }
 
 func (l *list[T]) setDefaultSelected() {
@@ -304,11 +314,21 @@ func (l *list[T]) scrollToSelection() {
 	if rItem.start <= start && rItem.end >= end {
 		return
 	}
-	// item already in view do nothing
-	if rItem.start >= start && rItem.start <= end {
-		return
-	} else if rItem.end <= end && rItem.end >= start {
-		return
+	// if we are moving by item we want to move the offset so that the
+	// whole item is visible not just portions of it
+	if l.movingByItem {
+		if rItem.start >= start && rItem.end <= end {
+			return
+		}
+		defer func() { l.movingByItem = false }()
+	} else {
+		// item already in view do nothing
+		if rItem.start >= start && rItem.start <= end {
+			return
+		}
+		if rItem.end >= start && rItem.end <= end {
+			return
+		}
 	}
 
 	if rItem.height >= l.height {
@@ -320,11 +340,22 @@ func (l *list[T]) scrollToSelection() {
 		return
 	}
 
-	itemMiddleStart := rItem.start + rItem.height/2 + 1
-	if l.direction == DirectionForward {
-		l.offset = itemMiddleStart - l.height/2
-	} else {
-		l.offset = max(0, lipgloss.Height(l.rendered)-(itemMiddleStart+l.height/2))
+	renderedLines := lipgloss.Height(l.rendered) - 1
+
+	// If item is above the viewport, make it the first item
+	if rItem.start < start {
+		if l.direction == DirectionForward {
+			l.offset = rItem.start
+		} else {
+			l.offset = max(0, renderedLines-rItem.start-l.height+1)
+		}
+	} else if rItem.end > end {
+		// If item is below the viewport, make it the last item
+		if l.direction == DirectionForward {
+			l.offset = max(0, rItem.end-l.height+1)
+		} else {
+			l.offset = max(0, renderedLines-rItem.end)
+		}
 	}
 }
 
@@ -446,32 +477,26 @@ func (l *list[T]) focusSelectedItem() tea.Cmd {
 		if f, ok := any(item).(layout.Focusable); ok {
 			if item.ID() == l.selectedItem && !f.IsFocused() {
 				cmds = append(cmds, f.Focus())
-				if cache, ok := l.renderedItems[item.ID()]; ok {
-					cache.dirty = true
-					l.renderedItems[item.ID()] = cache
-				}
+				delete(l.renderedItems, item.ID())
 			} else if item.ID() != l.selectedItem && f.IsFocused() {
 				cmds = append(cmds, f.Blur())
-				if cache, ok := l.renderedItems[item.ID()]; ok {
-					cache.dirty = true
-					l.renderedItems[item.ID()] = cache
-				}
+				delete(l.renderedItems, item.ID())
 			}
 		}
 	}
 	return tea.Batch(cmds...)
 }
 
-func (l *list[T]) blurItems() tea.Cmd {
+func (l *list[T]) blurSelectedItem() tea.Cmd {
+	if l.selectedItem == "" || l.focused {
+		return nil
+	}
 	var cmds []tea.Cmd
 	for _, item := range l.items {
 		if f, ok := any(item).(layout.Focusable); ok {
 			if item.ID() == l.selectedItem && f.IsFocused() {
 				cmds = append(cmds, f.Blur())
-				if cache, ok := l.renderedItems[item.ID()]; ok {
-					cache.dirty = true
-					l.renderedItems[item.ID()] = cache
-				}
+				delete(l.renderedItems, item.ID())
 			}
 		}
 	}
@@ -495,7 +520,7 @@ func (l *list[T]) renderIterator(startInx int, limitHeight bool) int {
 
 		item := l.items[inx]
 		var rItem renderedItem
-		if cache, ok := l.renderedItems[item.ID()]; ok && !cache.dirty {
+		if cache, ok := l.renderedItems[item.ID()]; ok {
 			rItem = cache
 		} else {
 			rItem = l.renderItem(item)
@@ -534,8 +559,8 @@ func (l *list[T]) AppendItem(T) tea.Cmd {
 
 // Blur implements List.
 func (l *list[T]) Blur() tea.Cmd {
-	cmd := l.blurItems()
-	return tea.Batch(cmd, l.render())
+	l.focused = false
+	return l.render()
 }
 
 // DeleteItem implements List.
@@ -644,6 +669,7 @@ func (l *list[T]) SelectItemAbove() tea.Cmd {
 	}
 	item := l.items[newIndex]
 	l.selectedItem = item.ID()
+	l.movingByItem = true
 	return l.render()
 }
 
@@ -661,6 +687,7 @@ func (l *list[T]) SelectItemBelow() tea.Cmd {
 	}
 	item := l.items[newIndex]
 	l.selectedItem = item.ID()
+	l.movingByItem = true
 	return l.render()
 }
 
@@ -692,6 +719,8 @@ func (l *list[T]) SetSelected(id string) tea.Cmd {
 func (l *list[T]) reset() tea.Cmd {
 	var cmds []tea.Cmd
 	l.rendered = ""
+	l.offset = 0
+	l.selectedItem = ""
 	l.indexMap = make(map[string]int)
 	l.renderedItems = make(map[string]renderedItem)
 	for inx, item := range l.items {
  
  
  
    
    @@ -205,42 +205,6 @@ func TestList(t *testing.T) {
 		golden.RequireEqual(t, []byte(l.View()))
 	})
 
-	t.Run("should go to selected item and center", func(t *testing.T) {
-		t.Parallel()
-		items := []Item{}
-		for i := range 30 {
-			content := strings.Repeat(fmt.Sprintf("Item %d\n", i), i+1)
-			content = strings.TrimSuffix(content, "\n")
-			item := NewSelectableItem(content)
-			items = append(items, item)
-		}
-		l := New(items, WithDirectionForward(), WithSize(10, 10), WithSelectedItem(items[4].ID())).(*list[Item])
-		execCmd(l, l.Init())
-
-		// should select the last item
-		assert.Equal(t, items[4].ID(), l.selectedItem)
-
-		golden.RequireEqual(t, []byte(l.View()))
-	})
-
-	t.Run("should go to selected item and center backwards", func(t *testing.T) {
-		t.Parallel()
-		items := []Item{}
-		for i := range 30 {
-			content := strings.Repeat(fmt.Sprintf("Item %d\n", i), i+1)
-			content = strings.TrimSuffix(content, "\n")
-			item := NewSelectableItem(content)
-			items = append(items, item)
-		}
-		l := New(items, WithDirectionBackward(), WithSize(10, 10), WithSelectedItem(items[4].ID())).(*list[Item])
-		execCmd(l, l.Init())
-
-		// should select the last item
-		assert.Equal(t, items[4].ID(), l.selectedItem)
-
-		golden.RequireEqual(t, []byte(l.View()))
-	})
-
 	t.Run("should go to selected item at the beginning", func(t *testing.T) {
 		t.Parallel()
 		items := []Item{}