diff --git a/reviewboard/datagrids/builtin_items.py b/reviewboard/datagrids/builtin_items.py
index b4556f6e5c298a304000b0933ce0a10a05aeae34..2ab3ef5824accf748676b86ce577024d1293ec9d 100644
--- a/reviewboard/datagrids/builtin_items.py
+++ b/reviewboard/datagrids/builtin_items.py
@@ -2,7 +2,8 @@ from __future__ import unicode_literals
 
 from django.utils.translation import ugettext_lazy as _
 
-from reviewboard.datagrids.sidebar import BaseSidebarSection, SidebarNavItem
+from reviewboard.datagrids.sidebar import (BaseSidebarItem,
+                                           BaseSidebarSection, SidebarNavItem)
 
 
 class OutgoingSection(BaseSidebarSection):
@@ -111,3 +112,43 @@ class IncomingSection(BaseSidebarSection):
                                  },
                                  icon_name='rb-icon-star-on',
                                  count=group['incoming_request_count'])
+
+
+class UserProfileItem(BaseSidebarItem):
+    """Displays the profile for a user in the user page sidebar.
+
+    This will display information such as the name, e-mail address,
+    gravatar, and dates logged in and joined.
+    """
+    template_name = 'datagrids/sidebar_user_info.html'
+
+    def get_extra_context(self):
+        request = self.datagrid.request
+        user = self.datagrid.user
+
+        return {
+            'show_profile': user.is_profile_visible(request.user),
+            'profile_user': user,
+        }
+
+
+class UserGroupsItem(BaseSidebarSection):
+    """Displays the list of groups a user belongs to in the user page sidebar.
+
+    Each group will be clickable, and will navigate to the corresponding
+    group page.
+    """
+    label = _('Groups')
+
+    def get_items(self):
+        request = self.datagrid.request
+
+        groups = (
+            self.datagrid.user.review_groups.accessible(request.user)
+            .filter(local_site=self.datagrid.local_site)
+            .order_by('name'))
+
+        for group in groups:
+            yield SidebarNavItem(self,
+                                 label=group.name,
+                                 url=group.get_absolute_url())
diff --git a/reviewboard/datagrids/grids.py b/reviewboard/datagrids/grids.py
index 066834c499354f11cc329e46d73d574d5907f715..4f846be6b564c723f3d63e5dfb087912cfc530d6 100644
--- a/reviewboard/datagrids/grids.py
+++ b/reviewboard/datagrids/grids.py
@@ -31,7 +31,9 @@ from reviewboard.datagrids.columns import (BugsColumn,
                                            ToMeColumn)
 from reviewboard.datagrids.sidebar import Sidebar, DataGridSidebarMixin
 from reviewboard.datagrids.builtin_items import (IncomingSection,
-                                                 OutgoingSection)
+                                                 OutgoingSection,
+                                                 UserGroupsItem,
+                                                 UserProfileItem)
 from reviewboard.reviews.models import Group, ReviewRequest
 from reviewboard.site.urlresolvers import local_site_reverse
 
@@ -165,7 +167,8 @@ class DashboardDataGrid(DataGridSidebarMixin, ReviewRequestDataGrid):
             OutgoingSection,
             IncomingSection,
         ],
-        default_view_id='incoming')
+        default_view_id='incoming',
+        css_classes=['scrollable'])
 
     def __init__(self, *args, **kwargs):
         local_site = kwargs.get('local_site', None)
@@ -306,3 +309,33 @@ class GroupDataGrid(DataGrid):
     @staticmethod
     def link_to_object(obj, value):
         return obj.get_absolute_url()
+
+
+class UserPageDataGrid(SidebarDataGridMixin, ReviewRequestDataGrid):
+    """A data grid for the user's page.
+
+    This will show the review requests the user has out for review, and
+    display information about the user on the side.
+    """
+    sidebar = Sidebar([
+        UserProfileItem,
+        UserGroupsItem,
+    ])
+
+    def __init__(self, request, user, *args, **kwargs):
+        queryset = ReviewRequest.objects.from_user(
+            user.username,
+            user=request.user,
+            status=None,
+            with_counts=True,
+            local_site=kwargs.get('local_site'),
+            filter_private=True)
+
+        super(UserPageDataGrid, self).__init__(
+            request,
+            queryset=queryset,
+            title=_("%s's review requests") % user.username,
+            *args, **kwargs)
+
+        self.groups = user.review_groups.accessible(request.user)
+        self.user = user
diff --git a/reviewboard/datagrids/views.py b/reviewboard/datagrids/views.py
index 009df93a52e650ffbc76a184668505bb5c8981e3..f72de60d80a6d9827c6bfcc5376490e0b6130acd 100644
--- a/reviewboard/datagrids/views.py
+++ b/reviewboard/datagrids/views.py
@@ -12,7 +12,8 @@ from reviewboard.extensions.hooks import DashboardHook, UserPageSidebarHook
 from reviewboard.datagrids.grids import (DashboardDataGrid,
                                          GroupDataGrid,
                                          ReviewRequestDataGrid,
-                                         SubmitterDataGrid)
+                                         SubmitterDataGrid,
+                                         UserPageDataGrid)
 from reviewboard.reviews.models import Group, ReviewRequest
 from reviewboard.reviews.views import _render_permission_denied
 from reviewboard.site.decorators import check_local_site_access
@@ -126,7 +127,7 @@ def group_members(request,
 @check_local_site_access
 def submitter(request,
               username,
-              template_name='datagrids/user_page.html',
+              template_name='datagrids/datagrid.html',
               local_site=None):
     """
     A list of review requests owned by a particular user.
@@ -140,23 +141,8 @@ def submitter(request,
     else:
         user = get_object_or_404(User, username=username)
 
-    datagrid = ReviewRequestDataGrid(
-        request,
-        ReviewRequest.objects.from_user(username,
-                                        user=request.user,
-                                        status=None,
-                                        with_counts=True,
-                                        local_site=local_site,
-                                        filter_private=True),
-        _("%s's review requests") % username,
-        local_site=local_site)
-
-    return datagrid.render_to_response(template_name, extra_context={
-        'show_profile': user.is_profile_visible(request.user),
-        'sidebar_hooks': UserPageSidebarHook.hooks,
-        'viewing_user': user,
-        'groups': user.review_groups.accessible(request.user),
-    })
+    datagrid = UserPageDataGrid(request, user, local_site=local_site)
+    return datagrid.render_to_response(template_name)
 
 
 @check_login_required
diff --git a/reviewboard/static/rb/css/dashboard.less b/reviewboard/static/rb/css/dashboard.less
index b72a13daf3f6843ad3eebcc67eb858d699b6e10a..271a7f1832f07acc0025976d7a6543e3e560c224 100644
--- a/reviewboard/static/rb/css/dashboard.less
+++ b/reviewboard/static/rb/css/dashboard.less
@@ -115,11 +115,18 @@
 }
 
 #dashboard_sidebar {
-  position: absolute;
+  float: left;
+  position: left;
   top: 0;
   bottom: 1px;
-  overflow-y: auto;
+  position: left;
   width: @dashboard-sidebar-width;
+
+  &.scrollable {
+    float: none;
+    overflow-y: auto;
+    position: absolute;
+  }
 }
 
 #dashboard-navbar {
@@ -223,18 +230,8 @@
   .border-radius(@box-inner-border-radius);
 }
 
-.user-dashboard #dashboard_sidebar {
-  position: relative;
-  float: left;
-
-  tr {
-    background: transparent;
-  }
-
-  .header {
-    font-weight: bold;
-    padding-top: 15px;
-  }
+#dashboard-navbar #user_page_profile {
+  margin-bottom: 1em;
 
   .nickname {
     font-size: 1.4em;
@@ -243,7 +240,6 @@
   }
 
   .email, .group {
-    text-decoration: underline;
     color: #0000C0;
   }
 
@@ -252,7 +248,7 @@
   }
 
   .logged-in {
-    padding-top: 1.5em;
+    margin-top: 1.5em;
   }
 }
 
diff --git a/reviewboard/templates/datagrids/sidebar_user_info.html b/reviewboard/templates/datagrids/sidebar_user_info.html
new file mode 100644
index 0000000000000000000000000000000000000000..389f497dc7368ef8e609e8f9118adb1fc3e6e663
--- /dev/null
+++ b/reviewboard/templates/datagrids/sidebar_user_info.html
@@ -0,0 +1,37 @@
+{% load gravatars i18n tz %}
+
+<li id="user_page_profile">
+ <div class="row">
+  {% gravatar profile_user 175 %}
+ </div>
+
+ <div class="row">
+  <h2 class="nickname">{{profile_user.username}}</h2>
+ </div>
+
+{% if show_profile %}
+ <div class="row fn">
+  {{profile_user.first_name}} {{profile_user.last_name}}
+ </div>
+
+{%  if request.user.is_authenticated %}
+ <div class="row">
+  <a class="email" href="mailto:{{profile_user.email}}">{{profile_user.email}}</a>
+ </div>
+{%  endif %}
+
+{%  localtime on %}
+ <div class="row logged-in">
+{%   blocktrans with profile_user.last_login|localtime|date as last_login_date %}
+  Last logged in {{last_login_date}}
+{%   endblocktrans %}
+ </div>
+
+ <div class="row joined">
+{%   blocktrans with profile_user.date_joined|localtime|date as joined_date %}
+  Joined {{joined_date}}
+{%   endblocktrans %}
+ </div>
+{%  endlocaltime %}
+{% endif %}{# show_profile #}
+</li>
diff --git a/reviewboard/templates/datagrids/user_page.html b/reviewboard/templates/datagrids/user_page.html
deleted file mode 100644
index b6d8589e370aef1ad604077fbe690618c0b2c40e..0000000000000000000000000000000000000000
--- a/reviewboard/templates/datagrids/user_page.html
+++ /dev/null
@@ -1,74 +0,0 @@
-{% extends "datagrid/datagrid.html" %}
-{% load djblets_deco %}
-{% load djblets_utils %}
-{% load i18n %}
-{% load reviewtags %}
-{% load gravatars %}
-{% load tz %}
-{% block title %}{{viewing_user|user_displayname}}{% endblock %}
-
-{% block content %}
-{% box "dashboard user-dashboard" %}
-<div id="dashboard-wrapper">
- <div id="dashboard_sidebar">
-  <table class="datagrid" id="dashboard-navbar">
-   <colgroup>
-    <col class="summary" />
-    <col class="count" />
-   </colgroup>
-   <tbody>
-    <tr>
-     <td class="logo">{% gravatar viewing_user 175 %}</td>
-    </tr>
-    <tr>
-     <td><h2 class="nickname">{{viewing_user.username}}</h2></td>
-    </tr>
-{% if show_profile %}
-    <tr>
-     <td class="fn">{{viewing_user.first_name}} {{viewing_user.last_name}}</td>
-    </tr>
-{% if request.user.is_authenticated %}
-    <tr>
-     <td><a class="email" href="mailto:{{viewing_user.email}}">{{viewing_user.email}}</a></td>
-    </tr>
-{% endif %}
-    <tr>
-     <td class="logged-in">Last logged in {% localtime on %}{{viewing_user.last_login|date:"F jS, Y"}}{% endlocaltime %}</td>
-    </tr>
-    <tr>
-     <td class="joined">Joined {% localtime on %}{{viewing_user.date_joined|date:"F jS, Y"}}{% endlocaltime %}</td>
-    </tr>
-    <tr>
-     <td>
-      <p><label>{% trans "Groups:" %}</label></p>
-{% for group in groups %}
-      <a class="group" href="{% url 'group' group %}">{{group}}</a>{% if not forloop.last %}, {% endif %}
-{% endfor %}
-     </td>
-    </tr>
- {% for hook in sidebar_hooks %}
-  {%  for main_entry in hook.entries %}
-    <tr>
-     <td class="summary main-item">
-      <a href="{{main_entry.url}}">{{main_entry.label}}</a>
-     </td>
-    </tr>
-   {%   for sub_entry in main_entry.subitems %}
-    <tr>
-     <td class="summary sub-item">
-      <a href="{{sub_entry.url}}">{{sub_entry.label}}</a>
-     </td>
-    </tr>
-   {%   endfor %}
-  {%  endfor %}
- {% endfor %}
-{% endif %}
-   </tbody>
-  </table>
- </div>
- <div id="dashboard-main" class="clearfix">
-  {{datagrid.render_listview}}
- </div>
-</div>
-{% endbox %}
-{% endblock %}
