diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 19c212d..565e79c 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -339,6 +339,7 @@ class ModelAdmin(BaseModelAdmin):
     actions_on_top = True
     actions_on_bottom = False
     actions_selection_counter = True
+    actions_template = 'admin/actions_as_buttons.html'
 
     def __init__(self, model, admin_site):
         self.model = model
@@ -925,6 +926,7 @@ class ModelAdmin(BaseModelAdmin):
         # There can be multiple action forms on the page (at the top
         # and bottom of the change list, for example). Get the action
         # whose button was pushed.
+        # The request will not contain 'index' field if button layout is used.
         try:
             action_index = int(request.POST.get('index', 0))
         except ValueError:
@@ -1202,37 +1204,13 @@ class ModelAdmin(BaseModelAdmin):
             return HttpResponseRedirect(request.path + '?' + ERROR_FLAG + '=1')
 
         # If the request was POSTed, this might be a bulk action or a bulk
-        # edit. Try to look up an action or confirmation first, but if this
-        # isn't an action the POST will fall through to the bulk edit check,
-        # below.
-        action_failed = False
-        selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME)
-
-        # Actions with no confirmation
-        if (actions and request.method == 'POST' and
-                'index' in request.POST and '_save' not in request.POST):
-            if selected:
-                response = self.response_action(request, queryset=cl.get_query_set(request))
-                if response:
-                    return response
-                else:
-                    action_failed = True
-            else:
-                msg = _("Items must be selected in order to perform "
-                        "actions on them. No items have been changed.")
-                self.message_user(request, msg)
-                action_failed = True
-
-        # Actions with confirmation
-        if (actions and request.method == 'POST' and
-                helpers.ACTION_CHECKBOX_NAME in request.POST and
-                'index' not in request.POST and '_save' not in request.POST):
-            if selected:
-                response = self.response_action(request, queryset=cl.get_query_set(request))
-                if response:
-                    return response
-                else:
-                    action_failed = True
+        # edit. It is a bulk edit if '_save' is in request.POST and it is a 
+        # bulk action if '_save' is not in request.POST.
+
+        if actions and request.method == 'POST' and '_save' not in request.POST:
+            response = self.response_action(request, queryset=cl.get_query_set(request))
+            if response:
+                return response
 
         # If we're allowing changelist editing, we need to construct a formset
         # for the changelist given all the fields to be edited. Then we'll
@@ -1240,8 +1218,7 @@ class ModelAdmin(BaseModelAdmin):
         formset = cl.formset = None
 
         # Handle POSTed bulk-edit data.
-        if (request.method == "POST" and cl.list_editable and
-                '_save' in request.POST and not action_failed):
+        if request.method == 'POST' and cl.list_editable and '_save' in request.POST:
             FormSet = self.get_changelist_formset(request)
             formset = cl.formset = FormSet(request.POST, request.FILES, queryset=cl.result_list)
             if formset.is_valid():
diff --git a/django/contrib/admin/static/admin/js/actions.js b/django/contrib/admin/static/admin/js/actions.js
index 8494970..c5ad2d7 100644
--- a/django/contrib/admin/static/admin/js/actions.js
+++ b/django/contrib/admin/static/admin/js/actions.js
@@ -104,7 +104,8 @@
 		$('form#changelist-form table#result_list tr').find('td:gt(0) :input').change(function() {
 			list_editable_changed = true;
 		});
-		$('form#changelist-form button[name="index"]').click(function(event) {
+		/* button[name="index"] is for select layout and button[name="action"] is for button layout */
+		$('form#changelist-form button[name="index"], form#changelist-form button[name="action"]').click(function(event) {
 			if (list_editable_changed) {
 				return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."));
 			}
@@ -117,6 +118,7 @@
 				}
 			});
 			if (action_changed) {
+				/* action_changed will always be false in button layout. Confirmations will only be shown in select layout. */
 				if (list_editable_changed) {
 					return confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action."));
 				} else {
diff --git a/django/contrib/admin/static/admin/js/actions.min.js b/django/contrib/admin/static/admin/js/actions.min.js
index 6b1947c..4caaa65 100644
--- a/django/contrib/admin/static/admin/js/actions.min.js
+++ b/django/contrib/admin/static/admin/js/actions.min.js
@@ -1,6 +1,6 @@
-(function(a){a.fn.actions=function(n){var b=a.extend({},a.fn.actions.defaults,n),e=a(this),g=false,k=function(c){c?i():j();a(e).attr("checked",c).parent().parent().toggleClass(b.selectedClass,c)},f=function(){var c=a(e).filter(":checked").length;a(b.counterContainer).html(interpolate(ngettext("%(sel)s of %(cnt)s selected","%(sel)s of %(cnt)s selected",c),{sel:c,cnt:_actions_icnt},true));a(b.allToggle).attr("checked",function(){if(c==e.length){value=true;i()}else{value=false;l()}return value})},i=
-function(){a(b.acrossClears).hide();a(b.acrossQuestions).show();a(b.allContainer).hide()},m=function(){a(b.acrossClears).show();a(b.acrossQuestions).hide();a(b.actionContainer).toggleClass(b.selectedClass);a(b.allContainer).show();a(b.counterContainer).hide()},j=function(){a(b.acrossClears).hide();a(b.acrossQuestions).hide();a(b.allContainer).hide();a(b.counterContainer).show()},l=function(){j();a(b.acrossInput).val(0);a(b.actionContainer).removeClass(b.selectedClass)};a(b.counterContainer).show();
-a(this).filter(":checked").each(function(){a(this).parent().parent().toggleClass(b.selectedClass);f();a(b.acrossInput).val()==1&&m()});a(b.allToggle).show().click(function(){k(a(this).attr("checked"));f()});a("div.actions span.question a").click(function(c){c.preventDefault();a(b.acrossInput).val(1);m()});a("div.actions span.clear a").click(function(c){c.preventDefault();a(b.allToggle).attr("checked",false);l();k(0);f()});lastChecked=null;a(e).click(function(c){if(!c)c=window.event;var d=c.target?
-c.target:c.srcElement;if(lastChecked&&a.data(lastChecked)!=a.data(d)&&c.shiftKey===true){var h=false;a(lastChecked).attr("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked);a(e).each(function(){if(a.data(this)==a.data(lastChecked)||a.data(this)==a.data(d))h=h?false:true;h&&a(this).attr("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked)})}a(d).parent().parent().toggleClass(b.selectedClass,d.checked);lastChecked=d;f()});a("form#changelist-form table#result_list tr").find("td:gt(0) :input").change(function(){g=
-true});a('form#changelist-form button[name="index"]').click(function(){if(g)return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."))});a('form#changelist-form input[name="_save"]').click(function(){var c=false;a("div.actions select option:selected").each(function(){if(a(this).val())c=true});if(c)return g?confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action.")):
-confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button."))})};a.fn.actions.defaults={actionContainer:"div.actions",counterContainer:"span.action-counter",allContainer:"div.actions span.all",acrossInput:"div.actions input.select-across",acrossQuestions:"div.actions span.question",acrossClears:"div.actions span.clear",allToggle:"#action-toggle",selectedClass:"selected"}})(django.jQuery);
+(function(a){a.fn.actions=function(m){var b=a.extend({},a.fn.actions.defaults,m),f=a(this),e=!1,j=function(c){c?h():i();a(f).attr("checked",c).parent().parent().toggleClass(b.selectedClass,c)},g=function(){var c=a(f).filter(":checked").length;a(b.counterContainer).html(interpolate(ngettext("%(sel)s of %(cnt)s selected","%(sel)s of %(cnt)s selected",c),{sel:c,cnt:_actions_icnt},!0));a(b.allToggle).attr("checked",function(){c==f.length?(value=!0,h()):(value=!1,k());return value})},h=function(){a(b.acrossClears).hide();
+a(b.acrossQuestions).show();a(b.allContainer).hide()},l=function(){a(b.acrossClears).show();a(b.acrossQuestions).hide();a(b.actionContainer).toggleClass(b.selectedClass);a(b.allContainer).show();a(b.counterContainer).hide()},i=function(){a(b.acrossClears).hide();a(b.acrossQuestions).hide();a(b.allContainer).hide();a(b.counterContainer).show()},k=function(){i();a(b.acrossInput).val(0);a(b.actionContainer).removeClass(b.selectedClass)};a(b.counterContainer).show();a(this).filter(":checked").each(function(){a(this).parent().parent().toggleClass(b.selectedClass);
+g();1==a(b.acrossInput).val()&&l()});a(b.allToggle).show().click(function(){j(a(this).attr("checked"));g()});a("div.actions span.question a").click(function(c){c.preventDefault();a(b.acrossInput).val(1);l()});a("div.actions span.clear a").click(function(c){c.preventDefault();a(b.allToggle).attr("checked",!1);k();j(0);g()});lastChecked=null;a(f).click(function(c){c||(c=window.event);var d=c.target?c.target:c.srcElement;if(lastChecked&&a.data(lastChecked)!=a.data(d)&&!0===c.shiftKey){var e=!1;a(lastChecked).attr("checked",
+d.checked).parent().parent().toggleClass(b.selectedClass,d.checked);a(f).each(function(){if(a.data(this)==a.data(lastChecked)||a.data(this)==a.data(d))e=e?!1:!0;e&&a(this).attr("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked)})}a(d).parent().parent().toggleClass(b.selectedClass,d.checked);lastChecked=d;g()});a("form#changelist-form table#result_list tr").find("td:gt(0) :input").change(function(){e=!0});a('form#changelist-form button[name="index"], form#changelist-form button[name="action"]').click(function(){if(e)return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."))});
+a('form#changelist-form input[name="_save"]').click(function(){var b=!1;a("div.actions select option:selected").each(function(){a(this).val()&&(b=!0)});if(b)return e?confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action.")):confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button."))})};
+a.fn.actions.defaults={actionContainer:"div.actions",counterContainer:"span.action-counter",allContainer:"div.actions span.all",acrossInput:"div.actions input.select-across",acrossQuestions:"div.actions span.question",acrossClears:"div.actions span.clear",allToggle:"#action-toggle",selectedClass:"selected"}})(django.jQuery);
diff --git a/django/contrib/admin/templates/admin/actions.html b/django/contrib/admin/templates/admin/actions.html
deleted file mode 100644
index aaaa245..0000000
--- a/django/contrib/admin/templates/admin/actions.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% load i18n %}
-<div class="actions">
-    {% for field in action_form %}{% if field.label %}<label>{{ field.label }} {% endif %}{{ field }}{% if field.label %}</label>{% endif %}{% endfor %}
-    <button type="submit" class="button" title="{% trans "Run the selected action" %}" name="index" value="{{ action_index|default:0 }}">{% trans "Go" %}</button>
-    {% if actions_selection_counter %}
-        <script type="text/javascript">var _actions_icnt="{{ cl.result_list|length|default:"0" }}";</script>
-        <span class="action-counter">{{ selection_note }}</span>
-        {% if cl.result_count != cl.result_list|length %}
-        <span class="all">{{ selection_note_all }}</span>
-        <span class="question">
-            <a href="javascript:;" title="{% trans "Click here to select the objects across all pages" %}">{% blocktrans with cl.result_count as total_count %}Select all {{ total_count }} {{ module_name }}{% endblocktrans %}</a>
-        </span>
-        <span class="clear"><a href="javascript:;">{% trans "Clear selection" %}</a></span>
-        {% endif %}
-    {% endif %}
-</div>
diff --git a/django/contrib/admin/templates/admin/actions_as_buttons.html b/django/contrib/admin/templates/admin/actions_as_buttons.html
new file mode 100644
index 0000000..174510d
--- /dev/null
+++ b/django/contrib/admin/templates/admin/actions_as_buttons.html
@@ -0,0 +1,22 @@
+{% load i18n %}
+<div class="actions">
+    {{ action_form.select_across }}
+    {% for choice in action_form.fields.action.choices %}
+        {% if choice.0 %}
+        <button type="submit" class="button" name="action" value="{{ choice.0 }}">{{ choice.1 }}</button>
+        {% endif %}
+    {% endfor %}
+    {% if actions_selection_counter %}
+        <script type="text/javascript">var _actions_icnt="{{ cl.result_list|length|default:"0" }}";</script>
+        <span class="nowrap">
+            <span class="action-counter">{{ selection_note }}</span>
+            {% if cl.result_count != cl.result_list|length %}
+            <span class="all">{{ selection_note_all }}</span>
+            <span class="question">
+                <a href="javascript:;" title="{% trans "Click here to select the objects across all pages" %}">{% blocktrans with cl.result_count as total_count %}Select all {{ total_count }} {{ module_name }}{% endblocktrans %}</a>
+            </span>
+            <span class="clear"><a href="javascript:;">{% trans "Clear selection" %}</a></span>
+        </span>
+        {% endif %}
+    {% endif %}
+</div>
diff --git a/django/contrib/admin/templates/admin/actions_as_select.html b/django/contrib/admin/templates/admin/actions_as_select.html
new file mode 100644
index 0000000..aaaa245
--- /dev/null
+++ b/django/contrib/admin/templates/admin/actions_as_select.html
@@ -0,0 +1,16 @@
+{% load i18n %}
+<div class="actions">
+    {% for field in action_form %}{% if field.label %}<label>{{ field.label }} {% endif %}{{ field }}{% if field.label %}</label>{% endif %}{% endfor %}
+    <button type="submit" class="button" title="{% trans "Run the selected action" %}" name="index" value="{{ action_index|default:0 }}">{% trans "Go" %}</button>
+    {% if actions_selection_counter %}
+        <script type="text/javascript">var _actions_icnt="{{ cl.result_list|length|default:"0" }}";</script>
+        <span class="action-counter">{{ selection_note }}</span>
+        {% if cl.result_count != cl.result_list|length %}
+        <span class="all">{{ selection_note_all }}</span>
+        <span class="question">
+            <a href="javascript:;" title="{% trans "Click here to select the objects across all pages" %}">{% blocktrans with cl.result_count as total_count %}Select all {{ total_count }} {{ module_name }}{% endblocktrans %}</a>
+        </span>
+        <span class="clear"><a href="javascript:;">{% trans "Clear selection" %}</a></span>
+        {% endif %}
+    {% endif %}
+</div>
diff --git a/django/contrib/admin/templates/admin/change_list.html b/django/contrib/admin/templates/admin/change_list.html
index c72b663..b310381 100644
--- a/django/contrib/admin/templates/admin/change_list.html
+++ b/django/contrib/admin/templates/admin/change_list.html
@@ -87,9 +87,9 @@
       {% endif %}
 
       {% block result_list %}
-          {% if action_form and actions_on_top and cl.full_result_count %}{% admin_actions %}{% endif %}
+          {% if action_form and actions_on_top and cl.full_result_count %}{% admin_actions cl.model_admin %}{% endif %}
           {% result_list cl %}
-          {% if action_form and actions_on_bottom and cl.full_result_count %}{% admin_actions %}{% endif %}
+          {% if action_form and actions_on_bottom and cl.full_result_count %}{% admin_actions cl.model_admin %}{% endif %}
       {% endblock %}
       {% block pagination %}{% pagination cl %}{% endblock %}
       </form>
diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py
index ce435de..2148fcf 100644
--- a/django/contrib/admin/templatetags/admin_list.py
+++ b/django/contrib/admin/templatetags/admin_list.py
@@ -378,11 +378,11 @@ def admin_list_filter(cl, spec):
         'spec': spec,
     }))
 
-@register.inclusion_tag('admin/actions.html', takes_context=True)
-def admin_actions(context):
+@register.simple_tag(takes_context=True)
+def admin_actions(context, model_admin):
     """
     Track the number of times the action field has been rendered on the page,
     so we know which value to use.
     """
     context['action_index'] = context.get('action_index', -1) + 1
-    return context
+    return get_template(model_admin.actions_template).render(context)
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
index 29ee66b..c113971 100644
--- a/docs/ref/contrib/admin/index.txt
+++ b/docs/ref/contrib/admin/index.txt
@@ -940,6 +940,14 @@ The `Overriding Admin Templates`_ section describes how to override or extend
 the default admin templates.  Use the following options to override the default
 templates used by the :class:`ModelAdmin` views:
 
+.. attribute:: ModelAdmin.actions_template
+
+    .. versionadded:: 1.4
+
+    Path to a template used for rendering action bar in change list view.
+    Django provides two templates: ``admin/actions_as_buttons.html`` (default)
+    and ``admin/actions_as_select.html``.
+
 .. attribute:: ModelAdmin.add_form_template
 
     Path to a custom template, used by :meth:`add_view`.
diff --git a/tests/regressiontests/admin_views/admin.py b/tests/regressiontests/admin_views/admin.py
index a5476e9..c77d0d9 100644
--- a/tests/regressiontests/admin_views/admin.py
+++ b/tests/regressiontests/admin_views/admin.py
@@ -161,6 +161,7 @@ class PersonAdmin(admin.ModelAdmin):
     list_filter = ('gender',)
     search_fields = ('^name',)
     save_as = True
+    actions_template = 'admin/actions_as_select.html'
 
     def get_changelist_formset(self, request, **kwargs):
         return super(PersonAdmin, self).get_changelist_formset(request,
@@ -229,6 +230,7 @@ redirect_to.short_description = 'Redirect to (Awesome action)'
 
 class ExternalSubscriberAdmin(admin.ModelAdmin):
     actions = [redirect_to, external_mail]
+    actions_template = 'admin/actions_as_select.html'
 
 
 class Podcast(Media):
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
index 72dc6a3..7f6143e 100644
--- a/tests/regressiontests/admin_views/tests.py
+++ b/tests/regressiontests/admin_views/tests.py
@@ -1718,7 +1718,7 @@ class AdminViewListEditable(TestCase):
         # 2 inputs per object(the field and the hidden id field) = 6
         # 3 management hidden fields = 3
         # 4 action inputs (3 regular checkboxes, 1 checkbox to select all)
-        # main form submit button = 1
+        # main form submit button = 1 (assuming that select layout is used for actions)
         # search field and search submit button = 2
         # CSRF field = 1
         # field to track 'select all' across paginated views = 1
@@ -2324,7 +2324,7 @@ class AdminActionsTest(TestCase):
 
     def test_actions_ordering(self):
         """
-        Ensure that actions are ordered as expected.
+        Ensure that actions are ordered as expected in select layout.
         Refs #15964.
         """
         response = self.client.get('/test_admin/admin/admin_views/externalsubscriber/')
@@ -2335,6 +2335,18 @@ class AdminActionsTest(TestCase):
 <option value="external_mail">External mail (Another awesome action)</option>
 </select>''', html=True)
 
+    def test_actions_as_buttons(self):
+        """
+        Test that actions are displayed as buttons by default.
+        Refs #19235.
+        """
+        response = self.client.get('/test_admin/admin/admin_views/subscriber/')
+        # Must check separately because HTML checking does not work with more than one top-level element.
+        self.assertContains(response, '''
+<button type="submit" class="button" name="action" value="delete_selected">Delete selected subscribers</button>''', html=True)
+        self.assertContains(response, '''
+<button type="submit" class="button" name="action" value="mail_admin">Mail admin</button>''', html=True)
+
     def test_model_without_action(self):
         "Tests a ModelAdmin without any action"
         response = self.client.get('/test_admin/admin/admin_views/oldsubscriber/')
