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.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -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.
You can’t perform that action at this time.