Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[docs] Create the FormControl page #32073

Merged
merged 3 commits into from
Apr 1, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
51 changes: 51 additions & 0 deletions docs/data/base/components/form-control/UseFormControl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as React from 'react';
import FormControlUnstyled, {
useFormControlUnstyled,
} from '@mui/base/FormControlUnstyled';

function CustomInput() {
const formControlContext = useFormControlUnstyled();

if (formControlContext === undefined) {
return null;
}

const { value, required, onChange, disabled, onFocus, onBlur } =
formControlContext;

return (
<input
value={value}
required={required}
onChange={onChange}
disabled={disabled}
onFocus={onFocus}
onBlur={onBlur}
/>
);
}

function ControlStateDisplay() {
const formControlContext = useFormControlUnstyled();
if (formControlContext === undefined) {
return null;
}

const { filled, focused } = formControlContext;

return (
<p>
{filled ? 'filled' : 'empty'}&nbsp;|&nbsp;
{focused ? 'focused' : 'not focused'}
</p>
);
}

export default function UseFormControl() {
return (
<FormControlUnstyled defaultValue="" required>
<CustomInput />
<ControlStateDisplay />
</FormControlUnstyled>
);
}
51 changes: 51 additions & 0 deletions docs/data/base/components/form-control/UseFormControl.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as React from 'react';
import FormControlUnstyled, {
useFormControlUnstyled,
} from '@mui/base/FormControlUnstyled';

function CustomInput() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this demo nicely shows the usage, I think it would be useful to create a more "real life" example maybe using the InputUnstyled too.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I say more "real life" I mean input with some validation and error message.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added another demo with InputUnstyled.

const formControlContext = useFormControlUnstyled();

if (formControlContext === undefined) {
return null;
}

const { value, required, onChange, disabled, onFocus, onBlur } =
formControlContext;

return (
<input
value={value as string}
required={required}
onChange={onChange}
disabled={disabled}
onFocus={onFocus}
onBlur={onBlur}
/>
);
}

function ControlStateDisplay() {
const formControlContext = useFormControlUnstyled();
if (formControlContext === undefined) {
return null;
}

const { filled, focused } = formControlContext;

return (
<p>
{filled ? 'filled' : 'empty'}&nbsp;|&nbsp;
{focused ? 'focused' : 'not focused'}
</p>
);
}

export default function UseFormControl() {
return (
<FormControlUnstyled defaultValue="" required>
<CustomInput />
<ControlStateDisplay />
</FormControlUnstyled>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<FormControlUnstyled defaultValue="" required>
<CustomInput />
<ControlStateDisplay />
</FormControlUnstyled>
58 changes: 58 additions & 0 deletions docs/data/base/components/form-control/form-control.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
product: base
title: React form control
components: FormControlUnstyled
packageName: '@mui/base'
---

# Unstyled form control

<p class="description">
The FormControlUnstyled is a utility that lets you associate a form input with auxillary components,
such as labels, error indicators or helper text.
</p>

{{"component": "modules/components/ComponentLinkHeader.js", "design": false}}

## FormControlUnstyled

FormControlUnstyled wraps an input and other components and enables reflecting the input's state in these other components.
michaldudak marked this conversation as resolved.
Show resolved Hide resolved

For instance, you may show additional element asking the user to enter a value if the input is empty or display a warning icon when the entered value is incorrect.
michaldudak marked this conversation as resolved.
Show resolved Hide resolved

The FormControlUnstyled provides a context that can be read by the useFormControl hook.

## useFormControl hook

The useFormControl hook can be used to enable integration between custom form inputs and FormControlUnstyled.
Additionally, you can read the form control's state and react to its changes in a custom component.

The demo below shows both.
`CustomInput` is a wrapper around a native HTML `input` that adds FormControlUnstyled integration.
`ControlStateDisplay` reads the state of the form control and displays it as text.

{{"demo": "UseFormControl.js", "defaultCodeOpen": false}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Since we have only 1 demo in this page, we can show the code by default.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided not to show it as the code in the preview does not explain the concept. It's the code outside the main function that matters in this case.


Note that even though FormControlUnstyled supports both controlled and uncontrolled-style API
(i.e. it accepts `value` and `defaultValue` props), `useFormControl` returns only the controlled `value`.
This way, you don't have to implement both in your custom input - FormControlUnstyled does this for you.

`useFormControl` returns an object with the following fields:

| Name | Type | Description |
| ---------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `disabled` | boolean | Represents the value of the FormControlUnstyled's `disabled` prop. |
| `error` | boolean | Represents the value of the FormControlUnstyled's `error` prop. Note that it is not calculated automatically (i.e. it's not set when `required: true` and `value: ''`) |
| `filled` | boolean | Set to `true` if `value` is not empty. |
| `focused` | boolean | Set to `true` if the wrapped input has received focus. |
| `required` | boolean | Represents the value of the FormControlUnstyled's `required` prop. |
| `value` | unknown | The current value of the form control. |

Additionally, the following callbacks are a part of the returned object.
They are meant to be used when creating custom inputs.

| Name | Type | Description |
| ---------- | ------------------------- | ------------------------------------------------------------- |
| `onChange` | React.ChangeEvent => void | Change handler. Should be forwarded to the inner input. |
Copy link
Member

@hbjORbj hbjORbj Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Value change handler is more descriptive?

| `onBlur` | () => void | Focus change handler. Should be forwarded to the inner input. |
| `onFocus` | () => void | Focus change handler. Should be forwarded to the inner input. |
1 change: 1 addition & 0 deletions docs/data/base/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const pages = [
subheader: 'utils',
children: [
{ pathname: '/base/react-click-away-listener', title: 'Click-away listener' },
{ pathname: '/base/react-form-control', title: 'Form control' },
{ pathname: '/base/react-modal', title: 'Modal' },
{ pathname: '/base/react-no-ssr', title: 'No SSR' },
{ pathname: '/base/react-popper', title: 'Popper' },
Expand Down
2 changes: 1 addition & 1 deletion docs/data/material/components/text-fields/text-fields.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
product: material-ui
title: Text Field React component
components: FilledInput, FormControl, FormControlUnstyled, FormHelperText, Input, InputAdornment, InputBase, InputLabel, OutlinedInput, TextField
components: FilledInput, FormControl, FormHelperText, Input, InputAdornment, InputBase, InputLabel, OutlinedInput, TextField
githubLabel: 'component: text field'
materialDesign: https://material.io/components/text-fields
unstyled: /base/react-input/
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/api-docs/form-control-unstyled.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@
"forwardsRefTo": "HTMLDivElement",
"filename": "/packages/mui-base/src/FormControlUnstyled/FormControlUnstyled.tsx",
"inheritance": null,
"demos": "<ul><li><a href=\"/components/text-fields/\">Text Fields</a></li></ul>",
"demos": "<ul><li><a href=\"/components/form-control/\">Form Control</a></li>\n<li><a href=\"/components/text-fields/\">Text Fields</a></li></ul>",
"cssComponent": false
}
2 changes: 1 addition & 1 deletion docs/pages/base/api/form-control-unstyled.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@
"forwardsRefTo": "HTMLDivElement",
"filename": "/packages/mui-base/src/FormControlUnstyled/FormControlUnstyled.tsx",
"inheritance": null,
"demos": "<ul><li><a href=\"/material-ui/react-text-field/\">Text Fields</a></li></ul>",
"demos": "<ul><li><a href=\"/base/components/form-control/\">Form Control</a></li></ul>",
"cssComponent": false
}
11 changes: 11 additions & 0 deletions docs/pages/base/react-form-control.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as React from 'react';
import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';
import {
demos,
docs,
demoComponents,
} from 'docs/data/base/components/form-control/form-control.md?@mui/markdown';

export default function Page() {
return <MarkdownDocs demos={demos} docs={docs} demoComponents={demoComponents} />;
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export type FormControlUnstyledOwnerState = Omit<
*
* Demos:
*
* - [Form Control](https://mui.com/components/form-control/)
* - [Text Fields](https://mui.com/components/text-fields/)
*
* API:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,6 @@ export interface FormControlUnstyledOwnProps {
* @default false
*/
error?: boolean;
/**
* Extra properties to be placed on the FormControlContext.
* @default {}
*/
extraContextProperties?: object;
/**
* If `true`, the component is displayed in focused state.
* @default false
Expand Down