Skip to content

Commit

Permalink
feat(component): add label id's to form fields (#304)
Browse files Browse the repository at this point in the history
  • Loading branch information
chanceaclark authored Dec 30, 2019
1 parent 1bf028d commit 0620612
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 6 deletions.
8 changes: 5 additions & 3 deletions packages/big-design/src/components/Input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ interface Props {
iconLeft?: React.ReactChild;
iconRight?: React.ReactChild;
label?: React.ReactChild;
labelId?: string;
onChipDelete?(chip: string): () => void;
}

Expand All @@ -40,7 +41,7 @@ class StyleableInput extends React.PureComponent<InputProps & PrivateProps, Inpu
private readonly uniqueId = uniqueId('input_');

render() {
const { chips, description, disabled, error, label, forwardedRef, onChipDelete, ...props } = this.props;
const { chips, description, disabled, error, label, labelId, forwardedRef, onChipDelete, ...props } = this.props;
const id = this.getId();

return (
Expand Down Expand Up @@ -106,19 +107,20 @@ class StyleableInput extends React.PureComponent<InputProps & PrivateProps, Inpu
}

private renderLabel() {
const { label, required } = this.props;
const { label, labelId, required } = this.props;
const id = this.getId();

if (typeof label === 'string') {
return (
<Input.Label htmlFor={id} renderOptional={!required}>
<Input.Label id={labelId} htmlFor={id} renderOptional={!required}>
{label}
</Input.Label>
);
}

if (React.isValidElement(label) && label.type === Input.Label) {
return React.cloneElement(label as React.ReactElement<React.LabelHTMLAttributes<HTMLLabelElement>>, {
id: labelId,
htmlFor: id,
});
}
Expand Down
7 changes: 7 additions & 0 deletions packages/big-design/src/components/Input/spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ test('matches label htmlFor with id provided', () => {
expect(label.htmlFor).toBe('test');
});

test('respects provided labelId', () => {
const { container } = render(<Input labelId="test" label="Test Label" />);
const label = container.querySelector('#test') as HTMLLabelElement;

expect(label.id).toBe('test');
});

test('renders a description', () => {
const descriptionText = 'This is a description';
const { queryByText } = render(<Input description={descriptionText} />);
Expand Down
8 changes: 5 additions & 3 deletions packages/big-design/src/components/Textarea/Textarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface Props {
description?: React.ReactChild;
error?: React.ReactChild;
label?: React.ReactChild;
labelId?: string;
rows?: 1 | 2 | 3 | 4 | 5 | 6 | 7;
resize?: boolean;
}
Expand All @@ -34,7 +35,7 @@ class StyleableTextarea extends React.PureComponent<TextareaProps & PrivateProps
private readonly MAX_ROWS = 7;

render() {
const { description, label, resize, rows, forwardedRef, ...props } = this.props;
const { description, label, labelId, resize, rows, forwardedRef, ...props } = this.props;
const id = this.getId();

return (
Expand Down Expand Up @@ -69,19 +70,20 @@ class StyleableTextarea extends React.PureComponent<TextareaProps & PrivateProps
}

private renderLabel() {
const { label, required } = this.props;
const { label, labelId, required } = this.props;
const id = this.getId();

if (typeof label === 'string') {
return (
<Textarea.Label htmlFor={id} renderOptional={!required}>
<Textarea.Label id={labelId} htmlFor={id} renderOptional={!required}>
{label}
</Textarea.Label>
);
}

if (React.isValidElement(label) && label.type === Textarea.Label) {
return React.cloneElement(label as React.ReactElement<React.LabelHTMLAttributes<HTMLLabelElement>>, {
id: labelId,
htmlFor: id,
});
}
Expand Down
7 changes: 7 additions & 0 deletions packages/big-design/src/components/Textarea/spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ test('matches label htmlFor with id provided', () => {
expect(label.htmlFor).toBe('test');
});

test('respects provided labelId', () => {
const { container } = render(<Textarea labelId="test" label="Test Label" />);
const label = container.querySelector('#test') as HTMLLabelElement;

expect(label.id).toBe('test');
});

test('renders a description', () => {
const descriptionText = 'This is a description';
const { queryByText } = render(<Textarea description={descriptionText} />);
Expand Down
9 changes: 9 additions & 0 deletions packages/docs/PropTables/InputPropTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ const inputProps: Prop[] = [
</>
),
},
{
name: 'labelId',
types: 'string',
description: (
<>
Appends an <Code>id</Code> to the generated label element.
</>
),
},
];

export const InputPropTable: React.FC<PropTableWrapper> = props => (
Expand Down
9 changes: 9 additions & 0 deletions packages/docs/PropTables/TextareaPropTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ const textareaProps: Prop[] = [
</>
),
},
{
name: 'labelId',
types: 'string',
description: (
<>
Appends an <Code>id</Code> to the generated label element.
</>
),
},
{
name: 'rows',
types: ['1', '2', '3', '4', '5', '6', '7'],
Expand Down

0 comments on commit 0620612

Please sign in to comment.