diff --git a/doc/user/events/img/widget_checkbox_button.png b/doc/user/events/img/widget_checkbox_button.png
new file mode 100644
index 0000000000..4240c12257
Binary files /dev/null and b/doc/user/events/img/widget_checkbox_button.png differ
diff --git a/doc/user/events/widget.rst b/doc/user/events/widget.rst
index 88e5a1fe35..f19f3cd285 100644
--- a/doc/user/events/widget.rst
+++ b/doc/user/events/widget.rst
@@ -124,6 +124,24 @@ If you want to disable voucher input in the widget, you can pass the ``disable-v
+Enabling the button-style single item select
+--------------------------------------------
+
+By default, the widget uses a checkbox to select items, that can only be bought in quantities of one. If you want to match
+the button-style of that checkbox with the one in the pretix shop, you can use the ``single-item-select`` attribute::
+
+
+
+.. image:: img/widget_checkbox_button.png
+ :align: center
+ :class: screenshot
+
+.. note::
+
+ Due to compatibilty with existing widget installations, the default value for ``single-item-select``
+ is ``checkbox``. This might change in the future, so make sure, to set the attribute to
+ ``single-item-select="checkbox"`` if you need it.
+
Filtering products
------------------
diff --git a/src/pretix/control/templates/pretixcontrol/event/widget.html b/src/pretix/control/templates/pretixcontrol/event/widget.html
index fd4bdef114..109de96a7b 100644
--- a/src/pretix/control/templates/pretixcontrol/event/widget.html
+++ b/src/pretix/control/templates/pretixcontrol/event/widget.html
@@ -32,7 +32,7 @@
{% abseventurl request.event "presale:event.index" as indexurl %}
{% endif %}
{% if form.cleaned_data.compatibility_mode %}
-
<div class="pretix-widget-compat" event="{% abseventurl request.event "presale:event.index" %}"{% if form.cleaned_data.subevent %} subevent="{{ form.cleaned_data.subevent.pk }}"{% endif %}{% if form.cleaned_data.voucher %} voucher="{{ form.cleaned_data.voucher }}"{% endif %}></div>
+ <div class="pretix-widget-compat" event="{% abseventurl request.event "presale:event.index" %}"{% if form.cleaned_data.subevent %} subevent="{{ form.cleaned_data.subevent.pk }}"{% endif %}{% if form.cleaned_data.voucher %} voucher="{{ form.cleaned_data.voucher }}"{% endif %} single-item-select="button"></div>
<noscript>
<div class="pretix-widget">
<div class="pretix-widget-info-message">
@@ -45,7 +45,7 @@
</noscript>
{% else %}
- <pretix-widget event="{% abseventurl request.event "presale:event.index" %}"{% if form.cleaned_data.subevent %} subevent="{{ form.cleaned_data.subevent.pk }}"{% endif %}{% if form.cleaned_data.voucher %} voucher="{{ form.cleaned_data.voucher }}"{% endif %}></pretix-widget>
+ <pretix-widget event="{% abseventurl request.event "presale:event.index" %}"{% if form.cleaned_data.subevent %} subevent="{{ form.cleaned_data.subevent.pk }}"{% endif %}{% if form.cleaned_data.voucher %} voucher="{{ form.cleaned_data.voucher }}"{% endif %} single-item-select="button"></pretix-widget>
<noscript>
<div class="pretix-widget">
<div class="pretix-widget-info-message">
diff --git a/src/pretix/static/pretixpresale/js/widget/widget.js b/src/pretix/static/pretixpresale/js/widget/widget.js
index 880d86e2f6..ae11c00d41 100644
--- a/src/pretix/static/pretixpresale/js/widget/widget.js
+++ b/src/pretix/static/pretixpresale/js/widget/widget.js
@@ -17,6 +17,7 @@ var strings = {
'quantity_dec': django.pgettext('widget', 'Decrease quantity'),
'quantity_inc': django.pgettext('widget', 'Increase quantity'),
'price': django.pgettext('widget', 'Price'),
+ 'select': django.pgettext('widget', 'Select'),
'select_item': django.pgettext('widget', 'Select %s'),
'select_variant': django.pgettext('widget', 'Select variant %s'),
'sold_out': django.pgettext('widget', 'Sold out'),
@@ -214,7 +215,13 @@ Vue.component('availbox', {
+ '' + strings.waiting_list + ' '
+ ''
+ ''
- + ''
+ + ''
+ + ' '
+ + ' ' + strings.select
+ + ' '
+ + ''
+ ' '
@@ -1903,6 +1910,7 @@ var create_widget = function (element) {
var items = element.attributes.items ? element.attributes.items.value : null;
var variations = element.attributes.variations ? element.attributes.variations.value : null;
var categories = element.attributes.categories ? element.attributes.categories.value : null;
+ var single_item_select = element.getAttribute("single-item-select") || "checkbox";
for (var i = 0; i < element.attributes.length; i++) {
var attrib = element.attributes[i];
if (attrib.name.match(/^data-.*$/)) {
@@ -1949,6 +1957,7 @@ var create_widget = function (element) {
voucher_code: voucher,
display_net_prices: false,
use_native_spinners: false,
+ single_item_select: single_item_select,
voucher_explanation_text: null,
show_variations_expanded: !!variations,
skip_ssl: skip_ssl,
diff --git a/src/pretix/static/pretixpresale/scss/widget.scss b/src/pretix/static/pretixpresale/scss/widget.scss
index 5ff9db318e..fbc5ab7926 100644
--- a/src/pretix/static/pretixpresale/scss/widget.scss
+++ b/src/pretix/static/pretixpresale/scss/widget.scss
@@ -69,6 +69,36 @@
@include button-variant($btn-default-color, $btn-default-bg, $btn-default-border);
}
}
+ label.pretix-widget-btn-checkbox {
+ @include button-variant($btn-default-color, $btn-default-bg, $btn-default-border);
+ border-width: 1px;
+ border-style: solid;
+ position: relative;
+ cursor: pointer;
+ padding: 6px 24px;
+ min-height: 32px;
+ box-sizing: border-box;
+ color: #333;
+ input {
+ position: absolute;
+ left: 10px;
+ }
+ &:has(input:checked) {
+ background-color: #e6e6e6;
+ border-color: #adadad;
+ }
+ }
+ .pretix-widget-icon-cart {
+ display: inline-block;
+ width: 1em;
+ height: 1em;
+ vertical-align: text-bottom;
+ fill: #333;
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2.267 6.756c0-.312-.202-.563-.453-.563-.252 0-.454.251-.454.563 0 .312.202.563.454.563.251 0 .453-.251.453-.563Zm3.174 0c0-.312-.202-.563-.454-.563-.251 0-.453.251-.453.563 0 .312.202.563.453.563.252 0 .454-.251.454-.563Zm.453-4.785c0-.154-.103-.282-.227-.282H1.413c-.035-.211-.039-.563-.28-.563H.227c-.124 0-.227.128-.227.282 0 .153.103.281.227.281h.722l.627 3.62c-.049.127-.216.466-.216.603 0 .153.103.281.227.281h3.627c.124 0 .227-.128.227-.281 0-.154-.103-.282-.227-.282H1.955c.036-.088.085-.18.085-.281 0-.102-.032-.212-.046-.308l3.698-.537c.117-.018.202-.141.202-.281V1.971Z' transform='matrix(2.52069 0 0 2.02994 -.035 -.523)'/%3E%3C/svg%3E%0A");
+ }
+ input:checked + .pretix-widget-icon-cart {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.534 3.097a.317.317 0 0 1-.067.197L3.56 4.42a.207.207 0 0 1-.16.084.207.207 0 0 1-.159-.084l-.907-1.126a.317.317 0 0 1-.067-.197c0-.154.103-.282.227-.282.06 0 .117.031.159.084l.521.642V2.252c0-.154.102-.281.226-.281.124 0 .227.127.227.281v1.289l.521-.642a.205.205 0 0 1 .159-.084c.124 0 .227.128.227.282ZM2.267 6.756c0-.312-.202-.563-.453-.563-.252 0-.454.251-.454.563 0 .312.202.563.454.563.251 0 .453-.251.453-.563Zm3.174 0c0-.312-.202-.563-.454-.563-.251 0-.453.251-.453.563 0 .312.202.563.453.563.252 0 .454-.251.454-.563Zm.453-4.785c0-.154-.103-.282-.227-.282H1.413c-.035-.211-.039-.563-.28-.563H.227c-.124 0-.227.128-.227.282 0 .153.103.281.227.281h.722l.627 3.62c-.049.127-.216.466-.216.603 0 .153.103.281.227.281h3.627c.124 0 .227-.128.227-.281 0-.154-.103-.282-.227-.282H1.955c.036-.088.085-.18.085-.281 0-.102-.032-.212-.046-.308l3.698-.537c.117-.018.202-.141.202-.281V1.971Z' transform='matrix(2.52069 0 0 2.02994 -.035 -.523)'/%3E%3C/svg%3E%0A");
+ }
input[type="text"], input[type="number"] {
line-height: normal;
border: 1px solid $input-border;