Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix(form-legend): Add styling for compound form with a tooltip icon n…
…ext to the legend (#3151)

* fix(form-legend): Add example in compound form for a tooltip icon next to the legend

* fix(form-legend): export compoundForm for future use

* fix(form-legend): Add tests

* fix(form-legend): Attach styling to new class instead of utility

* fix(form-legend-icon): Remove example

* fix(form-legend-icon): Update docs to include form layout info and legend icon blockquote

* fix(form-legend-icon): remove form-layout from the components list

* fix(form-legend-icon): Add inline help as example in input

* fix(form-legend-icon): Remove inline class

* fix(form-legend): Skip test for now

* Update tests
  • Loading branch information
Ayesha Mazumdar authored and brandonferrua committed Mar 22, 2018
1 parent 9ed087a commit f3c5b48
Show file tree
Hide file tree
Showing 12 changed files with 314 additions and 49 deletions.
2 changes: 1 addition & 1 deletion ui/components/form-element/base/example.jsx
Expand Up @@ -14,7 +14,7 @@ const inputLabel = 'Form Element Label';
const inputId = 'input-unique-id';
const errorId = 'error-message-unique-id';

export let FormElement = props => {
export const FormElement = props => {
const {
className,
formControlClassName,
Expand Down
64 changes: 53 additions & 11 deletions ui/components/form-element/docs.mdx
Expand Up @@ -4,15 +4,19 @@ import Example from '../../../shared/components/Example';
import Blockquote from '../../../shared/components/Blockquote';
import ButtonIcon from '../button-icons/';
import {FormElement} from './base/example';
import {Input} from '../input/base/example';
import {Checkbox} from '../checkbox/base/example';
import {Textarea} from '../textarea/base/example';
import {Avatar} from '../avatar/base/example';
import { Input } from '../input/base/example';
import { Checkbox } from '../checkbox/base/example';
import { Textarea } from '../textarea/base/example';
import { Avatar } from '../avatar/base/example';
import { Form } from '../form-layout/base/example';
import { CompoundForm } from '../form-layout/compound/example';

<div className="lead doc">
An HTML form element contains a HTML label and element
</div>

There are many types of form elements, including [inputs](/input), [text areas](/textarea), [checkboxes](/checkbox), and [radio buttons](/radio-group). Visit the individual component pages for in-depth details of specific states and visuals.

## Structuring a form element

To create a form element, a `<div>` element with the class `slds-form-element` is required.
Expand All @@ -32,7 +36,7 @@ A form element is made up of three primary elements, the label (`slds-form-eleme
A form label should use the `<label>` element with the class `slds-form-element__label`.

<Blockquote type="a11y" header="Accessibility requirement">
It is required to have the <code className="doc">for</code> attr applied the the label that points to the ID of the form element, <code className="doc"><input id="unique-id"></code>.
Labels must have the <code className="doc">for</code> attribute applied, and its value must match the ID of the associated form element, like <code className="doc"><input id="unique-id-of-input"></code>. This association ensures that assistive technology informs users about what information to enter where.
</Blockquote>

<CodeBlock toggleCode={false}>
Expand Down Expand Up @@ -110,11 +114,13 @@ By default, the overall form element takes up 54px of vertical space. If you req

### Feedback

A form element provides two types of feedback, a required form element and a form element with an error.
A form element can have various methods of feedback, such as a required denotation or an inline error message.

#### Required

When a form element is required, an `<abbr>` should be injected before the `<input>` with the class `slds-required`.
When a form element is required, an `<abbr>` should be injected before the `<input>` and within the `<label>` and have the class `slds-required`.

The `<input>` element should also have the HTML attribute required or required="". Similarily, if it is disabled, it should have the disabled or disabled="" attribute. Do not use true/false values inside the required or disabled because the mere presence of these attributes signifies the field is required or disabled.

<Example title="Form Element - Required">

Expand All @@ -128,10 +134,10 @@ When a form element is required, an `<abbr>` should be injected before the `<inp

#### Error

If an error has occured while submitting a form, the form element with an error should provide feedback.
If an error has occured while submitting a form, the form element with an error should provide feedback. The `slds-has-error` class is placed on the `<div class="slds-form-element">`. Then, the error message for the user is placed in a `<span>` with the `slds-form-element__help` class.

<Blockquote type="a11y" header="Accessibility requirement">
When a form element displayed feedback notifying the user of an error, the error string should be linked to the element by adding <code className="doc">aria-describedby</code> attribute to the <code className="doc"><input></code> and point to the error message ID.
When a form element displays feedback notifying the user of an error, the error string should be linked to the element by adding the <code className="doc">aria-describedby</code> attribute to the <code className="doc"><input></code>. The `aria-describedby` attribute must reference the id of the error message. This configuration allows screen readers to read the associated error message when the invalid field is focused.
</Blockquote>

<Example title="Form Element - Error">
Expand All @@ -140,17 +146,53 @@ If an error has occured while submitting a form, the form element with an error
<FormElement
className="slds-has-error"
label="Form Label"
inputId="form-element-04"
inputId="form-element-05"
errorId="form-error-01"
required
message="This field is required"
>
<Input id="form-element-04" required aria-describedby="form-error-01" />
<Input id="form-element-05" required aria-describedby="form-error-01" />
</FormElement>
</CodeView>

</Example>

## Layout

Layout helper classes are available through the following class names: `slds-form_stacked` and `slds-form_horizontal`. For optimal spacing and layout, ensure the `slds-form-element` class is present on each element within the form.

### Stacked

To vertically stack `<label>` and `<input>` pairs, place `slds-form--stacked` on the wrapper of the form for optimal spacing.

<Example title="Form Layout - Stacked">
<CodeView>
<Form/>
</CodeView>
</Example>

### Horizontal

To horizontally align a `<label>` and `<input>`, use the `slds-form--horizontal` class on the wrapper around the form. A `slds-form-element__label` takes up 33% of the width, and the `slds-form-element__control` uses the remaining 66%.

<Example title="Form Layout - Horizontal">
<CodeView>
<Form className="slds-form_horizontal"/>
</CodeView>
</Example>

### Compound

<Blockquote type="note" header="Implementation Note">
To use field level help with a `<legend>` (as opposed to a `<label>`), the `<legend>` and the `<div>` with the help icon must be siblings. Additionally, you'll need to add the class `slds-form-element__legend_has-tooltip` to the `<legend>`. Only add this class when your `<legend>` has adjacent field level help, otherwise you'll experience unexpected layouts.
</Blockquote>

<Example title="Form Layout - Compound">
<CodeView>
<CompoundForm/>
</CodeView>
</Example>

## Usage Examples

### Record Detail
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions ui/components/form-layout/__tests__/snapshot.spec.js
@@ -0,0 +1,23 @@
// Copyright (c) 2015-present, salesforce.com, inc. All rights reserved
// Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license
/* eslint-env jest */

import React from 'react';
import createHelpers from '../../../../jest.helpers';
import { Form } from '../base/example';
import { CompoundForm } from '../compound/example';

const { matchesMarkupAndStyle } = createHelpers(__dirname);

describe('Form Layout', () => {
xit('renders a base form layout', () => matchesMarkupAndStyle(<Form />));

it('renders a base form layout horizontally', () =>
matchesMarkupAndStyle(<Form className="slds-form_horizontal" />));

it('renders a compound form layout', () =>
matchesMarkupAndStyle(<CompoundForm />));

it('renders a compound form layout with a tooltip', () =>
matchesMarkupAndStyle(<CompoundForm tooltip />));
});
34 changes: 0 additions & 34 deletions ui/components/form-layout/_doc.scss
@@ -1,36 +1,2 @@
// Copyright (c) 2015-present, salesforce.com, inc. All rights reserved
// Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license

/**
* To vertically stack `<label>` and `<input>` pairs, place `.slds-form--stacked` on the wrapper of the form for optimal spacing.
*
* To horizontally align a `<label>` and `<input>`, use the `.slds-form--horizontal` class on the wrapper around the form. A `.slds-form-element__label` takes up 33% of the width, and the `.slds-form-element__control` uses the remaining 66%.
*
* For optimum spacing and layout, wrap each element in `.slds-form-element`. Layout helper classes are available through the following class names, `.slds-form--stacked`, `.slds-form--horizontal` and `.slds-form--inline`.
*
* The read-only state is for form elements that can’t be modified. It is used for small, non-editable form fields that sit next to inputs and allows the size and height to align. It is not meant for large paragraphs of text.
*
* Because the read-only field state has no `<input>`, don’t use a `<label>` to provide better accessibility for screen readers and keyboard navigators. Instead, use a `<span>` with the `.slds-form-element__label` class. Instead of an `<input>`, use the `.slds-form-element__static` class inside the `.slds-form-element__control` wrapper.
*
* Error states alert the user when content in the form is invalid. The `.slds-has-error` class is placed on the `<div class="slds-form-element">`. Place the error message for the user in a `<span>` with the `.slds-form-element__help` class.
*
* The native form elements, `<input>`, `<textarea>`, `<select>`, `<input type='checkbox'>`, and `<input type='radio'>`, receive validation styling for `disabled`, `checked`, and `checked disabled`, if applicable.
*
* #### Accessibility
*
* Every field requires an associated, non-empty `<label>` element. The label should have a `for` attribute that references the `id` of the field. For example, `<label for="emailAddress">Enter email address:</label>` and `<input id="emailAddress">`. This association ensures that assistive technology informs users what information to enter where.
*
* If the field is required, the `<input>` element should have the HTML attribute `required` or `required=""`. Similarily, if it is disabled, it should have the `disabled` or `disabled=""` attribute. Do not use true/false values inside the `required` or `disabled` because the mere presence of these attributes signifies the field is required or disabled.
*
* If the field is invalid and displays an error message, the `<input>` element should have an `aria-describedby` attribute that references the `id` of the error message. This configuration allows screen readers to read the associated error message when the invalid field is focused.
*
* @summary An HTML form contains interactive controls to submit information to a web server.
*
* @base
* @name form-layout
* @selector .slds-form
* @support dev-ready
* @category structure
* @type layout
* @layout responsive
*/
11 changes: 11 additions & 0 deletions ui/components/form-layout/base/_index.scss
Expand Up @@ -82,6 +82,7 @@
*
* @selector .slds-form_inline
* @restrict .slds-form
* @modifier
*/
.slds-form_inline,
.slds-form--inline {
Expand Down Expand Up @@ -115,3 +116,13 @@
}
}
}

/**
* @summary Aligns the legend properly when there is an info tooltip
*
* @selector .slds-form-element__legend_has-tooltip
* @restrict .slds-form-element__legend
*/
.slds-form-element__legend_has-tooltip {
float: left;
}
2 changes: 1 addition & 1 deletion ui/components/form-layout/base/example.jsx
Expand Up @@ -13,7 +13,7 @@ const inputId01 = 'input-id-01';
const inputId02 = 'input-id-02';
const inputId03 = 'input-id-03';

let Form = props => (
export const Form = props => (
<div className={classNames('slds-form', props.className)}>
<FormElement label="Text Input" inputId={inputId01}>
<Input id={inputId01} />
Expand Down
43 changes: 41 additions & 2 deletions ui/components/form-layout/compound/example.jsx
Expand Up @@ -2,14 +2,51 @@
// Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license

import React from 'react';
import classNames from 'classnames';
import SvgIcon from '../../../shared/svg-icon';
import { Tooltip } from '../../tooltips/base/example';

export default (
export const CompoundForm = props => (
<div className="demo-only" style={{ width: '440px' }}>
<div className="slds-form slds-form_compound">
<fieldset className="slds-form-element">
<legend className="slds-form-element__label slds-text-title_caps">
<legend
className={classNames(
'slds-form-element__label',
'slds-form-element__legend',
'slds-text-title_caps',
{ 'slds-form-element__legend_has-tooltip': props.tooltip }
)}
>
Location
</legend>
{props.tooltip && (
<div className="slds-form-element__icon">
<button
aria-describedby="help"
className="slds-button slds-button_icon"
>
<SvgIcon
className="slds-icon slds-icon_x-small slds-icon-text-default"
sprite="utility"
symbol="info"
/>
<span className="slds-assistive-text">Help</span>
</button>
<Tooltip
className="slds-nubbin_bottom-left"
id="help"
style={{
position: 'absolute',
top: '-45px',
left: '-15px',
width: '170px'
}}
>
Some helpful information
</Tooltip>
</div>
)}
<div className="slds-form-element__group">
<div className="slds-form-element__row">
<div className="slds-form-element slds-size_1-of-2">
Expand Down Expand Up @@ -68,3 +105,5 @@ export default (
</div>
</div>
);

export default <CompoundForm />;
15 changes: 15 additions & 0 deletions ui/components/input/base/example.jsx
Expand Up @@ -315,6 +315,21 @@ export let examples = [
</FormElement>
)
},
{
id: 'inline-help',
label: 'Inline Help',
element: (
<FormElement>
<FormElementLabel labelID="inline-text-label">
Input Label
</FormElementLabel>
<FormElementControl>
<Input aria-labelledby="inline-text-label" />
<div className="slds-form-element__help">ex: (415)111-2222</div>
</FormElementControl>
</FormElement>
)
},
{
id: 'field-level-help',
label: 'Field level help',
Expand Down

0 comments on commit f3c5b48

Please sign in to comment.