Skip to content

Commit f3c453c

Browse files
committed
Add Field Level Help and Inline Help to Input
1 parent ab82480 commit f3c453c

File tree

5 files changed

+144
-0
lines changed

5 files changed

+144
-0
lines changed

components/component-docs.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4507,6 +4507,13 @@
45074507
"required": false,
45084508
"description": "Message to display when the input is in an error state. When this is present, also visually highlights the component as in error."
45094509
},
4510+
"fieldLevelHelpTooltip": {
4511+
"type": {
4512+
"name": "node"
4513+
},
4514+
"required": false,
4515+
"description": "A [Tooltip](https://react.lightningdesignsystem.com/components/tooltips/) component that is displayed next to the label. The props from the component will be merged and override any default props."
4516+
},
45104517
"fixedTextLeft": {
45114518
"type": {
45124519
"name": "union",
@@ -4565,6 +4572,13 @@
45654572
"required": false,
45664573
"description": "Every input must have a unique ID in order to support keyboard navigation and ARIA support."
45674574
},
4575+
"inlineHelpText": {
4576+
"type": {
4577+
"name": "string"
4578+
},
4579+
"required": false,
4580+
"description": "Displays help text under the input."
4581+
},
45684582
"inputRef": {
45694583
"type": {
45704584
"name": "func"

components/input/__docs__/storybook-stories.jsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import IconSettings from '../../icon-settings';
55
import { FORMS_INPUT } from '../../../utilities/constants';
66
import Button from '../../button';
77
import Input from '../';
8+
import Tooltip from '../../tooltip';
89
import InputIcon from '../../icon/input-icon';
910

1011
const iconClicked = action;
@@ -231,4 +232,29 @@ storiesOf(FORMS_INPUT, module)
231232
placeholder="My placeholder"
232233
/>
233234
</section>
235+
))
236+
.add('Inline Help', () => (
237+
<section>
238+
<h1 className="slds-text-title_caps slds-p-vertical--medium">
239+
Inline Help
240+
</h1>
241+
<Input label="My Label" inlineHelpText="ex: (415) 111-2222" />
242+
</section>
243+
))
244+
.add('Field Level Help', () => (
245+
<section>
246+
<h1 className="slds-text-title_caps slds-p-vertical--medium">
247+
Field Level Help
248+
</h1>
249+
<Input
250+
label="My Label"
251+
fieldLevelHelpTooltip={
252+
<Tooltip
253+
align="top left"
254+
content="Some helpful information"
255+
position="overflowBoundaryElement"
256+
/>
257+
}
258+
/>
259+
</section>
234260
));

components/input/__tests__/input.browser-test.jsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import { expect } from 'chai';
55
import assign from 'lodash.assign';
66
import TestUtils from 'react-addons-test-utils';
77

8+
import Button from '../../button';
89
import Input from '../../input';
910
import Icon from '../../icon';
11+
import Tooltip from '../../tooltip';
1012
import InputIcon from '../../icon/input-icon';
1113
import IconSettings from '../../icon-settings';
1214

@@ -501,4 +503,62 @@ describe('SLDSInput', () => {
501503
expect(fixedTextLeft.textContent).to.equal('$');
502504
});
503505
});
506+
507+
describe('Inline Help', () => {
508+
let component;
509+
let inlineHelpText;
510+
511+
beforeEach(() => {
512+
component = getInput({
513+
label: 'Input Label',
514+
inlineHelpText: 'ex: (415) 111-2222',
515+
});
516+
inlineHelpText = findRenderedDOMComponentWithClass(
517+
component,
518+
'slds-form-element__help'
519+
);
520+
});
521+
522+
afterEach(() => {
523+
removeInput();
524+
});
525+
526+
it('renders the inline help text', () => {
527+
expect(inlineHelpText).to.be.ok;
528+
});
529+
530+
it('renders the inline help text content', () => {
531+
expect(inlineHelpText.textContent).to.equal('ex: (415) 111-2222');
532+
});
533+
});
534+
535+
describe('Field Level Help', () => {
536+
let component;
537+
let fieldLevelHelpTooltip;
538+
539+
beforeEach(() => {
540+
component = getInput({
541+
label: 'Input Label',
542+
fieldLevelHelpTooltip: (
543+
<Tooltip
544+
align="top left"
545+
content="Some helpful information"
546+
position="overflowBoundaryElement"
547+
/>
548+
),
549+
});
550+
fieldLevelHelpTooltip = findRenderedDOMComponentWithClass(
551+
component,
552+
'slds-form-element__icon'
553+
);
554+
});
555+
556+
afterEach(() => {
557+
removeInput();
558+
});
559+
560+
it('renders the tooltip trigger', () => {
561+
expect(fieldLevelHelpTooltip).to.be.ok;
562+
});
563+
});
504564
});

components/input/index.jsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ import classNames from 'classnames';
2323
// shortid is a short, non-sequential, url-friendly, unique id generator
2424
import shortid from 'shortid';
2525

26+
import Button from '../button';
27+
import Tooltip from '../tooltip';
28+
2629
// ## Children
2730
import InputIcon from '../icon/input-icon';
2831
import InnerInput from './private/inner-input';
@@ -120,6 +123,10 @@ const Input = createReactClass({
120123
* Message to display when the input is in an error state. When this is present, also visually highlights the component as in error.
121124
*/
122125
errorText: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
126+
/**
127+
* A [Tooltip](https://react.lightningdesignsystem.com/components/tooltips/) component that is displayed next to the label. The props from the component will be merged and override any default props.
128+
*/
129+
fieldLevelHelpTooltip: PropTypes.node,
123130
/**
124131
* Displays text or node to the left of the input. This follows the fixed text input UX pattern.
125132
*/
@@ -144,6 +151,10 @@ const Input = createReactClass({
144151
* Every input must have a unique ID in order to support keyboard navigation and ARIA support.
145152
*/
146153
id: PropTypes.string,
154+
/**
155+
* Displays help text under the input.
156+
*/
157+
inlineHelpText: PropTypes.string,
147158
/**
148159
* This callback exposes the input reference / DOM node to parent components. `<Parent inputRef={(inputComponent) => this.input = inputComponent} />
149160
*/
@@ -331,6 +342,29 @@ const Input = createReactClass({
331342
const hasRightIcon =
332343
!!this.props.iconRight ||
333344
(this.props.iconPosition === 'right' && !!this.props.iconName);
345+
let fieldLevelHelpTooltip;
346+
if (
347+
(this.props.label ||
348+
(this.props.assistiveText && this.props.assistiveText.label)) &&
349+
this.props.fieldLevelHelpTooltip
350+
) {
351+
const defaultProps = {
352+
triggerClassName: 'slds-form-element__icon',
353+
children: (
354+
<Button
355+
assistiveText={{ label: 'Help' }}
356+
iconCategory="utility"
357+
iconName="info"
358+
variant="icon"
359+
/>
360+
),
361+
};
362+
const tooltipProps = {
363+
...defaultProps,
364+
...this.props.fieldLevelHelpTooltip.props,
365+
};
366+
fieldLevelHelpTooltip = <Tooltip {...tooltipProps} />;
367+
}
334368

335369
return (
336370
<div
@@ -349,6 +383,7 @@ const Input = createReactClass({
349383
required={this.props.required}
350384
variant={this.props.isStatic ? 'static' : 'base'}
351385
/>
386+
{fieldLevelHelpTooltip}
352387
<InnerInput
353388
aria-activedescendant={this.props['aria-activedescendant']}
354389
aria-autocomplete={this.props['aria-autocomplete']}
@@ -372,6 +407,7 @@ const Input = createReactClass({
372407
hasRightIcon ? this.getIconRender('right', 'iconRight') : null
373408
}
374409
inlineEditTrigger={this.props.inlineEditTrigger}
410+
inlineHelpText={this.props.inlineHelpText}
375411
isStatic={this.props.isStatic}
376412
minLength={this.props.minLength}
377413
maxLength={this.props.maxLength}

components/input/private/inner-input.jsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ const propTypes = {
9292
* Every input must have a unique ID in order to support keyboard navigation and ARIA support.
9393
*/
9494
id: PropTypes.string.isRequired,
95+
/**
96+
* Displays help text under the input.
97+
*/
98+
inlineHelpText: PropTypes.string,
9599
/**
96100
* This callback exposes the input reference / DOM node to parent components. `<Parent inputRef={(inputComponent) => this.input = inputComponent} />
97101
*/
@@ -300,6 +304,10 @@ const InnerInput = (props) => {
300304
</span>
301305
)}
302306
{/* eslint-enable jsx-a11y/no-static-element-interactions */}
307+
308+
{props.inlineHelpText && (
309+
<div className="slds-form-element__help">{props.inlineHelpText}</div>
310+
)}
303311
</div>
304312
);
305313
};

0 commit comments

Comments
 (0)