diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3afbca847..c3ca8b168 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,48 @@
# @formio/bootstrap
+## 4.0.3
+
+### Patch Changes
+
+- 4864d4c: FIO-12002 Aligned bootstrap5 with VPAT so they can work correctly together
+- be69fe1: Adding information to the error link about which wizard page the error occurred on
+- af465a1: FIO-11335 Put numeric only announcement back in the label
+- a334b0f: FIO-11779 Fix Day component error message announcements in VPAT
+- 8d7803a: FIO-11976 Removed button from rendering a hidden label
+- 7c5dd71: FIO-12013 Fixed excessive label announcements in NVDA
+- 7b4b9f6: FIO-11446 Double announcements fix for Radio and Selectboxes
+- c657268: FIO-11317: Enabled the label for Data Grids and Edit Grids to be read properly by screenreaders
+- 2fae4ad: FIO-11976 Added sr-only label to bootstrap templates if the hideLabel is true
+
+## 4.0.3-api98.3
+
+### Patch Changes
+
+- 7c5dd71: FIO-12013 Fixed excessive label announcements in NVDA
+
+## 4.0.3-api98.2
+
+### Patch Changes
+
+- 4864d4c: FIO-12002 Aligned bootstrap5 with VPAT so they can work correctly together
+- 8d7803a: FIO-11976 Removed button from rendering a hidden label
+- 2fae4ad: FIO-11976 Added sr-only label to bootstrap templates if the hideLabel is true
+
+## 4.0.3-api98.1
+
+### Patch Changes
+
+- be69fe1: Adding information to the error link about which wizard page the error occurred on
+
+## 4.0.3-api98.0
+
+### Patch Changes
+
+- af465a1: FIO-11335 Put numeric only announcement back in the label
+- a334b0f: FIO-11779 Fix Day component error message announcements in VPAT
+- 7b4b9f6: FIO-11446 Double announcements fix for Radio and Selectboxes
+- c657268: FIO-11317: Enabled the label for Data Grids and Edit Grids to be read properly by screenreaders
+
## 4.0.2
### Patch Changes
diff --git a/package.json b/package.json
index 07a312d5a..5cdafa5b1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@formio/bootstrap",
- "version": "4.0.2",
+ "version": "4.0.3",
"description": "Bootstrap templates for Form.io forms",
"main": "lib/cjs/bootstrap5.js",
"module": "lib/mjs/bootstrap5.js",
diff --git a/src/templates/bootstrap3/datagrid/form.ejs b/src/templates/bootstrap3/datagrid/form.ejs
index e2624fb07..8e691993f 100644
--- a/src/templates/bootstrap3/datagrid/form.ejs
+++ b/src/templates/bootstrap3/datagrid/form.ejs
@@ -3,6 +3,7 @@
{{ ctx.component.hover ? 'table-hover' : ''}}
{{ ctx.component.condensed ? 'table-condensed' : ''}}
" {% if (ctx.component.layoutFixed) { %}style="table-layout: fixed;"{% } %}>
+
{{ctx.t(ctx.component.label)}}
{% if (ctx.hasHeader) { %}
diff --git a/src/templates/bootstrap3/datagrid/html.ejs b/src/templates/bootstrap3/datagrid/html.ejs
index da835867a..784b5083e 100644
--- a/src/templates/bootstrap3/datagrid/html.ejs
+++ b/src/templates/bootstrap3/datagrid/html.ejs
@@ -3,6 +3,7 @@
{{ component.hover ? 'table-hover' : ''}}
{{ component.condensed ? 'table-condensed' : ''}}
">
+ {{t(component.label)}}
{% if (hasHeader) { %}
diff --git a/src/templates/bootstrap3/errorsList/form.ejs b/src/templates/bootstrap3/errorsList/form.ejs
index 776fd0b3f..5434d6756 100644
--- a/src/templates/bootstrap3/errorsList/form.ejs
+++ b/src/templates/bootstrap3/errorsList/form.ejs
@@ -1,12 +1,12 @@
{{ctx.t('error')}}
{% ctx.errors.forEach(function(err) { %}
- {{err.message}}
+ {{err.message}}
+ {% if (err.errorPageTitle) { %}
+ . Click to navigate to the component within {{ err.errorPageTitle }}
+ {% } %}
+
+
{% }) %}
-
+
\ No newline at end of file
diff --git a/src/templates/bootstrap4/datagrid/form.ejs b/src/templates/bootstrap4/datagrid/form.ejs
index 7437b1c13..bc5618c09 100644
--- a/src/templates/bootstrap4/datagrid/form.ejs
+++ b/src/templates/bootstrap4/datagrid/form.ejs
@@ -3,6 +3,7 @@
{{ ctx.component.hover ? 'table-hover' : ''}}
{{ ctx.component.condensed ? 'table-sm' : ''}}
" {% if (ctx.component.layoutFixed || ctx.readOnly) { %}style="table-layout: fixed;"{% } %}>
+ {{ctx.t(ctx.component.label)}}
{% if (ctx.component.reorder) { %}
diff --git a/src/templates/bootstrap4/datagrid/html.ejs b/src/templates/bootstrap4/datagrid/html.ejs
index 2bce75175..2cb72b2e8 100644
--- a/src/templates/bootstrap4/datagrid/html.ejs
+++ b/src/templates/bootstrap4/datagrid/html.ejs
@@ -3,6 +3,7 @@
{{ ctx.component.hover ? 'table-hover' : ''}}
{{ ctx.component.condensed ? 'table-sm' : ''}}
">
+ {{ctx.t(ctx.component.label)}}
{% if (ctx.hasHeader) { %}
diff --git a/src/templates/bootstrap4/day/form.ejs b/src/templates/bootstrap4/day/form.ejs
index 472160f69..2b9c4fe68 100644
--- a/src/templates/bootstrap4/day/form.ejs
+++ b/src/templates/bootstrap4/day/form.ejs
@@ -1,5 +1,5 @@
{% var fieldsetLegendIds = ctx.instance.getFieldsetLegendIds ? ctx.instance.getFieldsetLegendIds() : ''; %}
-
+
{{ctx.t(ctx.component.label)}}
{% if (ctx.header) { %}
{{ctx.header}}
diff --git a/src/templates/bootstrap4/editgridTable/html.ejs b/src/templates/bootstrap4/editgridTable/html.ejs
index 66b9a88c1..1a75acca6 100644
--- a/src/templates/bootstrap4/editgridTable/html.ejs
+++ b/src/templates/bootstrap4/editgridTable/html.ejs
@@ -6,6 +6,7 @@
{{ ctx.component.hover ? 'table-hover' : ''}}
{{ ctx.component.condensed ? 'table-sm' : ''}}
">
+ {{ctx.t(ctx.component.label)}}
{% if (ctx.header) { %}
{{ctx.header}}
diff --git a/src/templates/bootstrap4/errorsList/form.ejs b/src/templates/bootstrap4/errorsList/form.ejs
index baab6f894..9220ffce5 100644
--- a/src/templates/bootstrap4/errorsList/form.ejs
+++ b/src/templates/bootstrap4/errorsList/form.ejs
@@ -6,13 +6,11 @@
{% ctx.errors.forEach(function(err) { %}
-
+
{{err.message}}
+ {% if (err.errorPageTitle) { %}
+ . Click to navigate to the component within {{ err.errorPageTitle }}
+ {% } %}
{% }) %}
diff --git a/src/templates/bootstrap4/field/form.ejs b/src/templates/bootstrap4/field/form.ejs
index 47b2e15f4..8f2d4e443 100644
--- a/src/templates/bootstrap4/field/form.ejs
+++ b/src/templates/bootstrap4/field/form.ejs
@@ -2,8 +2,8 @@
{{ ctx.labelMarkup }}
{% } %}
-{% if (ctx.label.hidden && ctx.label.className && ctx.component.validate.required) { %}
-
+{% if (ctx.label.hidden && !ctx.options.floatingLabels && ctx.component.label && ctx.component.type !== 'checkbox' && ctx.component.type !== 'button') { %}
+ {{ ctx.labelMarkup }}
{% } %}
{{ctx.element}}
diff --git a/src/templates/bootstrap4/input/form.ejs b/src/templates/bootstrap4/input/form.ejs
index 03b58e8d6..f61535d88 100644
--- a/src/templates/bootstrap4/input/form.ejs
+++ b/src/templates/bootstrap4/input/form.ejs
@@ -21,8 +21,8 @@
{% } %}
id="{{ctx.instance.id}}-{{ctx.component.key}}"
aria-labelledby="{% if (fieldsetLegendIds) { %}{{fieldsetLegendIds}} {% } %}l-{{ctx.instance.id}}-{{ctx.component.key}} {% if (ctx.component.description) { %}d-{{ctx.instance.id}}-{{ctx.component.key}}{% } %}"
- {% if (ctx.component.description || ctx.component.type === 'number' || ctx.component.type === 'phoneNumber' || ctx.component.type === 'currency') { %}
- aria-describedby="{% if (ctx.component.description) { %}d-{{ctx.instance.id}}-{{ctx.component.key}}{% } %}{% if (ctx.component.type === 'number' || ctx.component.type === 'phoneNumber' || ctx.component.type === 'currency') { %} h-{{ctx.instance.id}}-{{ctx.component.key}}{% } %}"
+ {% if (ctx.component.description) { %}
+ aria-describedby="d-{{ctx.instance.id}}-{{ctx.component.key}}"
{% } %}
aria-required="{{ctx.input.ref === 'input' || !ctx.input.ref ? ctx.component.validate.required :
ctx.component.fields && ctx.component.fields[ctx.input.ref] && ctx.component.fields[ctx.input.ref].required || false}}"
@@ -34,9 +34,6 @@
{% if (ctx.component.editor || ctx.component.wysiwyg) { %}
{% } %}
-{% if (ctx.component.type === 'number' || ctx.component.type === 'phoneNumber' || ctx.component.type === 'currency') { %}
-{{ctx.t('numeric only')}}
-{% } %}
{% if (ctx.component.type === 'datetime') { %}
{% } %}
diff --git a/src/templates/bootstrap4/label/form.ejs b/src/templates/bootstrap4/label/form.ejs
index bb67a584f..03f2020c8 100644
--- a/src/templates/bootstrap4/label/form.ejs
+++ b/src/templates/bootstrap4/label/form.ejs
@@ -1,16 +1,22 @@
{{ ctx.t(ctx.component.label, { _userInput: true }) }}
{% if (ctx.component.validate && ctx.component.validate.required) { %}
*
{% } %}
- {% if (ctx.component.tooltip) { %}
+ {% if (ctx.component.type === 'number' || ctx.component.type === 'phoneNumber' || ctx.component.type === 'currency') { %}
+ , {{ctx.t('numeric only')}},
+ {% } %}
+ {% if (ctx.component.tooltip && !ctx.label.hidden) { %}
{% } %}
diff --git a/src/templates/bootstrap5/cssClasses.ts b/src/templates/bootstrap5/cssClasses.ts
index cf99fce67..2fe2804fb 100644
--- a/src/templates/bootstrap5/cssClasses.ts
+++ b/src/templates/bootstrap5/cssClasses.ts
@@ -1,5 +1,6 @@
export default {
'border-default': '',
+ 'sr-only': 'visually-hidden',
'formio-tab-panel-active': 'active',
'formio-tab-link-active': 'active',
'formio-tab-link-container-active': 'active',
diff --git a/src/templates/bootstrap5/datagrid/form.ejs b/src/templates/bootstrap5/datagrid/form.ejs
index 2f41a93da..e60196e8b 100644
--- a/src/templates/bootstrap5/datagrid/form.ejs
+++ b/src/templates/bootstrap5/datagrid/form.ejs
@@ -3,6 +3,7 @@
{{ ctx.component.hover ? 'table-hover' : ''}}
{{ ctx.component.condensed ? 'table-sm' : ''}}
" {% if (ctx.component.layoutFixed || ctx.readOnly) { %}style="table-layout: fixed;"{% } %}>
+ {{ctx.t(ctx.component.label)}}
{% if (ctx.component.reorder) { %}
diff --git a/src/templates/bootstrap5/datagrid/html.ejs b/src/templates/bootstrap5/datagrid/html.ejs
index 2bce75175..6a5b91313 100644
--- a/src/templates/bootstrap5/datagrid/html.ejs
+++ b/src/templates/bootstrap5/datagrid/html.ejs
@@ -3,6 +3,7 @@
{{ ctx.component.hover ? 'table-hover' : ''}}
{{ ctx.component.condensed ? 'table-sm' : ''}}
">
+ {{ctx.t(ctx.component.label)}}
{% if (ctx.hasHeader) { %}
diff --git a/src/templates/bootstrap5/day/form.ejs b/src/templates/bootstrap5/day/form.ejs
index 472160f69..2b9c4fe68 100644
--- a/src/templates/bootstrap5/day/form.ejs
+++ b/src/templates/bootstrap5/day/form.ejs
@@ -1,5 +1,5 @@
{% var fieldsetLegendIds = ctx.instance.getFieldsetLegendIds ? ctx.instance.getFieldsetLegendIds() : ''; %}
-
+
{{ctx.t(ctx.component.label)}}
{% if (ctx.header) { %}
{{ctx.header}}
diff --git a/src/templates/bootstrap5/editgridTable/html.ejs b/src/templates/bootstrap5/editgridTable/html.ejs
index 3b93fd120..f350cf368 100644
--- a/src/templates/bootstrap5/editgridTable/html.ejs
+++ b/src/templates/bootstrap5/editgridTable/html.ejs
@@ -6,6 +6,7 @@
{{ ctx.component.hover ? 'table-hover' : ''}}
{{ ctx.component.condensed ? 'table-sm' : ''}}
">
+ {{ctx.t(ctx.component.label)}}
{% if (ctx.header) { %}
{{ctx.header}}
diff --git a/src/templates/bootstrap5/errorsList/form.ejs b/src/templates/bootstrap5/errorsList/form.ejs
index baab6f894..4e412d52c 100644
--- a/src/templates/bootstrap5/errorsList/form.ejs
+++ b/src/templates/bootstrap5/errorsList/form.ejs
@@ -6,13 +6,11 @@
{% ctx.errors.forEach(function(err) { %}
-
+
{{err.message}}
+ {% if (err.errorPageTitle) { %}
+ . Click to navigate to the component within {{ err.errorPageTitle }}
+ {% } %}
{% }) %}
diff --git a/src/templates/bootstrap5/field/form.ejs b/src/templates/bootstrap5/field/form.ejs
index 47b2e15f4..8f2d4e443 100644
--- a/src/templates/bootstrap5/field/form.ejs
+++ b/src/templates/bootstrap5/field/form.ejs
@@ -2,8 +2,8 @@
{{ ctx.labelMarkup }}
{% } %}
-{% if (ctx.label.hidden && ctx.label.className && ctx.component.validate.required) { %}
-
+{% if (ctx.label.hidden && !ctx.options.floatingLabels && ctx.component.label && ctx.component.type !== 'checkbox' && ctx.component.type !== 'button') { %}
+ {{ ctx.labelMarkup }}
{% } %}
{{ctx.element}}
diff --git a/src/templates/bootstrap5/input/form.ejs b/src/templates/bootstrap5/input/form.ejs
index 54c7eb9ec..87764d30f 100644
--- a/src/templates/bootstrap5/input/form.ejs
+++ b/src/templates/bootstrap5/input/form.ejs
@@ -22,8 +22,8 @@
{% } %}
id="{{ctx.instance.id}}-{{ctx.component.key}}"
aria-labelledby="{% if (fieldsetLegendIds) { %}{{fieldsetLegendIds}} {% } %}l-{{ctx.instance.id}}-{{ctx.component.key}} {% if (ctx.component.description) { %}d-{{ctx.instance.id}}-{{ctx.component.key}}{% } %}"
- {% if (ctx.component.description || ctx.component.type === 'number' || ctx.component.type === 'phoneNumber' || ctx.component.type === 'currency') { %}
- aria-describedby="{% if (ctx.component.description) { %}d-{{ctx.instance.id}}-{{ctx.component.key}}{% } %}{% if (ctx.component.type === 'number' || ctx.component.type === 'phoneNumber' || ctx.component.type === 'currency') { %} h-{{ctx.instance.id}}-{{ctx.component.key}}{% } %}"
+ {% if (ctx.component.description) { %}
+ aria-describedby="d-{{ctx.instance.id}}-{{ctx.component.key}}"
{% } %}
aria-required="{{ctx.input.ref === 'input' || !ctx.input.ref ? ctx.component.validate.required :
ctx.component.fields && ctx.component.fields[ctx.input.ref] && ctx.component.fields[ctx.input.ref].required || false}}"
@@ -41,9 +41,6 @@
{% if (ctx.component.editor || ctx.component.wysiwyg) { %}
{% } %}
-{% if (ctx.component.type === 'number' || ctx.component.type === 'phoneNumber' || ctx.component.type === 'currency') { %}
-{{ctx.t('numeric only')}}
-{% } %}
{% if (ctx.component.type === 'datetime') { %}
{% } %}
diff --git a/src/templates/bootstrap5/label/form.ejs b/src/templates/bootstrap5/label/form.ejs
index bb67a584f..ea6798555 100644
--- a/src/templates/bootstrap5/label/form.ejs
+++ b/src/templates/bootstrap5/label/form.ejs
@@ -1,16 +1,22 @@
{{ ctx.t(ctx.component.label, { _userInput: true }) }}
{% if (ctx.component.validate && ctx.component.validate.required) { %}
*
{% } %}
- {% if (ctx.component.tooltip) { %}
+ {% if (ctx.component.type === 'number' || ctx.component.type === 'phoneNumber' || ctx.component.type === 'currency') { %}
+ , {{ctx.t('numeric only')}},
+ {% } %}
+ {% if (ctx.component.tooltip && !ctx.label.hidden) { %}
{% } %}