diff --git a/reviewboard/datagrids/columns.py b/reviewboard/datagrids/columns.py
index a1eaeba051a8480761c34d5d1749d2a6d5d95fd0..e1a1c40a759fd76a7d87df803c2a8aab6e8185a4 100644
--- a/reviewboard/datagrids/columns.py
+++ b/reviewboard/datagrids/columns.py
@@ -624,6 +624,7 @@ class SummaryColumn(Column):
             css_class='summary',
             sortable=True,
             *args, **kwargs)
+        self.cell_template = 'datagrids/summary_cell.html'
 
     def augment_queryset(self, state, queryset):
         """Add additional queries to the queryset."""
diff --git a/reviewboard/extensions/hooks.py b/reviewboard/extensions/hooks.py
index 15bd2ecde566593585dad8e34aff5451f932dc13..ad4e2f186fb44dc267ced126fd9661f76609d831 100644
--- a/reviewboard/extensions/hooks.py
+++ b/reviewboard/extensions/hooks.py
@@ -1109,6 +1109,106 @@ class UserInfoboxHook(ExtensionHook):
 
 
 @six.add_metaclass(ExtensionHookPoint)
+class ReviewRequestInfoboxHook(ExtensionHook):
+    """A hook for adding information to the review request infobox.
+
+    Extensions can use this hook to add additional pieces of data to the box
+    which pops up when hovering the mouse over a review request.
+    """
+
+    def __init__(self, extension, template_name=None):
+        """Initialize the hook.
+
+        Args:
+            extension (reviewboard.extensions.base.Extension):
+                The extension instance.
+
+            template_name (unicode):
+                The template to render with the default :py:func:`render`
+                method.
+        """
+        super(ReviewRequestInfoboxHook, self).__init__(extension)
+
+        self.template_name = template_name
+
+    def get_extra_context(self, review_request, request, local_site):
+        """Return extra context to use when rendering the template.
+
+        This may be overridden in order to make use of the default
+        :py:func:`render` method.
+
+        Args:
+            review_request (reviewboard.reviews.models.ReviewRequest):
+                The review request that the infobox is being shown for.
+
+            request (django.http.HttpRequest):
+                The request for the infobox view.
+
+            local_site (reviewboard.site.models.LocalSite):
+                The local site, if any.
+
+        Returns:
+            dict:
+            Additional context to include when rendering the template.
+        """
+        return {}
+
+    def get_etag_data(self, review_request, request, local_site):
+        """Return data to be included in the review request infobox ETag.
+
+        The infobox view uses an ETag to enable browser caching of the content.
+        If the extension returns data which can change, this method should
+        return a string which is unique to that data.
+
+        Args:
+            review_request (reviewboard.reviews.models.ReviewRequest):
+                The review request that the infobox is being shown for.
+
+            request (django.http.HttpRequest):
+                The request for the infobox view.
+
+            local_site (reviewboard.site.models.LocalSite):
+                The local site, if any.
+
+        Returns:
+            unicode:
+            A string to be included in the ETag for the view.
+        """
+        return ''
+
+    def render(self, review_request, request, local_site):
+        """Return content to include in the review request infobox.
+
+        This may be overridden in the case where providing a custom template
+        and overriding :py:func:`get_extra_context` is insufficient.
+
+        Args:
+            review_request (reviewboard.reviews.models.ReviewRequest):
+                The review request that the infobox is being shown for.
+
+            request (django.http.HttpRequest):
+                The request for the infobox view.
+
+            local_site (reviewboard.site.models.LocalSite):
+                The local site, if any.
+
+        Returns:
+            django.utils.safestring.SafeText:
+            Text to include in the infobox HTML.
+        """
+        context = {
+            'review_request': review_request,
+        }
+        context.update(
+            self.get_extra_context(review_request, request, local_site))
+
+        assert self.template_name is not None
+
+        return render_to_string(self.template_name,
+                                RequestContext(request, context))
+
+
+@six.add_metaclass(ExtensionHookPoint)
 class UserPageSidebarItemsHook(DataGridSidebarItemsHook):
     """A hook for adding items to the sidebar of the user page.
 
diff --git a/reviewboard/reviews/tests/test_views.py b/reviewboard/reviews/tests/test_views.py
index 0b774bea0a742a3d5792bd312563f71960f331e1..3c07952bbd6505824672b5d59ce549f32ca4f009 100644
--- a/reviewboard/reviews/tests/test_views.py
+++ b/reviewboard/reviews/tests/test_views.py
@@ -1169,3 +1169,64 @@ class UserInfoboxTests(TestCase):
         user.save()
 
         self.client.get(local_site_reverse('user-infobox', args=['test']))
+
+
+class ReviewRequestInfoboxTests(TestCase):
+    """ Tests for reviewboard.reviews.views.review_request_infobox."""
+    def test_get(self):
+        """Testing review_request_infobox"""
+        username = 'test'
+        summary = 'This is a test summary'
+        description = 'This is my description'
+        testing_done = 'Some testing'
+
+        user = User.objects.create_user(username, 'test@example.com')
+        user.first_name = 'Testy'
+        user.last_name = 'McTest'
+        full_name = user.first_name + " " + user.last_name
+        user.save()
+
+        review_request = self.create_review_request(
+            publish=True,
+            submitter=username,
+            summary=summary,
+            description=description,
+            testing_done=testing_done)
+
+        response = self.client.get(local_site_reverse(
+            'review-request-infobox',
+            kwargs={'review_request_id': review_request.pk}))
+
+        self.assertEqual(response.context['summary'], review_request.summary)
+        self.assertEqual(response.context['description'],
+                         review_request.description)
+        self.assertEqual(response.context['submitter'], full_name)
+
+    def test_140_char(self):
+        """Testing review_request_infobox
+        truncates descriptions longer than 140 characters
+        """
+        username = 'test'
+        summary = 'This is a test summary'
+        description = ('This is the description for the test review request '
+                       'that is longer than 140 characters, it should show up '
+                       'truncated to 140 characters instead of continuing and '
+                       'running over.')
+        testing_done = 'Some testing'
+
+        user = User.objects.create_user(username, 'test@example.com')
+        user.save()
+
+        review_request = self.create_review_request(
+            publish=True,
+            submitter=username,
+            summary=summary,
+            description=description,
+            testing_done=testing_done)
+
+        response = self.client.get(local_site_reverse(
+            'review-request-infobox',
+            kwargs={'review_request_id': review_request.pk}))
+
+        self.assertEqual(response.context['description'],
+                         review_request.description[0:140])
diff --git a/reviewboard/reviews/urls.py b/reviewboard/reviews/urls.py
index 9a1822d2d0f6a04fd80b7d8deb15893cbdd4975d..b164f998e2cd8b29657dfe75313bf93662ba7630 100644
--- a/reviewboard/reviews/urls.py
+++ b/reviewboard/reviews/urls.py
@@ -64,6 +64,10 @@ bugs_urls = patterns(
 review_request_urls = patterns(
     'reviewboard.reviews.views',
 
+    # Review request info box
+    url(r'^infobox/$', 'review_request_infobox',
+        name='review-request-infobox'),
+
     # Review request detail
     url(r'^$', 'review_detail', name="review-request-detail"),
 
diff --git a/reviewboard/reviews/views.py b/reviewboard/reviews/views.py
index 93282ffbcadbc2dc8e913ea701c48004dd7858da..78631593ab00f536437d0de5d6999b5c0b45db39 100644
--- a/reviewboard/reviews/views.py
+++ b/reviewboard/reviews/views.py
@@ -1451,6 +1451,87 @@ def user_infobox(request, username,
 
 @check_login_required
 @check_local_site_access
+def review_request_infobox(request, review_request_id,
+                           template_name='reviews/review_request_infobox.html',
+                           local_site=None):
+    """Display a review request info popup.
+
+    The infobox is meant to be embedded in other pages, rather than being
+    a standalone page.
+
+    Args:
+        request (django.http.HttpResponse):
+            The HTTP Request for the review request infobox.
+
+        review_request_id (int):
+            The ID of the review request to show the infobox for.
+
+        template_name (unicode):
+            The template used to create the review request infobox HTML.
+
+        local_site (reviewboard.site.models.LocalSite):
+            The local site, if any.
+
+    Returns:
+        HTTP response of the review request infobox.
+    """
+    from reviewboard.extensions.hooks import ReviewRequestInfoboxHook
+
+    review_request, response = \
+        _find_review_request(request, review_request_id, local_site)
+
+    if not review_request:
+        return response
+
+    etag_data = [
+        six.text_type(review_request.id),
+        review_request.summary,
+        review_request.description,
+        six.text_type(review_request.submitter),
+        six.text_type(review_request.time_added),
+        six.text_type(review_request.last_updated),
+    ]
+
+    for hook in ReviewRequestInfoboxHook.hooks:
+        try:
+            etag_data.append(hook.get_etag_data(review_request, request,
+                                                local_site))
+        except Exception as e:
+            logging.exception('Error when running ReviewRequestInfoboxHook.'
+                              'get_etag_data method in extension "%s": %s',
+                              hook.extension.id, e)
+
+    etag = encode_etag(':'.join(etag_data))
+
+    if etag_if_none_match(request, etag):
+        return HttpResponseNotModified()
+
+    extra_content = []
+
+    for hook in ReviewRequestInfoboxHook.hooks:
+        try:
+            extra_content.append(hook.render(review_request, request,
+                                             local_site))
+        except Exception as e:
+            logging.exception('Error when running UserInfoboxHook.'
+                              'render method in extension "%s": %s',
+                              hook.extension.id, e)
+
+    response = render_to_response(template_name, RequestContext(request, {
+        'extra_content': mark_safe(''.join(extra_content)),
+        'review_request_id': review_request.id,
+        'summary': review_request.summary,
+        'description': review_request.description[0:140],
+        'submitter': review_request.submitter.get_full_name(),
+        'submitter_user': review_request.submitter,
+    }))
+    set_etag(response, etag)
+
+    return response
+
+
+@check_login_required
+@check_local_site_access
 def bug_url(request, review_request_id, bug_id, local_site=None):
     """Redirects user to bug tracker issue page."""
     review_request, response = \
diff --git a/reviewboard/static/rb/css/common.less b/reviewboard/static/rb/css/common.less
index fd46171fc3c12d367fc6d7f41fcc38949e1f2ac9..0175c70157a237e9e5d0949700a382b9ae5a74b4 100644
--- a/reviewboard/static/rb/css/common.less
+++ b/reviewboard/static/rb/css/common.less
@@ -578,6 +578,52 @@
 
 
 /****************************************************************************
+ * Review request page hover
+ ****************************************************************************/
+
+.review_request_infobox {
+  font-size: 12px;
+
+  a {
+    text-decoration: none;
+
+    &:hover {
+      text-decoration: underline;
+    }
+  }
+
+  h3 {
+    margin-top: 0;
+    padding-top: 0;
+
+    a {
+      color: inherit;
+    }
+  }
+
+  .infobox-extra {
+    border-top: 1px solid #666;
+    box-sizing: border-box;
+    padding: 0.5em;
+    width: 100%;
+  }
+
+  .infobox-text {
+    box-sizing: border-box;
+    color: black;
+    display: inline-block;
+    min-width: 20em;
+    max-width: 40em;
+    padding: 0.75em;
+    position: relative;
+    word-wrap: break-word;
+    vertical-align: top;
+    }
+
+}
+
+
+/****************************************************************************
  * Bug hover
  ****************************************************************************/
 
@@ -599,7 +645,7 @@
   }
 }
 
-.user_infobox, .bug_infobox {
+.user_infobox, .bug_infobox, .review_request_infobox {
   background: #F9F9F9;
   border: 1px #666666 solid;
   border-radius: 3px;
diff --git a/reviewboard/static/rb/js/common.es6.js b/reviewboard/static/rb/js/common.es6.js
index 69a153e12fc346b756798e15e117c5ed3730e9bf..64451f6d3465ac5443234797045e31ca05826bee 100644
--- a/reviewboard/static/rb/js/common.es6.js
+++ b/reviewboard/static/rb/js/common.es6.js
@@ -2,8 +2,8 @@ window.RB = {};
 
 
 /*
- * Bug and user infoboxes. These are shown when hovering over links to users
- * and bugs.
+ * Bug, user, and review request infoboxes. These are shown when hovering over
+ * links to users, bugs, and review requests.
  */
 $.fn.infobox = function(id) {
     let $el = $(`.${id}`);
@@ -31,6 +31,10 @@ $.fn.user_infobox = function() {
     return this;
 };
 
+$.fn.review_request_infobox = function() {
+    $(this).infobox('review_request_infobox');
+    return this;
+};
 
 $.fn.bug_infobox = function() {
     $(this).infobox('bug_infobox');
@@ -40,6 +44,7 @@ $.fn.bug_infobox = function() {
 
 $(document).ready(function() {
     $('.user').user_infobox();
+    $('.summary-text').review_request_infobox();
     $('.bug').bug_infobox();
     $('time.timesince').timesince();
 
diff --git a/reviewboard/static/rb/js/ui/views/infoboxView.es6.js b/reviewboard/static/rb/js/ui/views/infoboxView.es6.js
index 11583724e0f40e7c800b3e19e97973ede540fe3d..9db3c576222d8de66554834c1625b91905021e94 100644
--- a/reviewboard/static/rb/js/ui/views/infoboxView.es6.js
+++ b/reviewboard/static/rb/js/ui/views/infoboxView.es6.js
@@ -1,9 +1,9 @@
 /**
  * An infobox pop-up.
  *
- * This binds to an ``<a>`` element (expected to be either a bug or a user,
- * right now), and loads the contents of the infobox from a URL built from that
- * element's ``href`` attribute plus the string "infobox/".
+ * This binds to an ``<a>`` element (expected to be a bug, user, or review
+ * request), and loads the contents of the infobox from a URL built
+ * from that element's ``href`` attribute plus the string "infobox/".
  */
 RB.InfoboxView = Backbone.View.extend({
     /**
diff --git a/reviewboard/templates/datagrids/summary_cell.html b/reviewboard/templates/datagrids/summary_cell.html
new file mode 100644
index 0000000000000000000000000000000000000000..7850cbc44752c3b321d631440156670ac29c63c1
--- /dev/null
+++ b/reviewboard/templates/datagrids/summary_cell.html
@@ -0,0 +1,7 @@
+<td{% if css_class %} class="{{css_class}}"{% endif %}{% if column_state.last %} colspan="2"{% endif %}{% if url and column.cell_clickable %} onclick="javascript:window.location = '{{url|escapejs}}'; return false;"{% endif %}>
+{% if url %}
+ <a href="{{url}}"><div><a class="summary-text" href ="{{url}}">{{data}}</a></div></a>
+{% else %}
+ {{data}}
+{% endif %}
+</td>
diff --git a/reviewboard/templates/reviews/review_request_infobox.html b/reviewboard/templates/reviews/review_request_infobox.html
new file mode 100644
index 0000000000000000000000000000000000000000..91311d5b2f5ecce41a69a068be8878e23610abb2
--- /dev/null
+++ b/reviewboard/templates/reviews/review_request_infobox.html
@@ -0,0 +1,12 @@
+<div class="infobox-content {{extra_content|yesno:'has-extra-content,'}}">
+ <div class="infobox-text">
+  <h3><a href="{% url 'review-request-detail' review_request_id %}">{{summary}}</a></h3>
+  <p class="review_request_description">{{description|truncatechars:140}}</p>
+  <p><a href="{% url 'user' submitter_user %}">{{submitter}}</a></p>
+  </p>
+ </div>
+
+{% if extra_content %}
+  <div class="infobox-extra">{{extra_content}}</div>
+{% endif %}
+</div>
