Skip to content
Permalink
Browse files
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 f3c5b486e7c267b92913d256fa2b49995e3bcae7
@@ -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,
@@ -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.
@@ -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}>
@@ -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">

@@ -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">
@@ -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

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.

@@ -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 />));
});
@@ -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
*/
@@ -82,6 +82,7 @@
*
* @selector .slds-form_inline
* @restrict .slds-form
* @modifier
*/
.slds-form_inline,
.slds-form--inline {
@@ -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;
}
@@ -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} />
@@ -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">
@@ -68,3 +105,5 @@ export default (
</div>
</div>
);

export default <CompoundForm />;
@@ -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',

0 comments on commit f3c5b48

Please sign in to comment.