-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Open
Labels
Description
Prerequisites
- I have searched the existing issues
- I understand that providing a SSCCE example is tremendously useful to the maintainers.
- I have read the documentation
- Ideally, I'm providing a sample JSFiddle, Codesandbox.io or preferably a shared playground link demonstrating the issue.
What theme are you using?
core
Version
5.x
Current Behavior
When using a JSON Schema that combines a discriminated union with null using anyOf, the form does not render the discriminated union options correctly. Instead, it only allows selecting the null option, and the expected fields for the other options are not displayed.
Expected Behavior
The form should correctly render the options from the discriminated union alongside the null option, allowing users to select any of the available types or null.
Steps To Reproduce
- Use the following JSON Schema in the react-jsonschema-form playground or your environment:
Failing Json Schema
{
"$defs": {
"LogitechMouse": {
"additionalProperties": false,
"properties": {
"name": {
"default": "Logitech Mouse",
"title": "Name",
"type": "string"
},
"price": {
"default": 10.0,
"title": "Price",
"type": "number"
},
"type": {
"const": "peripheral",
"default": "peripheral",
"enum": [
"peripheral"
],
"title": "Type",
"type": "string"
},
"kind": {
"const": "mouse",
"default": "mouse",
"enum": [
"mouse"
],
"title": "Kind",
"type": "string"
},
"max_dpi": {
"default": 600,
"title": "Max Dpi",
"type": "integer"
},
"brand": {
"const": "Logitech",
"default": "Logitech",
"enum": [
"Logitech"
],
"title": "Brand",
"type": "string"
}
},
"title": "LogitechMouse",
"type": "object"
},
"RazerMouse": {
"additionalProperties": false,
"properties": {
"name": {
"default": "Razer Mouse",
"title": "Name",
"type": "string"
},
"price": {
"default": 20.0,
"title": "Price",
"type": "number"
},
"type": {
"const": "peripheral",
"default": "peripheral",
"enum": [
"peripheral"
],
"title": "Type",
"type": "string"
},
"kind": {
"const": "mouse",
"default": "mouse",
"enum": [
"mouse"
],
"title": "Kind",
"type": "string"
},
"max_dpi": {
"default": 1200,
"title": "Max Dpi",
"type": "integer"
},
"brand": {
"const": "Razer",
"default": "Razer",
"enum": [
"Razer"
],
"title": "Brand",
"type": "string"
}
},
"title": "RazerMouse",
"type": "object"
}
},
"properties": {
"components": {
"anyOf": [
{
"discriminator": {
"mapping": {
"Logitech": "#/$defs/LogitechMouse",
"Razer": "#/$defs/RazerMouse"
},
"propertyName": "brand"
},
"oneOf": [
{
"$ref": "#/$defs/LogitechMouse"
},
{
"$ref": "#/$defs/RazerMouse"
}
],
"title": "AvailableMouses"
},
{
"type": "null"
}
],
"title": "Components"
}
},
"required": [
"components"
],
"title": "Computer",
"type": "object"
}
- Render the form (https://rjsf-team.github.io/react-jsonschema-form/)
- Attempt to select options other than null for the components field.
- Observe that only the null option is selectable, and the discriminated union options are not available.
To prove that the discriminated union
is not the problem, here's the same json without combining it with the null
option:
Working Json Schema
{
"$defs": {
"LogitechMouse": {
"additionalProperties": false,
"properties": {
"name": {
"default": "Logitech Mouse",
"title": "Name",
"type": "string"
},
"price": {
"default": 10.0,
"title": "Price",
"type": "number"
},
"type": {
"const": "peripheral",
"default": "peripheral",
"enum": [
"peripheral"
],
"title": "Type",
"type": "string"
},
"kind": {
"const": "mouse",
"default": "mouse",
"enum": [
"mouse"
],
"title": "Kind",
"type": "string"
},
"max_dpi": {
"default": 600,
"title": "Max Dpi",
"type": "integer"
},
"brand": {
"const": "Logitech",
"default": "Logitech",
"enum": [
"Logitech"
],
"title": "Brand",
"type": "string"
}
},
"title": "LogitechMouse",
"type": "object"
},
"RazerMouse": {
"additionalProperties": false,
"properties": {
"name": {
"default": "Razer Mouse",
"title": "Name",
"type": "string"
},
"price": {
"default": 20.0,
"title": "Price",
"type": "number"
},
"type": {
"const": "peripheral",
"default": "peripheral",
"enum": [
"peripheral"
],
"title": "Type",
"type": "string"
},
"kind": {
"const": "mouse",
"default": "mouse",
"enum": [
"mouse"
],
"title": "Kind",
"type": "string"
},
"max_dpi": {
"default": 1200,
"title": "Max Dpi",
"type": "integer"
},
"brand": {
"const": "Razer",
"default": "Razer",
"enum": [
"Razer"
],
"title": "Brand",
"type": "string"
}
},
"title": "RazerMouse",
"type": "object"
}
},
"properties": {
"components": {
"discriminator": {
"mapping": {
"Logitech": "#/$defs/LogitechMouse",
"Razer": "#/$defs/RazerMouse"
},
"propertyName": "brand"
},
"oneOf": [
{
"$ref": "#/$defs/LogitechMouse"
},
{
"$ref": "#/$defs/RazerMouse"
}
],
"title": "AvailableMouses"
}
},
"required": [
"components"
],
"title": "Computer",
"type": "object"
}
Environment
-- using the live-playground (same behavior happens running locally) --
OS: Ubuntu 22.04.2 LTS on Windows 10 x86_64
Node: v20.5.0
npm: 9.8.0
Anything else?
Off-topic: I'm using Pydantic
(version 2.9.2) to generate those Json-Schemas; here's the code:
Pydantic Code
from pydantic import BaseModel, Field, ConfigDict
from typing import Annotated, Literal, Union
class BaseProduct(BaseModel):
name: str
price: float
class BaseHardware(BaseProduct):
type: Literal["hardware"] = "hardware"
class BasePeripheral(BaseProduct):
type: Literal["peripheral"] = "peripheral"
class BaseMouseProduct(BasePeripheral):
kind: Literal["mouse"] = "mouse"
max_dpi: int
class LogitechMouse(BaseMouseProduct):
model_config = ConfigDict(extra="forbid")
brand: Literal["Logitech"] = "Logitech"
name: str = Field("Logitech Mouse")
max_dpi: int = Field(600)
price: float = Field(10.0)
class RazerMouse(BaseMouseProduct):
model_config = ConfigDict(extra="forbid")
brand: Literal["Razer"] = "Razer"
name: str = Field("Razer Mouse")
max_dpi: int = Field(1200)
price: float = Field(20.0)
AvailableMouses = Annotated[
Union[LogitechMouse, RazerMouse],
Field(title="AvailableMouses", discriminator="brand")
]
class Computer(BaseModel):
components: Union[AvailableMouses, None]
if __name__ == "__main__":
print(Computer.schema_json(indent=2))
giacomorebecchi