Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EuiCard a11y #2521

Merged
merged 15 commits into from
Nov 14, 2019
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
## [`master`](https://github.com/elastic/eui/tree/master)

- Made `EuiCard` more accessible ([#2521](https://github.com/elastic/eui/pull/2521))
- Added ability to pass `children` to `EuiCard` ([#2521](https://github.com/elastic/eui/pull/2521))

**Bug fixes**

- Added support for `timeFormat` formatting in `EuiSuperDatePicker` and fixed some formatting inconsistencies ([#2518](https://github.com/elastic/eui/pull/2518))
- Added support for `locale` in `EuiSuperDatePicker` and `EuiDatePicker` both as a prop and from `EuiContext` ([#2518](https://github.com/elastic/eui/pull/2518))

**Breaking changes**

- Removed `EuiCardGraphic` ([#2521](https://github.com/elastic/eui/pull/2521))

## [`15.0.0`](https://github.com/elastic/eui/tree/v15.0.0)

- Converted `EuiShowFor` and `EuiHideFor` to TS ([#2503](https://github.com/elastic/eui/pull/2503))
Expand Down
1 change: 1 addition & 0 deletions src-docs/src/components/guide_page/guide_page_chrome.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ export class GuidePageChrome extends Component {
placeholder="Search"
value={this.state.search}
onChange={this.onSearchChange}
aria-label="Search for a docs section"
/>
</div>
</div>
Expand Down
91 changes: 91 additions & 0 deletions src-docs/src/views/card/card_children.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React from 'react';

import {
EuiCard,
EuiFlexGroup,
EuiFlexItem,
EuiCodeBlock,
EuiRadioGroup,
EuiText,
EuiButton,
EuiCode,
} from '../../../../src/components';

const radios = [
{
id: 'radios0',
label: 'Option one',
},
{
id: 'radios1',
label: 'Option two',
},
{
id: 'radios2',
label: 'Option three',
disabled: true,
},
];

export default () => {
return (
<EuiFlexGroup gutterSize="l">
<EuiFlexItem>
<EuiCard
textAlign="left"
title="Lists"
description={
<span>
Wrap a lists with <EuiCode>EuiText size=&quot;s&quot;</EuiCode> to
match the description text.
</span>
}>
<EuiText size="s">
<ul>
<li>Bullet 1</li>
<li>Bullet 2</li>
<li>Bullet 3</li>
</ul>
</EuiText>
</EuiCard>
</EuiFlexItem>
<EuiFlexItem>
<EuiCard
textAlign="left"
title="Form controls"
description="Add any controls you need."
footer={
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButton size="s" fill>
Send
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
}>
<EuiRadioGroup
options={radios}
idSelected={radios[0].id}
onChange={() => {}}
compressed
/>
</EuiCard>
</EuiFlexItem>
<EuiFlexItem>
<EuiCard
textAlign="left"
title="Just about anything"
description={
<span>
Just be sure not to add any <EuiCode>onClick</EuiCode> handler to
the card if the children are also interactable.
</span>
}>
<EuiCodeBlock language="html" paddingSize="s">
{'<yoda>Hello, young Skywalker</yoda>'}
</EuiCodeBlock>
</EuiCard>
</EuiFlexItem>
</EuiFlexGroup>
);
};
136 changes: 117 additions & 19 deletions src-docs/src/views/card/card_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ import CardSelectable from './card_selectable';
const cardSelectableSource = require('!!raw-loader!./card_selectable');
const cardSelectableHtml = renderToHtml(CardSelectable);

import CardChildren from './card_children';
const cardChildrenSource = require('!!raw-loader!./card_children');
const cardChildrenHtml = renderToHtml(CardChildren);

export const CardExample = {
title: 'Card',
sections: [
Expand All @@ -58,8 +62,7 @@ export const CardExample = {
<p>
By default a card&apos;s title element is a <EuiCode>span</EuiCode>.
This can be changed via the <EuiCode>titleElement</EuiCode> prop.
However, if an <EuiCode>onClick</EuiCode> function is also passed,
the title element will be forced back to a span.
However, it will always remain the same visual size.
</p>
<p>
By default a card&apos;s content is center aligned. To change the
Expand All @@ -70,6 +73,12 @@ export const CardExample = {
),
props: { EuiCard },
demo: <Card />,
snippet: `<EuiCard
icon={<EuiIcon size="xxl" type={} />}
title=""
description=""
onClick={}
/>`,
},
{
title: 'Layout',
Expand All @@ -89,7 +98,8 @@ export const CardExample = {
Most of the time, cards should read from top to bottom (vertical).
However, in some cases, you may want the icon to be to the left of
the content. In this case, add the prop{' '}
<EuiCode>layout=&quot;horizontal&quot;</EuiCode>.
<EuiCode>layout=&quot;horizontal&quot;</EuiCode>. Works best when
the icon is size <EuiCode>xl</EuiCode>.
</p>
<EuiCallOut
color="danger"
Expand All @@ -105,6 +115,13 @@ export const CardExample = {
),
props: { EuiCard },
demo: <CardLayout />,
snippet: `<EuiCard
layout="horizontal"
icon={<EuiIcon size="xl" type={} />}
title=""
description=""
onClick={}
/>`,
},
{
title: 'Images',
Expand Down Expand Up @@ -137,6 +154,13 @@ export const CardExample = {
),
props: { EuiCard },
demo: <CardImage />,
snippet: `<EuiCard
textAlign="left"
image="https://source.unsplash.com/400x200/?Nature"
title=""
description=""
onClick={}
/>`,
},
{
title: 'Footer',
Expand All @@ -151,15 +175,40 @@ export const CardExample = {
},
],
text: (
<p>
Footers can contain any number of elements and will always align to
the bottom of the card. However, if you supply a footer containing a{' '}
<EuiCode>EuiButton</EuiCode> you <strong>must not</strong> also give
it an <EuiCode>onClick</EuiCode>.
</p>
<>
<p>
Footers can contain any number of elements and will always align to
the bottom of the card. However, if you supply a footer containing a{' '}
<EuiCode>EuiButton</EuiCode> you <strong>must not</strong> also give
it an <EuiCode>onClick</EuiCode>.
</p>
<EuiCallOut title="Accessibility" color="warning">
<p>
When using footers to display generic &quot;Go&quot; buttons. You
must provide an <EuiCode>aria-label</EuiCode> to the button itself
that refers back to the title of the card.
</p>
</EuiCallOut>
</>
),
components: { EuiCard },
demo: <CardFooter />,
snippet: `<EuiCard
icon={<EuiIcon size="xxl" type="" />}
title=""
description=""
footer={
<div>
<EuiButton aria-label=""></EuiButton>
<EuiSpacer size="xs" />
<EuiText size="s">
<p>
Or try <EuiLink href="">this</EuiLink>
</p>
</EuiText>
</div>
}
/>`,
},
{
title: 'Beta badge',
Expand All @@ -185,6 +234,14 @@ export const CardExample = {
),
props: { EuiCard },
demo: <CardBeta />,
snippet: `<EuiCard
icon={<EuiIcon size="xxl" type={} />}
title=""
description=""
onClick={}
betaBadgeLabel=""
betaBadgeTooltipContent=""
/>`,
},
{
title: 'Selectable',
Expand All @@ -204,31 +261,72 @@ export const CardExample = {
When you have a list of cards that can be selected but{' '}
<strong>do not navigate anywhere</strong>, you can add the{' '}
<EuiCode>selectable</EuiCode> prop. The prop is an object that
requires an <EuiCode>onClick</EuiCode>. It will apply the button as
seen below, and passing{' '}
extends <EuiCode>EuiButtonEmpty</EuiCode>. It will apply the button
as seen below, and passing{' '}
<EuiCode>selectable.isSelected = true</EuiCode> will alter the
styles of the card and button to look selected.
</p>
<p>
The select button is essentially an EuiButtonEmpty and so the{' '}
<EuiCode>selectable</EuiCode> object can also accept any props that
EuiButtonEmpty can.
</p>
<EuiCallOut
color="warning"
title="When providing an extra link to more details or such, be sure to
stop event propagation from also selecting the card."
/>
</Fragment>
),
props: { EuiCardSelect },
demo: <CardSelectable />,
snippet: `<EuiCard
icon={<EuiIcon />}
title="Title"
description="Example of a short card description."
footer={cardFooterContent}
title=""
description=""
selectable={{
onClick: this.cardClicked,
isSelected: this.state.cardIsSelected,
isDisabled: this.state.cardIsDisabled,
}}
footer={<EuiButtonEmpty
onClick={e => {
e.stopPropagation();
}}
aria-label=""
/>}
/>`,
},
{
title: 'Custom children',
source: [
{
type: GuideSectionTypes.JS,
code: cardChildrenSource,
},
{
type: GuideSectionTypes.HTML,
code: cardChildrenHtml,
},
],
text: (
<Fragment>
<p>
In the event that you need more than just paragraph text for the
description, you can pass anything you need as the{' '}
<EuiCode>children</EuiCode> of the component.
</p>
</Fragment>
),
props: { EuiCard },
demo: <CardChildren />,
snippet: `<EuiCard
textAlign="left"
title=""
description="">
<EuiText size="s">
<ul>
<li>Bullet 1</li>
<li>Bullet 2</li>
<li>Bullet 3</li>
</ul>
</EuiText>
</EuiCard>`,
},
],
};
Loading