diff --git a/CHANGELOG.md b/CHANGELOG.md
index e901d67b4..50dc3f19e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
+## Unreleased
+
+### Fixed
+
+- Parameter `animate` from `DataTable.move_cursor` was being ignored https://github.com/Textualize/textual/issues/3840
+
 ## [0.47.1] - 2023-01-05
 
 ### Fixed
diff --git a/src/textual/widgets/_data_table.py b/src/textual/widgets/_data_table.py
index eef090bfb..e2a5a0022 100644
--- a/src/textual/widgets/_data_table.py
+++ b/src/textual/widgets/_data_table.py
@@ -1094,7 +1094,7 @@ class DataTable(ScrollView, Generic[CellType], can_focus=True):
                 self._highlight_column(new_coordinate.column)
             # If the coordinate was changed via `move_cursor`, give priority to its
             # scrolling because it may be animated.
-            self.call_next(self._scroll_cursor_into_view)
+            self.call_after_refresh(self._scroll_cursor_into_view)
 
     def move_cursor(
         self,
@@ -1119,20 +1119,24 @@ class DataTable(ScrollView, Generic[CellType], can_focus=True):
             column: The new column to move the cursor to.
             animate: Whether to animate the change of coordinates.
         """
+
         cursor_row, cursor_column = self.cursor_coordinate
         if row is not None:
             cursor_row = row
         if column is not None:
             cursor_column = column
         destination = Coordinate(cursor_row, cursor_column)
-        self.cursor_coordinate = destination
 
         # Scroll the cursor after refresh to ensure the virtual height
         # (calculated in on_idle) has settled. If we tried to scroll before
         # the virtual size has been set, then it might fail if we added a bunch
         # of rows then tried to immediately move the cursor.
+        # We do this before setting `cursor_coordinate` because its watcher will also
+        # schedule a call to `_scroll_cursor_into_view` without optionally animating.
         self.call_after_refresh(self._scroll_cursor_into_view, animate=animate)
 
+        self.cursor_coordinate = destination
+
     def _highlight_coordinate(self, coordinate: Coordinate) -> None:
         """Apply highlighting to the cell at the coordinate, and post event."""
         self.refresh_coordinate(coordinate)

diff --git a/tests/test_data_table.py b/tests/test_data_table.py
index 70b6ffe47..e09a9c3f9 100644
--- a/tests/test_data_table.py
+++ b/tests/test_data_table.py
@@ -1382,3 +1382,41 @@ async def test_cell_padding_cannot_be_negative():
         assert table.cell_padding == 0
         table.cell_padding = -1234
         assert table.cell_padding == 0
+
+
+async def test_move_cursor_respects_animate_parameter():
+    """Regression test for https://github.com/Textualize/textual/issues/3840
+
+    Make sure that the call to `_scroll_cursor_into_view` from `move_cursor` happens
+    before the call from the watcher method from `cursor_coordinate`.
+    The former should animate because we call it with `animate=True` whereas the later
+    should not.
+    """
+
+    scrolls = []
+
+    class _DataTable(DataTable):
+        def _scroll_cursor_into_view(self, animate=False):
+            nonlocal scrolls
+            scrolls.append(animate)
+            super()._scroll_cursor_into_view(animate)
+
+    class LongDataTableApp(App):
+        def compose(self):
+            yield _DataTable()
+
+        def on_mount(self):
+            dt = self.query_one(_DataTable)
+            dt.add_columns("one", "two")
+            for _ in range(100):
+                dt.add_row("one", "two")
+
+        def key_s(self):
+            table = self.query_one(_DataTable)
+            table.move_cursor(row=99, animate=True)
+
+    app = LongDataTableApp()
+    async with app.run_test() as pilot:
+        await pilot.press("s")
+
+    assert scrolls == [True, False]

DataTable move_cursor animate doesn't do anything?
While working on:
- https://github.com/Textualize/textual/discussions/3606

I wanted to check `animate` for `move_cursor` behaves correctly, but it doesn't seem to do anything?


---

Repro:


```py
from random import randint
from textual.app import App, ComposeResult
from textual.widgets import DataTable, Button
from textual.widgets._data_table import RowKey
from textual.containers import Horizontal
from textual import on
from textual.reactive import Reactive, reactive

ROWS = [
    ("lane", "swimmer", "country", "time"),
    (4, "Joseph Schooling", "Singapore", 50.39),
    (2, "Michael Phelps", "United States", 51.14),
    (5, "Chad le Clos", "South Africa", 51.14),
    (6, "László Cseh", "Hungary", 51.14),
    (3, "Li Zhuhao", "China", 51.26),
    (8, "Mehdy Metella", "France", 51.58),
    (7, "Tom Shields", "United States", 51.73),
    (1, "Aleksandr Sadovnikov", "Russia", 51.84),
    (10, "Darren Burns", "Scotland", 51.84),
]


class TableApp(App):
    CSS = """
    DataTable {
    height: 80%;
    }
    """

    keys: Reactive[RowKey] = reactive([])

    def compose(self) -> ComposeResult:
        yield DataTable(cursor_type="row")
        with Horizontal():
            yield Button("True")
            yield Button("False")

    @on(Button.Pressed)
    def goto(self, event: Button.Pressed):
        row  = randint(0, len(self.keys) - 1)
        print(row)

        animate = str(event.button.label) == "True"
        table = self.query_one(DataTable)
        table.move_cursor(row=row, animate=animate)

    def on_mount(self) -> None:
        table = self.query_one(DataTable)
        table.add_columns(*ROWS[0])
        for _ in range(20):
            keys = table.add_rows(ROWS[1:])
            self.keys.extend(keys)


app = TableApp()
if __name__ == "__main__":
    app.run()
```

---
<!-- This is valid Markdown, do not quote! -->
# Textual Diagnostics

## Versions

| Name    | Value  |
|---------|--------|
| Textual | 0.39.0 |
| Rich    | 13.3.3 |

## Python

| Name           | Value                                             |
|----------------|---------------------------------------------------|
| Version        | 3.11.4                                            |
| Implementation | CPython                                           |
| Compiler       | Clang 14.0.0 (clang-1400.0.29.202)                |
| Executable     | /Users/dave/.pyenv/versions/3.11.4/bin/python3.11 |

## Operating System

| Name    | Value                                                                                                   |
|---------|---------------------------------------------------------------------------------------------------------|
| System  | Darwin                                                                                                  |
| Release | 21.6.0                                                                                                  |
| Version | Darwin Kernel Version 21.6.0: Thu Mar  9 20:08:59 PST 2023; root:xnu-8020.240.18.700.8~1/RELEASE_X86_64 |

## Terminal

| Name                 | Value           |
|----------------------|-----------------|
| Terminal Application | vscode (1.85.0) |
| TERM                 | xterm-256color  |
| COLORTERM            | truecolor       |
| FORCE_COLOR          | *Not set*       |
| NO_COLOR             | *Not set*       |

## Rich Console options

| Name           | Value               |
|----------------|---------------------|
| size           | width=90, height=68 |
| legacy_windows | False               |
| min_width      | 1                   |
| max_width      | 90                  |
| is_terminal    | True                |
| encoding       | utf-8               |
| max_height     | 68                  |
| justify        | None                |
| overflow       | None                |
| no_wrap        | False               |
| highlight      | None                |
| markup         | None                |
| height         | None                |


tests/test_data_table.py::test_move_cursor_respects_animate_parameter
tests/test_data_table.py::test_datatable_message_emission tests/test_data_table.py::test_empty_table_interactions tests/test_data_table.py::test_cursor_movement_with_home_pagedown_etc[True] tests/test_data_table.py::test_cursor_movement_with_home_pagedown_etc[False] tests/test_data_table.py::test_add_rows tests/test_data_table.py::test_add_rows_user_defined_keys tests/test_data_table.py::test_add_row_duplicate_key tests/test_data_table.py::test_add_column_duplicate_key tests/test_data_table.py::test_add_column_with_width tests/test_data_table.py::test_add_columns tests/test_data_table.py::test_add_columns_user_defined_keys tests/test_data_table.py::test_remove_row tests/test_data_table.py::test_remove_row_and_update tests/test_data_table.py::test_remove_column tests/test_data_table.py::test_remove_column_and_update tests/test_data_table.py::test_clear tests/test_data_table.py::test_column_labels tests/test_data_table.py::test_initial_column_widths tests/test_data_table.py::test_get_cell_returns_value_at_cell tests/test_data_table.py::test_get_cell_invalid_row_key tests/test_data_table.py::test_get_cell_invalid_column_key tests/test_data_table.py::test_get_cell_coordinate_returns_coordinate tests/test_data_table.py::test_get_cell_coordinate_invalid_row_key tests/test_data_table.py::test_get_cell_coordinate_invalid_column_key tests/test_data_table.py::test_get_cell_at_returns_value_at_cell tests/test_data_table.py::test_get_cell_at_exception tests/test_data_table.py::test_get_row tests/test_data_table.py::test_get_row_invalid_row_key tests/test_data_table.py::test_get_row_at tests/test_data_table.py::test_get_row_at_invalid_index[-1] tests/test_data_table.py::test_get_row_at_invalid_index[2] tests/test_data_table.py::test_get_row_index_returns_index tests/test_data_table.py::test_get_row_index_invalid_row_key tests/test_data_table.py::test_get_column tests/test_data_table.py::test_get_column_invalid_key tests/test_data_table.py::test_get_column_at tests/test_data_table.py::test_get_column_at_invalid_index[-1] tests/test_data_table.py::test_get_column_at_invalid_index[5] tests/test_data_table.py::test_get_column_index_returns_index tests/test_data_table.py::test_get_column_index_invalid_column_key tests/test_data_table.py::test_update_cell_cell_exists tests/test_data_table.py::test_update_cell_cell_doesnt_exist tests/test_data_table.py::test_update_cell_invalid_column_key tests/test_data_table.py::test_update_cell_at_coordinate_exists tests/test_data_table.py::test_update_cell_at_coordinate_doesnt_exist tests/test_data_table.py::test_update_cell_at_column_width[A-BB-3] tests/test_data_table.py::test_update_cell_at_column_width[1234567-1234-7] tests/test_data_table.py::test_update_cell_at_column_width[12345-123-5] tests/test_data_table.py::test_update_cell_at_column_width[12345-123456789-9] tests/test_data_table.py::test_coordinate_to_cell_key tests/test_data_table.py::test_coordinate_to_cell_key_invalid_coordinate tests/test_data_table.py::test_datatable_click_cell_cursor tests/test_data_table.py::test_click_row_cursor tests/test_data_table.py::test_click_column_cursor tests/test_data_table.py::test_hover_coordinate tests/test_data_table.py::test_hover_mouse_leave tests/test_data_table.py::test_header_selected tests/test_data_table.py::test_row_label_selected tests/test_data_table.py::test_sort_coordinate_and_key_access tests/test_data_table.py::test_sort_reverse_coordinate_and_key_access tests/test_data_table.py::test_cell_cursor_highlight_events tests/test_data_table.py::test_row_cursor_highlight_events tests/test_data_table.py::test_column_cursor_highlight_events tests/test_data_table.py::test_reuse_row_key_after_clear tests/test_data_table.py::test_reuse_column_key_after_clear tests/test_data_table.py::test_key_equals_equivalent_string tests/test_data_table.py::test_key_doesnt_match_non_equal_string tests/test_data_table.py::test_key_equals_self tests/test_data_table.py::test_key_string_lookup tests/test_data_table.py::test_scrolling_cursor_into_view tests/test_data_table.py::test_move_cursor tests/test_data_table.py::test_unset_hover_highlight_when_no_table_cell_under_mouse tests/test_data_table.py::test_sort_by_all_columns_no_key tests/test_data_table.py::test_sort_by_multiple_columns_no_key tests/test_data_table.py::test_sort_by_function_sum tests/test_data_table.py::test_add_row_auto_height[hey tests/test_data_table.py::test_add_row_auto_height[cell1-1] tests/test_data_table.py::test_add_row_auto_height[cell2-2] tests/test_data_table.py::test_add_row_auto_height[cell3-4] tests/test_data_table.py::test_add_row_auto_height[1\n2\n3\n4\n5\n6\n7-7] tests/test_data_table.py::test_add_row_expands_column_widths tests/test_data_table.py::test_cell_padding_updates_virtual_size tests/test_data_table.py::test_cell_padding_cannot_be_negative