Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 35 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ react-jsonschema-form

[![Build Status](https://travis-ci.org/mozilla-services/react-jsonschema-form.svg)](https://travis-ci.org/mozilla-services/react-jsonschema-form)

A simple [React](http://facebook.github.io/react/) component capable of building
HTML forms out of a [JSON schema](http://jsonschema.net/).
A simple [React](http://facebook.github.io/react/) component capable of building HTML forms out of a [JSON schema](http://jsonschema.net/).

Requires React 0.14+.

Expand Down Expand Up @@ -60,15 +59,46 @@ render((
), document.getElementById("app"));
```

### Alternative widgets

JSONSchema is limited for describing how a given data type should be rendered as an input component, that's why this lib introduces the concept of *UI schema*. A UI schema is basically an object literal describing which UI widget should be used to render a certain field

Example:

```js
const uiSchema =  {
done: {
widget: "radio" // could also be "select"
}
};

render((
<Form schema={schema}
uiSchema={uiSchema}
formData={formData} />
), document.getElementById("app"));
```

Here's a list of supported alternative widgets for different JSONSchema data types:

#### `boolean`

* `radio`: a radio button group with `true` and `false` as selectable values;
* `select`: a select box with `true` and `false` as options;
* by default, a checkbox is used

#### `string`:

* `textarea`: a `textarea` element
* by default, a regular `input[type=text]` element is used.

## Development server

```
$ npm start
```

A [Cosmos development server](https://github.com/skidding/cosmos) showcasing
components with hot reload enabled is available at
[localhost:8080](http://localhost:8080).
A [Cosmos development server](https://github.com/skidding/cosmos) showcasing components with hot reload enabled is available at [localhost:8080](http://localhost:8080).

## Tests

Expand Down
46 changes: 46 additions & 0 deletions fixtures/Form/nested-default.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
module.exports = {
schema: {
title: "Todo Tasks",
description: "Tasks collection.",
type: "object",
additionalProperties: false,
required: [
"title", "tasks"
],
default: {
title: "Default task list",
tasks: [
{title: "A default task", done: true},
{title: "Another default task", done: false},
]
},
properties: {
title: {
type: "string",
title: "Tasks list title",
},
tasks: {
type: "array",
title: "Tasks list",
items: {
type: "object",
properties: {
done: {
type: "boolean",
title: "Done?",
description: "Is that task done already?"
},
title: {
type: "string",
title: "Title",
description: "The task title.",
minLength: 1
}
}
}
}
}
},
onSubmit: console.log.bind(console, "submit"),
onError: console.log.bind(console, "errors")
};
62 changes: 62 additions & 0 deletions fixtures/Form/nested-uiSchema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
module.exports = {
schema: {
title: "Todo Tasks",
description: "Tasks collection.",
type: "object",
additionalProperties: false,
required: [
"title", "tasks"
],
properties: {
title: {
type: "string",
title: "Tasks list title",
},
tasks: {
type: "array",
title: "Tasks list",
items: {
type: "object",
properties: {
type: {
type: "string",
title: "Category",
enum: ["coding", "sleeping"]
},
done: {
type: "boolean",
title: "Done?",
description: "Is that task done already?"
},
title: {
type: "string",
title: "Title",
description: "The task title.",
minLength: 1
}
}
}
}
}
},
uiSchema: {
title: {
widget: "textarea",
},
tasks: {
items: {
type: {
widget: "radio"
},
done: {
widget: "radio",
},
title: {
widget: "textarea"
}
}
}
},
onSubmit: console.log.bind(console, "submit"),
onError: console.log.bind(console, "errors")
};
2 changes: 1 addition & 1 deletion fixtures/fields/ArrayField/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ module.exports = {
title: "item"
}
},
onChange: console.log.bind(console)
onChange: console.log.bind(console, "change")
};
2 changes: 1 addition & 1 deletion fixtures/fields/ArrayField/with-default.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ module.exports = {
title: "item"
}
},
onChange: console.log.bind(console)
onChange: console.log.bind(console, "change")
};
2 changes: 1 addition & 1 deletion fixtures/fields/ArrayField/with-formData.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ module.exports = {
}
},
formData: ["item1", "item2"],
onChange: console.log.bind(console)
onChange: console.log.bind(console, "change")
};
17 changes: 17 additions & 0 deletions fixtures/fields/ArrayField/with-uiSchema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module.exports = {
schema: {
type: "array",
title: "title",
items: {
type: "string",
title: "item"
}
},
uiSchema: {
items: {
widget: "textarea"
}
},
formData: ["item1", "item2"],
onChange: console.log.bind(console, "change")
};
2 changes: 1 addition & 1 deletion fixtures/fields/BooleanField/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ module.exports = {
type: "boolean",
title: "My boolean",
},
onChange: console.log.bind(console)
onChange: console.log.bind(console, "change")
};
2 changes: 1 addition & 1 deletion fixtures/fields/BooleanField/with-default.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ module.exports = {
title: "My boolean",
default: true,
},
onChange: console.log.bind(console)
onChange: console.log.bind(console, "change")
};
2 changes: 1 addition & 1 deletion fixtures/fields/BooleanField/with-formData.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ module.exports = {
title: "My boolean",
},
formData: true,
onChange: console.log.bind(console)
onChange: console.log.bind(console, "change")
};
11 changes: 11 additions & 0 deletions fixtures/fields/BooleanField/with-uiSchema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = {
schema: {
type: "boolean",
title: "My boolean"
},
uiSchema: {
widget: "radio"
},
formData: false,
onChange: console.log.bind(console, "change")
};
2 changes: 1 addition & 1 deletion fixtures/fields/ObjectField/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ module.exports = {
}
}
},
onChange: console.log.bind(console)
onChange: console.log.bind(console, "change")
};
2 changes: 1 addition & 1 deletion fixtures/fields/ObjectField/with-default.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ module.exports = {
}
}
},
onChange: console.log.bind(console)
onChange: console.log.bind(console, "change")
};
2 changes: 1 addition & 1 deletion fixtures/fields/ObjectField/with-formData.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ module.exports = {
string: "an existing string",
bool: true
},
onChange: console.log.bind(console)
onChange: console.log.bind(console, "change")
};
25 changes: 25 additions & 0 deletions fixtures/fields/ObjectField/with-uiSchema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module.exports = {
schema: {
type: "object",
title: "object title",
properties: {
string: {
type: "string",
title: "string"
},
bool: {
type: "boolean",
title: "bool"
}
}
},
uiSchema: {
string: {
widget: "textarea"
},
bool: {
widget: "select"
}
},
onChange: console.log.bind(console, "change")
};
2 changes: 1 addition & 1 deletion fixtures/fields/SchemaField/array.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ module.exports = {
title: "item"
}
},
onChange: console.log.bind(console)
onChange: console.log.bind(console, "change")
};
2 changes: 1 addition & 1 deletion fixtures/fields/SchemaField/boolean.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ module.exports = {
type: "boolean",
title: "My boolean",
},
onChange: console.log.bind(console)
onChange: console.log.bind(console, "change")
};
2 changes: 1 addition & 1 deletion fixtures/fields/SchemaField/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ module.exports = {
}
}
},
onChange: console.log.bind(console)
onChange: console.log.bind(console, "change")
};
10 changes: 10 additions & 0 deletions fixtures/fields/StringField/with-uiSchema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module.exports = {
schema: {
type: "string",
title: "string",
},
uiSchema: {
widget: "textarea"
},
formData: "an existing string"
};
2 changes: 1 addition & 1 deletion fixtures/widgets/CheckboxWidget/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = {
type: "boolean",
label: "foo",
onChange: console.log.bind(console)
onChange: console.log.bind(console, "change")
};
2 changes: 1 addition & 1 deletion fixtures/widgets/RadioWidget/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ module.exports = {
label: "foo",
defaultValue: "b",
options: ["a", "b"],
onChange: console.log.bind(console)
onChange: console.log.bind(console, "change")
};
2 changes: 1 addition & 1 deletion fixtures/widgets/SelectWidget/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ module.exports = {
type: "string",
label: "foo",
options: ["foo", "bar", "baz"],
onChange: console.log.bind(console)
onChange: console.log.bind(console, "change")
};
2 changes: 1 addition & 1 deletion fixtures/widgets/TextWidget/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ module.exports = {
type: "string",
label: "foo",
value: "plop",
onChange: console.log.bind(console)
onChange: console.log.bind(console, "change")
};
20 changes: 17 additions & 3 deletions src/components/Form.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
import React from "react";
import React, { Component, PropTypes } from "react";
import { Validator } from "jsonschema";

import SchemaField from "./fields/SchemaField";
import ErrorList from "./ErrorList";


export default class Form extends React.Component {
export default class Form extends Component {
static propTypes = {
schema: PropTypes.object.isRequired,
uiSchema: PropTypes.object,
formData: PropTypes.any,
onChange: PropTypes.func,
onError: PropTypes.func,
onSubmit: PropTypes.func,
}

static defaultProps = {
uiSchema: {}
}

constructor(props) {
super(props);
const edit = !!props.formData;
Expand Down Expand Up @@ -63,13 +76,14 @@ export default class Form extends React.Component {
}

render() {
const {schema} = this.props;
const {schema, uiSchema} = this.props;
const {formData} = this.state;
return (
<form className="generic-form" onSubmit={this.onSubmit.bind(this)}>
{this.renderErrors()}
<SchemaField
schema={schema}
uiSchema={uiSchema}
formData={formData}
onChange={this.onChange.bind(this)} />
<p><button type="submit">Submit</button></p>
Expand Down
Loading