diff --git a/lms/djangoapps/courseware/courses.py b/lms/djangoapps/courseware/courses.py
index 18d5e669688c1ea98c54b818cc4d7a54af79255d..2c7cd36de5530c081a44083e2370d897f10dc7c6 100644
--- a/lms/djangoapps/courseware/courses.py
+++ b/lms/djangoapps/courseware/courses.py
@@ -22,6 +22,7 @@ from courseware.module_render import get_module
 from django.conf import settings
 from django.core.urlresolvers import reverse
 from django.http import Http404, QueryDict
+from enrollment.api import get_course_enrollment_details
 from edxmako.shortcuts import render_to_string
 from fs.errors import ResourceNotFoundError
 from lms.djangoapps.courseware.courseware_access_exception import CoursewareAccessException
@@ -173,6 +174,30 @@ def can_self_enroll_in_course(course_key):
     return True
 
 
+def course_open_for_self_enrollment(course_key):
+    """
+    For a given course_key, determine if the course is available for enrollment
+    """
+    # Check to see if learners can enroll themselves.
+    if not can_self_enroll_in_course(course_key):
+        return False
+
+    # Check the enrollment start and end dates.
+    course_details = get_course_enrollment_details(unicode(course_key))
+    now = datetime.now().replace(tzinfo=pytz.UTC)
+    start = course_details['enrollment_start']
+    end = course_details['enrollment_end']
+
+    start = start if start is not None else now
+    end = end if end is not None else now
+
+    # If we are not within the start and end date for enrollment.
+    if now < start or end < now:
+        return False
+
+    return True
+
+
 def find_file(filesystem, dirs, filename):
     """
     Looks for a filename in a list of dirs on a filesystem, in the specified order.
diff --git a/lms/djangoapps/courseware/tests/test_courses.py b/lms/djangoapps/courseware/tests/test_courses.py
index a8ccccc8c44ab9184be61c105a6bb5e8606ad056..f9229dbda57bc20a61f2fd8d1e751c441888ca46 100644
--- a/lms/djangoapps/courseware/tests/test_courses.py
+++ b/lms/djangoapps/courseware/tests/test_courses.py
@@ -4,8 +4,10 @@ Tests for course access
 """
 import itertools
 
+import datetime
 import ddt
 import mock
+import pytz
 from django.conf import settings
 from django.core.urlresolvers import reverse
 from django.test.client import RequestFactory
@@ -13,6 +15,7 @@ from django.test.utils import override_settings
 from nose.plugins.attrib import attr
 
 from courseware.courses import (
+    course_open_for_self_enrollment,
     get_cms_block_link,
     get_cms_course_link,
     get_course_about_section,
@@ -322,6 +325,52 @@ class CoursesRenderTest(ModuleStoreTestCase):
             self.assertIn("this module is temporarily unavailable", course_about)
 
 
+class CourseEnrollmentOpenTests(ModuleStoreTestCase):
+    def setUp(self):
+        super(CourseEnrollmentOpenTests, self).setUp()
+        self.now = datetime.datetime.now().replace(tzinfo=pytz.UTC)
+
+    def test_course_enrollment_open(self):
+        start = self.now - datetime.timedelta(days=1)
+        end = self.now + datetime.timedelta(days=1)
+        course = CourseFactory(enrollment_start=start, enrollment_end=end)
+        self.assertTrue(course_open_for_self_enrollment(course.id))
+
+    def test_course_enrollment_closed_future(self):
+        start = self.now + datetime.timedelta(days=1)
+        end = self.now + datetime.timedelta(days=2)
+        course = CourseFactory(enrollment_start=start, enrollment_end=end)
+        self.assertFalse(course_open_for_self_enrollment(course.id))
+
+    def test_course_enrollment_closed_past(self):
+        start = self.now - datetime.timedelta(days=2)
+        end = self.now - datetime.timedelta(days=1)
+        course = CourseFactory(enrollment_start=start, enrollment_end=end)
+        self.assertFalse(course_open_for_self_enrollment(course.id))
+
+    def test_course_enrollment_dates_missing(self):
+        course = CourseFactory()
+        self.assertTrue(course_open_for_self_enrollment(course.id))
+
+    def test_course_enrollment_dates_missing_start(self):
+        end = self.now + datetime.timedelta(days=1)
+        course = CourseFactory(enrollment_end=end)
+        self.assertTrue(course_open_for_self_enrollment(course.id))
+
+        end = self.now - datetime.timedelta(days=1)
+        course = CourseFactory(enrollment_end=end)
+        self.assertFalse(course_open_for_self_enrollment(course.id))
+
+    def test_course_enrollment_dates_missing_end(self):
+        start = self.now - datetime.timedelta(days=1)
+        course = CourseFactory(enrollment_start=start)
+        self.assertTrue(course_open_for_self_enrollment(course.id))
+
+        start = self.now + datetime.timedelta(days=1)
+        course = CourseFactory(enrollment_start=start)
+        self.assertFalse(course_open_for_self_enrollment(course.id))
+
+
 @attr(shard=1)
 @ddt.ddt
 class CourseInstantiationTests(ModuleStoreTestCase):
diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py
index e51675b54409570f4a3c88c79fb8a9e4bbc0a42b..691792de19f36bf0ef364d273cef3b7af1beab76 100644
--- a/lms/djangoapps/courseware/views/views.py
+++ b/lms/djangoapps/courseware/views/views.py
@@ -19,6 +19,7 @@ from courseware.access import has_access, has_ccx_coach_role
 from courseware.access_utils import check_course_open_for_learner
 from courseware.courses import (
     can_self_enroll_in_course,
+    course_open_for_self_enrollment,
     get_course,
     get_course_overview_with_access,
     get_course_with_access,
@@ -312,6 +313,7 @@ def course_info(request, course_id):
             'request': request,
             'masquerade_user': user,
             'course_id': course_key.to_deprecated_string(),
+            'url_to_enroll': CourseTabView.url_to_enroll(course_key),
             'cache': None,
             'course': course,
             'staff_access': staff_access,
@@ -321,7 +323,6 @@ def course_info(request, course_id):
             'show_enroll_banner': show_enroll_banner,
             'user_is_enrolled': user_is_enrolled,
             'dates_fragment': dates_fragment,
-            'url_to_enroll': CourseTabView.url_to_enroll(course_key),
             'course_tools': course_tools,
         }
         context.update(
@@ -449,15 +450,22 @@ class CourseTabView(EdxFragmentView):
                 )
             )
         elif not is_enrolled and not is_staff:
-            PageLevelMessages.register_warning_message(
-                request,
-                Text(_('You must be enrolled in the course to see course content. {enroll_link}.')).format(
-                    enroll_link=HTML('<a href="{url_to_enroll}">{enroll_link_label}</a>').format(
-                        url_to_enroll=CourseTabView.url_to_enroll(course_key),
-                        enroll_link_label=_("Enroll now"),
+            # Only show enroll button if course is open for enrollment.
+            if course_open_for_self_enrollment(course_key):
+                enroll_message = _('You must be enrolled in the course to see course content. \
+                        {enroll_link_start}Enroll now{enroll_link_end}.')
+                PageLevelMessages.register_warning_message(
+                    request,
+                    Text(enroll_message).format(
+                        enroll_link_start=HTML('<button class="enroll-btn btn-link">'),
+                        enroll_link_end=HTML('</button>')
                     )
                 )
-            )
+            else:
+                PageLevelMessages.register_warning_message(
+                    request,
+                    Text(_('You must be enrolled in the course to see course content.'))
+                )
 
     @staticmethod
     def handle_exceptions(request, course, exception):
diff --git a/openedx/features/course_experience/static/course_experience/fixtures/enrollment-button.html b/openedx/features/course_experience/static/course_experience/fixtures/enrollment-button.html
new file mode 100644
index 0000000000000000000000000000000000000000..1e55c18cb7e91d867f5a48ec124f2b8ff8ca6848
--- /dev/null
+++ b/openedx/features/course_experience/static/course_experience/fixtures/enrollment-button.html
@@ -0,0 +1 @@
+<button class="enroll-btn btn-link">Enroll Now</button>
diff --git a/openedx/features/course_experience/static/course_experience/js/Enrollment.js b/openedx/features/course_experience/static/course_experience/js/Enrollment.js
new file mode 100644
index 0000000000000000000000000000000000000000..e28fd5e06370aebc9158059816079f6c36f04a6e
--- /dev/null
+++ b/openedx/features/course_experience/static/course_experience/js/Enrollment.js
@@ -0,0 +1,45 @@
+
+/*
+ * Course Enrollment on the Course Home page
+ */
+export class CourseEnrollment {  // eslint-disable-line import/prefer-default-export
+  /**
+   * Redirect to a URL.  Mainly useful for mocking out in tests.
+   * @param  {string} url The URL to redirect to.
+   */
+  static redirect(url) {
+    window.location.href = url;
+  }
+
+  static refresh() {
+    window.location.reload(false);
+  }
+
+  static createEnrollment(courseId) {
+    const data = JSON.stringify({
+      course_details: { course_id: courseId },
+    });
+    const enrollmentAPI = '/api/enrollment/v1/enrollment';
+    const trackSelection = '/course_modes/choose/';
+
+    return () =>
+      $.ajax(
+        {
+          type: 'POST',
+          url: enrollmentAPI,
+          data,
+          contentType: 'application/json',
+        }).done(() => {
+          window.analytics.track('edx.bi.user.course-home.enrollment');
+          CourseEnrollment.refresh();
+        }).fail(() => {
+          // If the simple enrollment we attempted failed, go to the track selection page,
+          // which is better for handling more complex enrollment situations.
+          CourseEnrollment.redirect(trackSelection + courseId);
+        });
+  }
+
+  constructor(buttonClass, courseId) {
+    $(buttonClass).click(CourseEnrollment.createEnrollment(courseId));
+  }
+}
diff --git a/openedx/features/course_experience/static/course_experience/js/spec/Enrollment_spec.js b/openedx/features/course_experience/static/course_experience/js/spec/Enrollment_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..6220736b89c1790b1bf57ca7ae5a9dfa2c746f12
--- /dev/null
+++ b/openedx/features/course_experience/static/course_experience/js/spec/Enrollment_spec.js
@@ -0,0 +1,48 @@
+/* globals $, loadFixtures */
+
+import {
+  expectRequest,
+  requests as mockRequests,
+  respondWithJson,
+  respondWithError,
+} from 'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers';
+import { CourseEnrollment } from '../Enrollment';
+
+
+describe('CourseEnrollment tests', () => {
+  describe('Ensure button behavior', () => {
+    const endpointUrl = '/api/enrollment/v1/enrollment';
+    const courseId = 'course-v1:edX+DemoX+Demo_Course';
+    const enrollButtonClass = '.enroll-btn';
+
+    window.analytics = jasmine.createSpyObj('analytics', ['page', 'track', 'trackLink']);
+
+    beforeEach(() => {
+      loadFixtures('course_experience/fixtures/enrollment-button.html');
+      new CourseEnrollment('.enroll-btn', courseId);  // eslint-disable-line no-new
+    });
+    it('Verify that we reload on success', () => {
+      const requests = mockRequests(this);
+      $(enrollButtonClass).click();
+      expectRequest(
+        requests,
+        'POST',
+        endpointUrl,
+        `{"course_details":{"course_id":"${courseId}"}}`,
+      );
+      spyOn(CourseEnrollment, 'refresh');
+      respondWithJson(requests);
+      expect(CourseEnrollment.refresh).toHaveBeenCalled();
+      expect(window.analytics.track).toHaveBeenCalled();
+      requests.restore();
+    });
+    it('Verify that we redirect to track selection on fail', () => {
+      const requests = mockRequests(this);
+      $(enrollButtonClass).click();
+      spyOn(CourseEnrollment, 'redirect');
+      respondWithError(requests, 403);
+      expect(CourseEnrollment.redirect).toHaveBeenCalled();
+      requests.restore();
+    });
+  });
+});
diff --git a/openedx/features/course_experience/templates/course_experience/course-home-fragment.html b/openedx/features/course_experience/templates/course_experience/course-home-fragment.html
index e8fb3d8dd8a96ca99d45825414f4b82a780700b6..93e38c167017c3947d9e58d73f8272d9e6514277 100644
--- a/openedx/features/course_experience/templates/course_experience/course-home-fragment.html
+++ b/openedx/features/course_experience/templates/course_experience/course-home-fragment.html
@@ -112,3 +112,7 @@ from openedx.features.course_experience import UNIFIED_COURSE_TAB_FLAG, SHOW_REV
         courseToolLink: ".course-tool-link",
     });
 </%static:webpack>
+
+<%static:webpack entry="Enrollment">
+    new CourseEnrollment('.enroll-btn', '${course_key | n, js_escaped_string}');
+</%static:webpack>
diff --git a/webpack.config.js b/webpack.config.js
index b34e53ce7b94ae89b7b5781bc7b1937d47a1ab12..9ba5257aea6f70e4b47bf95b83d023c42d272063 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -23,6 +23,7 @@ var wpconfig = {
         CourseSock: './openedx/features/course_experience/static/course_experience/js/CourseSock.js',
         CourseTalkReviews: './openedx/features/course_experience/static/course_experience/js/CourseTalkReviews.js',
         WelcomeMessage: './openedx/features/course_experience/static/course_experience/js/WelcomeMessage.js',
+        Enrollment: './openedx/features/course_experience/static/course_experience/js/Enrollment.js',
         Import: './cms/static/js/features/import/factories/import.js'
     },