-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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'} | | ||
{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,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 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'} | | ||
{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> |
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}} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: |
||
| `onBlur` | () => void | Focus change handler. Should be forwarded to the inner input. | | ||
| `onFocus` | () => void | Focus change handler. Should be forwarded to the inner input. | |
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} />; | ||
} |
There was a problem hiding this comment.
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.There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.