diff --git a/src/components/widgets/CheckboxWidget.js b/src/components/widgets/CheckboxWidget.js
index f583f5e7a4..632ab4b426 100644
--- a/src/components/widgets/CheckboxWidget.js
+++ b/src/components/widgets/CheckboxWidget.js
@@ -2,12 +2,40 @@ import React from "react";
import PropTypes from "prop-types";
import DescriptionField from "../fields/DescriptionField.js";
+// Check to see if a schema specifies that a value must be true
+function schemaRequiresTrueValue(schema) {
+ // Check if const is a truthy value
+ if (schema.const) {
+ return true;
+ }
+
+ // Check if an enum has a single value of true
+ if (schema.enum && schema.enum.length === 1 && schema.enum[0] === true) {
+ return true;
+ }
+
+ // If anyOf has a single value, evaluate the subschema
+ if (schema.anyOf && schema.anyOf.length === 1) {
+ return schemaRequiresTrueValue(schema.anyOf[0]);
+ }
+
+ // If oneOf has a single value, evaluate the subschema
+ if (schema.oneOf && schema.oneOf.length === 1) {
+ return schemaRequiresTrueValue(schema.oneOf[0]);
+ }
+
+ // Evaluate each subschema in allOf, to see if one of them requires a true
+ // value
+ if (schema.allOf) {
+ return schema.allOf.some(schemaRequiresTrueValue);
+ }
+}
+
function CheckboxWidget(props) {
const {
schema,
id,
value,
- required,
disabled,
readonly,
label,
@@ -16,6 +44,12 @@ function CheckboxWidget(props) {
onFocus,
onChange,
} = props;
+
+ // Because an unchecked checkbox will cause html5 validation to fail, only add
+ // the "required" attribute if the field value must be "true", due to the
+ // "const" or "enum" keywords
+ const required = schemaRequiresTrueValue(schema);
+
return (
{schema.description && (
diff --git a/test/BooleanField_test.js b/test/BooleanField_test.js
index ea9d43b7a6..640dc46f5f 100644
--- a/test/BooleanField_test.js
+++ b/test/BooleanField_test.js
@@ -51,6 +51,116 @@ describe("BooleanField", () => {
expect(node.querySelector(".field label span").textContent).eql("foo");
});
+ describe("HTML5 required attribute", () => {
+ it("should not render a required attribute for simple required fields", () => {
+ const { node } = createFormComponent({
+ schema: {
+ type: "object",
+ properties: {
+ foo: {
+ type: "boolean",
+ },
+ },
+ required: ["foo"],
+ },
+ });
+
+ expect(node.querySelector("input[type=checkbox]").required).eql(false);
+ });
+
+ it("should add a required attribute if the schema uses const with a true value", () => {
+ const { node } = createFormComponent({
+ schema: {
+ type: "object",
+ properties: {
+ foo: {
+ type: "boolean",
+ const: true,
+ },
+ },
+ },
+ });
+
+ expect(node.querySelector("input[type=checkbox]").required).eql(true);
+ });
+
+ it("should add a required attribute if the schema uses an enum with a single value of true", () => {
+ const { node } = createFormComponent({
+ schema: {
+ type: "object",
+ properties: {
+ foo: {
+ type: "boolean",
+ enum: [true],
+ },
+ },
+ },
+ });
+
+ expect(node.querySelector("input[type=checkbox]").required).eql(true);
+ });
+
+ it("should add a required attribute if the schema uses an anyOf with a single value of true", () => {
+ const { node } = createFormComponent({
+ schema: {
+ type: "object",
+ properties: {
+ foo: {
+ type: "boolean",
+ anyOf: [
+ {
+ const: true,
+ },
+ ],
+ },
+ },
+ },
+ });
+
+ expect(node.querySelector("input[type=checkbox]").required).eql(true);
+ });
+
+ it("should add a required attribute if the schema uses a oneOf with a single value of true", () => {
+ const { node } = createFormComponent({
+ schema: {
+ type: "object",
+ properties: {
+ foo: {
+ type: "boolean",
+ oneOf: [
+ {
+ const: true,
+ },
+ ],
+ },
+ },
+ },
+ });
+
+ expect(node.querySelector("input[type=checkbox]").required).eql(true);
+ });
+
+ it("should add a required attribute if the schema uses an allOf with a value of true", () => {
+ const { node } = createFormComponent({
+ schema: {
+ type: "object",
+ properties: {
+ foo: {
+ type: "boolean",
+ allOf: [
+ {
+ const: true,
+ },
+ ],
+ },
+ },
+ },
+ });
+
+ expect(node.querySelector("input[type=checkbox]").required).eql(true);
+ });
+ });
+
it("should render a single label", () => {
const { node } = createFormComponent({
schema: {