diff --git a/docs/5.x upgrade guide.md b/docs/5.x upgrade guide.md
index 6823ee4c4f..e8355c3716 100644
--- a/docs/5.x upgrade guide.md
+++ b/docs/5.x upgrade guide.md
@@ -28,6 +28,10 @@ There are three new packages added in RJSF version 5:
### `@rjsf/core` BREAKING CHANGES
+#### Support dropped for non-standard `enumNames` property
+
+`enumNames` was a non-standard JSON Schema field that RJSF supported prior to version 5 to support labels that differed from an enumeration value. This behavior can still be accomplished with `oneOf` or `anyOf` containing `const` values. For more information, see [#532](https://github.com/rjsf-team/react-jsonschema-form/issues/532).
+
#### Types
In version 4, RJSF exported all its types directly from `@rjsf/core`.
In version 5, only the types for the `Form` component and the `withTheme()` HOC are exported directly from `@rjsf/core`.
diff --git a/docs/api-reference/utility-functions.md b/docs/api-reference/utility-functions.md
index 7a7a242122..cfaf21dbf8 100644
--- a/docs/api-reference/utility-functions.md
+++ b/docs/api-reference/utility-functions.md
@@ -250,9 +250,8 @@ The difference between mergeSchemas and mergeObjects is that mergeSchemas only c
- GenericObjectType: The merged schema object
### optionsList()
-Gets the list of options from the schema. If the schema has an enum list, then those enum values are returned.
-The labels for the options will be extracted from the non-standard `enumNames` if it exists othewise will be the same as the `value`.
-If the schema has a `oneOf` or `anyOf`, then the value is the list of `constant` values from the schema and the label is either the `schema.title` or the value.
+Gets the list of options from the schema. If the schema has an enum list, then those enum values are returned. The labels for the options will be the same as the `value`.
+If the schema has a `oneOf` or `anyOf`, then the value is the list of `const` values from the schema and the label is either the `schema.title`, if it exists, or the value.
#### Parameters
- schema: RJSFSchema - The schema from which to extract the options list
diff --git a/docs/usage/single.md b/docs/usage/single.md
index c394278d4a..df4650989e 100644
--- a/docs/usage/single.md
+++ b/docs/usage/single.md
@@ -63,26 +63,7 @@ render((
### Custom labels for `enum` fields
-This library supports a custom [`enumNames`](https://github.com/rjsf-team/react-jsonschema-form/issues/57) property for `enum` fields, which, however is not JSON-Schema compliant (see below for a compliant approach).
-The `enumNames` property allows defining custom labels for each option of an `enum`:
-
-```jsx
-import validator from "@rjsf/validator-ajv6";
-
-const schema = {
- type: "number",
- enum: [1, 2, 3],
- enumNames: ["one", "two", "three"]
-};
-
-render((
-
-), document.getElementById("app"));
-```
-
-#### Alternative JSON-Schema compliant approach
-
-JSON Schema has an alternative approach to enumerations using `anyOf`; react-jsonschema-form supports it as well.
+JSON Schema supports the following approaches to enumerations using `oneOf`/`anyOf`; react-jsonschema-form supports it as well.
```jsx
import validator from "@rjsf/validator-ajv6";
@@ -119,6 +100,21 @@ render((
), document.getElementById("app"));
```
+```jsx
+const schema = {
+ "type": "number",
+ "oneOf": [
+ {"const": 1, "title": "one"},
+ {"const": 2, "title": "two"},
+ {"const": 3, "title": "three"}
+ ]
+};
+
+render((
+
+), document.getElementById("app"));
+```
+
### Disabled attribute for `enum` fields
To disable an option, use the `ui:enumDisabled` property in the uiSchema.
diff --git a/docs/usage/widgets.md b/docs/usage/widgets.md
index 7832c9e7f1..468897a21d 100644
--- a/docs/usage/widgets.md
+++ b/docs/usage/widgets.md
@@ -35,8 +35,33 @@ Here's a list of supported alternative widgets for different JSON Schema data ty
* `select`: a select box with `true` and `false` as options;
* by default, a checkbox is used
-> Note: To set the labels for a boolean field, instead of using `true` and `false` you can set `enumNames` in your schema. Note that `enumNames` belongs in your `schema`, not the `uiSchema`, and the order is always `[true, false]`.
+> Note: To set the labels for a boolean field, instead of using `true` and `false`, your schema can use `oneOf` with `const` values for both true and false, where you can specify the custom label in the `title` field. You will also need to specify a widget in your `uiSchema`. See the following example:
+
+schema:
+
+```json
+{
+ "properties": {
+ "booleanWithCustomLabels": {
+ "type": "boolean",
+ "oneOf": [
+ {"const": true, "title": "Custom label for true"},
+ {"const": false, "title": "Custom label for false"}
+ ]
+ }
+ }
+}
+```
+
+uiSchema:
+```json
+ {
+ "booleanWithCustomLabels": {
+ "ui:widget": "radio" // or "select"
+ }
+ }
+```
## For `string` fields
* `textarea`: a `textarea` element is used;
diff --git a/packages/core/src/components/fields/BooleanField.tsx b/packages/core/src/components/fields/BooleanField.tsx
index d61cb37611..368ad8843e 100644
--- a/packages/core/src/components/fields/BooleanField.tsx
+++ b/packages/core/src/components/fields/BooleanField.tsx
@@ -5,6 +5,7 @@ import {
optionsList,
FieldProps,
RJSFSchemaDefinition,
+ EnumOptionsType,
} from "@rjsf/utils";
import isObject from "lodash/isObject";
@@ -35,7 +36,7 @@ function BooleanField(props: FieldProps) {
const { widget = "checkbox", ...options } = getUiOptions(uiSchema);
const Widget = getWidget(schema, widget, widgets);
- let enumOptions;
+ let enumOptions: EnumOptionsType[] | undefined;
if (Array.isArray(schema.oneOf)) {
enumOptions = optionsList({
@@ -52,14 +53,21 @@ function BooleanField(props: FieldProps) {
.filter((o) => o) as RJSFSchemaDefinition[], // cast away the error that typescript can't grok is fixed
});
} else {
- enumOptions = optionsList({
- enum: schema.enum || [true, false],
- enumNames:
- schema.enumNames ||
- (schema.enum && schema.enum[0] === false
- ? ["No", "Yes"]
- : ["Yes", "No"]),
- });
+ schema.enum = schema.enum ?? [true, false];
+ if (
+ schema.enum &&
+ schema.enum.length === 2 &&
+ schema.enum.every((v) => typeof v === "boolean")
+ ) {
+ enumOptions = [
+ { value: schema.enum[0], label: schema.enum[0] ? "Yes" : "No" },
+ { value: schema.enum[1], label: schema.enum[1] ? "Yes" : "No" },
+ ];
+ } else {
+ enumOptions = optionsList({
+ enum: schema.enum,
+ });
+ }
}
return (
diff --git a/packages/core/test/BooleanField_test.js b/packages/core/test/BooleanField_test.js
index c65bf59a0c..5b3e0cdc34 100644
--- a/packages/core/test/BooleanField_test.js
+++ b/packages/core/test/BooleanField_test.js
@@ -324,23 +324,6 @@ describe("BooleanField", () => {
expect(labels).eql(["No", "Yes"]);
});
- it("should support enumNames for radio widgets", () => {
- const { node } = createFormComponent({
- schema: {
- type: "boolean",
- enumNames: ["Yes", "No"],
- },
- formData: true,
- uiSchema: { "ui:widget": "radio" },
- });
-
- const labels = [].map.call(
- node.querySelectorAll(".field-radio-group label"),
- (label) => label.textContent
- );
- expect(labels).eql(["Yes", "No"]);
- });
-
it("should support oneOf titles for radio widgets", () => {
const { node } = createFormComponent({
schema: {
@@ -452,23 +435,6 @@ describe("BooleanField", () => {
expect(onBlur.calledWith(element.id, false)).to.be.true;
});
- it("should support enumNames for select", () => {
- const { node } = createFormComponent({
- schema: {
- type: "boolean",
- enumNames: ["Yes", "No"],
- },
- formData: true,
- uiSchema: { "ui:widget": "select" },
- });
-
- const labels = [].map.call(
- node.querySelectorAll(".field option"),
- (label) => label.textContent
- );
- expect(labels).eql(["", "Yes", "No"]);
- });
-
it("should handle a focus event with checkbox", () => {
const onFocus = sandbox.spy();
const { node } = createFormComponent({
diff --git a/packages/core/test/FormContext_test.js b/packages/core/test/FormContext_test.js
index 6665c9a5a2..d08d3475af 100644
--- a/packages/core/test/FormContext_test.js
+++ b/packages/core/test/FormContext_test.js
@@ -137,8 +137,12 @@ describe("FormContext", () => {
type: "array",
items: {
type: "string",
- enum: ["foo"],
- enumNames: ["bar"],
+ oneOf: [
+ {
+ const: "foo",
+ title: "bar",
+ },
+ ],
},
uniqueItems: true,
},
diff --git a/packages/playground/src/samples/alternatives.js b/packages/playground/src/samples/alternatives.js
index fd1647cfaa..20eabf154a 100644
--- a/packages/playground/src/samples/alternatives.js
+++ b/packages/playground/src/samples/alternatives.js
@@ -67,8 +67,11 @@ module.exports = {
blendMode: {
title: "Blend mode",
type: "string",
- enum: ["screen", "multiply", "overlay"],
- enumNames: ["Screen", "Multiply", "Overlay"],
+ oneOf: [
+ { const: "screen", title: "Screen" },
+ { const: "multiply", title: "Multiply" },
+ { const: "overlay", title: "Overlay" },
+ ],
},
},
},
diff --git a/packages/playground/src/samples/widgets.js b/packages/playground/src/samples/widgets.js
index 4dd727e9b8..d02f397d7c 100644
--- a/packages/playground/src/samples/widgets.js
+++ b/packages/playground/src/samples/widgets.js
@@ -91,7 +91,20 @@ export default {
title: "Custom select widget with options",
type: "string",
enum: ["foo", "bar"],
- enumNames: ["Foo", "Bar"],
+ },
+ selectWidgetOptions2: {
+ title: "Custom select widget with options, overriding the enum titles.",
+ type: "string",
+ oneOf: [
+ {
+ const: "foo",
+ title: "Foo",
+ },
+ {
+ const: "bar",
+ title: "Bar",
+ },
+ ],
},
},
},
diff --git a/packages/utils/src/optionsList.ts b/packages/utils/src/optionsList.ts
index cbda055d91..83a5b7a22c 100644
--- a/packages/utils/src/optionsList.ts
+++ b/packages/utils/src/optionsList.ts
@@ -2,9 +2,8 @@ import toConstant from "./toConstant";
import { RJSFSchema, EnumOptionsType } from "./types";
/** Gets the list of options from the schema. If the schema has an enum list, then those enum values are returned. The
- * labels for the options will be extracted from the non-standard `enumNames` if it exists othewise will be the same as
- * the `value`. If the schema has a `oneOf` or `anyOf`, then the value is the list of `constant` values from the schema
- * and the label is either the `schema.title` or the value.
+ * labels for the options will be the same as the `value`. If the schema has a `oneOf` or `anyOf`, then the value is the
+ * list of `const` values from the schema and the label is either the `schema.title` or the value.
*
* @param schema - The schema from which to extract the options list
* @returns - The list of options from the schema
@@ -13,8 +12,8 @@ export default function optionsList(
schema: RJSFSchema
): EnumOptionsType[] | undefined {
if (schema.enum) {
- return schema.enum.map((value, i) => {
- const label = (schema.enumNames && schema.enumNames[i]) || String(value);
+ return schema.enum.map((value) => {
+ const label = String(value);
return { label, value };
});
}
diff --git a/packages/utils/src/types.ts b/packages/utils/src/types.ts
index 690e0576af..0efac6c076 100644
--- a/packages/utils/src/types.ts
+++ b/packages/utils/src/types.ts
@@ -9,11 +9,9 @@ export type GenericObjectType = {
};
/** Map the JSONSchema7 to our own type so that we can easily bump to JSONSchema8 at some future date and only have to
- * update this one type. Also, because we are supporting the non-standard `enumNames` prop in the code, define it here.
+ * update this one type.
*/
-export type RJSFSchema = JSONSchema7 & {
- enumNames?: string[];
-};
+export type RJSFSchema = JSONSchema7;
/** Map the JSONSchema7Definition to our own type so that we can easily bump to JSONSchema8Definition at some future
* date and only have to update this one type.
diff --git a/packages/utils/test/optionsList.test.ts b/packages/utils/test/optionsList.test.ts
index 304b0d4deb..5fc40b3675 100644
--- a/packages/utils/test/optionsList.test.ts
+++ b/packages/utils/test/optionsList.test.ts
@@ -7,19 +7,9 @@ describe("optionsList()", () => {
enum: ["Opt1", "Opt2", "Opt3"],
};
- const enumNameSchema = {
- ...enumSchema,
- enumNames: ["Option1", "Option2", "Option3"],
- };
expect(optionsList(enumSchema)).toEqual(
enumSchema.enum!.map((opt) => ({ label: opt, value: opt }))
);
- expect(optionsList(enumNameSchema)).toEqual(
- enumNameSchema.enum!.map((opt, index) => {
- const label = enumNameSchema.enumNames[index] || opt;
- return { label: label, value: opt };
- })
- );
});
it("should generate options for a oneOf|anyOf schema", () => {
const oneOfSchema = {