-
Couldn't load subscription status.
- Fork 32
docs: Revamp GridForm docs #3187
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
base: main
Are you sure you want to change the base?
Changes from all commits
53167ab
fff7888
cef1cbf
3a53551
b1d05a8
05c00fb
ec5e503
9562d55
6dbaf28
f8dbe30
309c8a3
7d5ddfa
8f9a058
a34b0b5
641aeb2
86152dc
5108c8c
f67e05d
fea9287
e2e3cc6
8c65ca0
d6b147e
5694439
a562cc1
82d2598
6208a48
9a809ff
b55a426
05f8fab
18bc8fd
79cb2d9
4a31dec
61bc85d
90cb56a
b71d85f
b920435
c380ed9
253e249
50ca32b
3d94191
33b6332
951a98f
59ebec6
b491baa
94029e1
5aebe44
0757139
bddbdb3
c22064f
7c923dc
4097e9a
0506a55
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,35 @@ | ||
| import { Meta } from '@storybook/blocks'; | ||
|
|
||
| import { | ||
| AboutHeader, | ||
| addParentPath, | ||
| TableOfContents, | ||
| } from '~styleguide/blocks'; | ||
|
|
||
| import { parameters as buttonsParameters } from './Buttons.mdx'; | ||
| import { parameters as fieldsParameters } from './Fields.mdx'; | ||
| import { parameters as layoutParameters } from './Layout.mdx'; | ||
| import { parameters as statesParameters } from './States.mdx'; | ||
| import { parameters as usageParameters } from './Usage.mdx'; | ||
| import { parameters as validationParameters } from './Validation.mdx'; | ||
|
|
||
| export const parameters = { | ||
| id: 'Organisms/GridForm', | ||
| title: 'GridForm', | ||
| subtitle: 'An efficient way to build and design forms on a grid.', | ||
| }; | ||
|
|
||
| <Meta title="Organisms/GridForm/About" /> | ||
|
|
||
| <AboutHeader {...parameters} /> | ||
|
|
||
| <TableOfContents | ||
| links={addParentPath(parameters.id, [ | ||
| usageParameters, | ||
| fieldsParameters, | ||
| buttonsParameters, | ||
| validationParameters, | ||
| layoutParameters, | ||
| statesParameters, | ||
| ])} | ||
| /> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| import { Canvas, Meta } from '@storybook/blocks'; | ||
|
|
||
| import { ComponentHeader, LinkTo } from '~styleguide/blocks'; | ||
|
|
||
| import * as ButtonsStories from './Buttons.stories'; | ||
|
|
||
| export const parameters = { | ||
| title: 'Buttons', | ||
| subtitle: 'Configure submit and cancel buttons for your forms.', | ||
| }; | ||
|
|
||
| <Meta title="Organisms/GridForm/Buttons" /> | ||
|
|
||
| <ComponentHeader {...parameters} /> | ||
|
|
||
| ## Submit button position | ||
|
|
||
| We can position the submit button by passing the `position` prop within `submit` with a | ||
| value of `'left'`, `'center'`, `'right'`, or `'stretch'`. The default is `'left'`. | ||
|
|
||
| <Canvas of={ButtonsStories.SubmitButtonRight} /> | ||
|
|
||
| <Canvas of={ButtonsStories.SubmitButtonLeft} /> | ||
|
|
||
| <Canvas of={ButtonsStories.SubmitButtonCenter} /> | ||
|
|
||
| <Canvas of={ButtonsStories.SubmitButtonStretch} /> | ||
|
|
||
| ## Submit button type | ||
|
|
||
| We can specify the type submit button by passing the `type` prop within `submit`. We can choose between | ||
| the <LinkTo id="atoms-button--fill-button">`FillButton`</LinkTo> or <LinkTo id="atoms-button--cta-button">`CTAButton`</LinkTo>. The default is `'fill'`. | ||
|
|
||
| <Canvas of={ButtonsStories.SubmitButtonFill} /> | ||
|
|
||
| <Canvas of={ButtonsStories.SubmitButtonCTA} /> | ||
|
|
||
| ## Inline submit button | ||
|
|
||
| We can make the Submit button inline with an input by setting the column | ||
| sizes so they fit on the same row (e.g size 8 for an input and size 4 for | ||
|
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. In the actual example it has input of size 6 and the submit button's size 4, should the example follow the guidance in this MDX file? 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. good catch, i updated them to all use the shared args but will make this match |
||
| the submit). | ||
|
|
||
| We can additionally remove the label from text inputs and checkbox inputs. | ||
| Use the `hideLabel` prop to remove the label, allowing the submit button to | ||
| align nicely with the input. **However**, if using `hideLabel` to remove the default label, you should provide an `aria-label` and/or include another label to the right/left of the input to ensure the input is accessible. | ||
|
|
||
| <Canvas of={ButtonsStories.SubmitButtonInline} /> | ||
|
|
||
| ## Cancel button | ||
|
|
||
| Optionally, include a cancel button. | ||
|
|
||
| <Canvas of={ButtonsStories.CancelButton} /> | ||
|
|
||
| ## Button states | ||
|
|
||
| ### Loading | ||
|
|
||
| We can set the state of the submit button to `loading` as `true` to show a loading spinner. This is useful when you need to show the user that the form is submitting. | ||
|
|
||
| <Canvas of={ButtonsStories.Loading} /> | ||
|
|
||
| ### Disabled | ||
|
|
||
| You can also set `disabled` to `true` to disable submission. | ||
|
|
||
| <Canvas of={ButtonsStories.Disabled} /> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| import { GridForm } from '@codecademy/gamut'; | ||
| import { action } from '@storybook/addon-actions'; | ||
| import type { Meta, StoryObj } from '@storybook/react'; | ||
|
|
||
| const meta: Meta<typeof GridForm> = { | ||
| component: GridForm, | ||
| args: { | ||
| onSubmit: (values) => { | ||
| action('Form Submitted')(values); | ||
| // eslint-disable-next-line no-console | ||
| console.log('Form Submitted', values); | ||
| }, | ||
| fields: [ | ||
| { | ||
| label: 'Simple text', | ||
| name: 'simple-text', | ||
| type: 'text', | ||
| size: 12, | ||
| }, | ||
| ], | ||
| }, | ||
| }; | ||
|
|
||
| export default meta; | ||
| type Story = StoryObj<typeof GridForm>; | ||
|
|
||
| export const SubmitButtonRight: Story = { | ||
| args: { | ||
| submit: { | ||
| contents: 'Right Submit!?', | ||
| position: 'right', | ||
| size: 12, | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| export const SubmitButtonLeft: Story = { | ||
| args: { | ||
| submit: { | ||
| contents: 'Left Submit!?', | ||
| position: 'left', | ||
| size: 12, | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| export const SubmitButtonCenter: Story = { | ||
| args: { | ||
| submit: { | ||
| contents: 'Center Submit!?', | ||
| position: 'center', | ||
| size: 12, | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| export const SubmitButtonStretch: Story = { | ||
| args: { | ||
| submit: { | ||
| contents: 'Stretch Submit!?', | ||
| position: 'stretch', | ||
| size: 12, | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| export const SubmitButtonFill: Story = { | ||
| args: { | ||
| submit: { | ||
| contents: 'Fill Submit!?', | ||
| type: 'fill', | ||
| size: 12, | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| export const SubmitButtonCTA: Story = { | ||
| args: { | ||
| submit: { | ||
| contents: 'CTA Submit!?', | ||
| type: 'cta', | ||
| size: 12, | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| export const SubmitButtonInline: Story = { | ||
| args: { | ||
| fields: [ | ||
| { | ||
| label: 'Simple text', | ||
| name: 'simple-text', | ||
| type: 'text', | ||
| size: 6, | ||
| }, | ||
| ], | ||
| submit: { | ||
| contents: 'Inline Submit!?', | ||
| size: 4, | ||
| position: 'right', | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| export const CancelButton: Story = { | ||
| args: { | ||
| cancel: { | ||
| children: 'Cancel', | ||
| onClick: () => {}, | ||
| }, | ||
| submit: { | ||
| contents: 'Submit!?', | ||
| position: 'right', | ||
| size: 12, | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| export const Loading: Story = { | ||
| args: { | ||
| submit: { | ||
| contents: 'Loading Submit!?', | ||
| loading: true, | ||
| size: 12, | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| export const Disabled: Story = { | ||
| args: { | ||
| submit: { | ||
| contents: 'Disabled Submit!?', | ||
| disabled: true, | ||
| size: 12, | ||
| }, | ||
| }, | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| import { Canvas, Meta } from '@storybook/blocks'; | ||
|
|
||
| import { ComponentHeader } from '~styleguide/blocks'; | ||
|
|
||
| import * as FieldsStories from './Fields.stories'; | ||
|
|
||
| export const parameters = { | ||
| title: 'Fields', | ||
| subtitle: 'Comprehensive GridForm field types to cover various input needs.', | ||
| }; | ||
|
|
||
| <Meta title="Organisms/GridForm/Fields" /> | ||
|
|
||
| <ComponentHeader {...parameters} /> | ||
|
|
||
| ## Text inputs | ||
|
|
||
| Text inputs support various HTML input types including `text`, `email`, `password`, `number`, `tel`, `url`, `search`, `date`, `time`, and more. All text inputs share the same basic properties but may have different validation patterns. | ||
|
|
||
| <Canvas of={FieldsStories.TextField} /> | ||
|
|
||
| ### Default value | ||
|
|
||
| <Canvas of={FieldsStories.DefaultTextField} /> | ||
|
|
||
| ### Placeholder text | ||
|
|
||
| Text inputs are allowed to have traditional `placeholder` text. | ||
| This is a somewhat dangerous behavior for accessibility, as browsers | ||
| generally don't render placeholder text with high enough color contrast | ||
| for AA standards. If you do need to use placeholder text, such as on | ||
| landing page forms that have been shown to have higher completion rates | ||
| with the text, please make sure the placeholder text doesn't add any new | ||
| information to the form — it should really only rephrase the text label. | ||
|
|
||
| See [this article](https://www.nngroup.com/articles/form-design-placeholders/) for | ||
| more details on why using placeholders is often bad. | ||
|
|
||
| <Canvas of={FieldsStories.PlaceholderTextField} /> | ||
|
|
||
| ## Textarea input | ||
|
|
||
| <Canvas of={FieldsStories.TextareaField} /> | ||
|
|
||
| ## Select input | ||
|
|
||
| <Canvas of={FieldsStories.SelectField} /> | ||
|
|
||
| ## Radio group input | ||
|
|
||
| <Canvas of={FieldsStories.RadioGroupField} /> | ||
|
|
||
| ## File upload input | ||
|
|
||
| File upload fields allow users to select and upload files. You can add custom validation to restrict file types and sizes. | ||
|
|
||
| <Canvas of={FieldsStories.FileUploadField} /> | ||
|
|
||
| ## Checkbox input | ||
|
|
||
| <Canvas of={FieldsStories.CheckboxField} /> | ||
|
|
||
| ### Spacing | ||
|
|
||
| Checkboxes can use tight spacing when you need them to fit in smaller areas: | ||
|
|
||
| <Canvas of={FieldsStories.CheckboxSpacing} /> | ||
|
Comment on lines
+61
to
+67
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. |
||
|
|
||
| ## Nested checkboxes input | ||
|
|
||
| Nested checkboxes allow for hierarchical selection with parent-child relationships between options. Infinite levels of nesting are supported. Clicking a parent checkbox toggles all its children accordingly. Individual child checkboxes can be toggled independently. Checkbox states are `checked` if all children are checked, `indeterminate` if some children are checked, or `unchecked` if no children are checked. The values returned by the form on submit or update are an array of all selected values, including all children. | ||
|
|
||
| <Canvas of={FieldsStories.NestedCheckboxesField} /> | ||
|
|
||
| ## Custom inputs | ||
|
|
||
| Some forms, such as the checkout flows that use Recurly, need to define | ||
| their own inputs. We can specify a `'custom'` field type along with a [`render` prop](https://reactjs.org/docs/render-props.html). | ||
|
|
||
| We also have a `'custom-group'` type for when you are passing in a custom `FormGroup` - including a label. If you do not want `GridForm` to surface errors for your field, you should likely use a `'custom-group'`. If you chose to go this route, please be aware of [accessibility best practices](https://www.deque.com/blog/anatomy-of-accessible-forms-best-practices/) for forms. | ||
|
|
||
| <Canvas of={FieldsStories.CustomInputs} /> | ||
|
|
||
| ## Hidden input | ||
|
|
||
| Hidden inputs can be used to include data that users can't see or modify with the submission. For this implementation you can set the `defaultValue` in the object and it will be submitted with the regular form data. | ||
|
|
||
| <Canvas of={FieldsStories.HiddenInput} /> | ||
|
|
||
| ## Sweet container input | ||
|
|
||
| "Sweet container" ([honeypot](<https://en.wikipedia.org/wiki/Honeypot_(computing)>)) inputs can be used to detect bots by providing a field that would not generally be clicked by human users, but might be triggered automatically by bots. | ||
|
|
||
| We call it a "sweet container" so that bots do not immediately detect it as a honeypot input. | ||
|
|
||
| <Canvas of={FieldsStories.SweetContainer} /> | ||

Uh oh!
There was an error while loading. Please reload this page.
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.
Food for thought: It'd be nice if there was some more info on how to navigate these files, esp for first time users.
E.g.
If you need an overview of how GridForm works and to interact with a playground, go to <LinkTo id="..../Usage">Usage</LinkTo>
All other pages provide guidance on specific parts of GridForm.