Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React from 'react';
import { Button, Tooltip, TooltipPosition } from '@patternfly/react-core';
import {
Table,
Tbody,
Thead,
Tr,
Th,
Td
} from '@patternfly/react-table';
import RhUiArrowCircleUpIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-arrow-circle-up-icon';
import RhUiNotificationFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-notification-fill-icon';
import RhUiSettingsIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-settings-icon';
import RhUiCopyIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-copy-icon';
import RhUiDownloadIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-download-icon';
import RhUiEllipsisVerticalIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-icon';
import RhUiEditIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-edit-icon';
import RhUiSearchIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-search-icon';
import RhUiZoomOutIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-zoom-out-icon';
import RhUiZoomInIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-zoom-in-icon';
import RhUiSyncIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-sync-icon';
import RhUiTrashIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-trash-icon';
import RhUiExportIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-export-icon';
import RhUiTaskIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-task-icon';

const REACT_LABEL = 'React name';

const ROWS = [
{ Icon: RhUiArrowCircleUpIcon, name: 'rh-ui-arrow-circle-up', reactName: 'RhUiArrowCircleUpIcon', tooltip: 'Upgrade', note: '' },
{ Icon: RhUiNotificationFillIcon, name: 'rh-ui-notification-fill', reactName: 'RhUiNotificationFillIcon', tooltip: 'Notifications', note: '' },
{ Icon: RhUiSettingsIcon, name: 'rh-ui-settings', reactName: 'RhUiSettingsIcon', tooltip: 'Settings', note: '' },
{ Icon: RhUiCopyIcon, name: 'rh-ui-copy', reactName: 'RhUiCopyIcon', tooltip: 'Copy', note: '' },
{ Icon: RhUiDownloadIcon, name: 'rh-ui-download', reactName: 'RhUiDownloadIcon', tooltip: 'Download', note: '' },
{ Icon: RhUiEllipsisVerticalIcon, name: 'rh-ui-ellipsis-vertical', reactName: 'RhUiEllipsisVerticalIcon', tooltip: 'More options', note: '' },
{ Icon: RhUiEditIcon, name: 'rh-ui-edit', reactName: 'RhUiEditIcon', tooltip: 'Edit', note: '' },
{ Icon: RhUiSearchIcon, name: 'rh-ui-search', reactName: 'RhUiSearchIcon', tooltip: 'Search', note: '' },
{ Icon: RhUiZoomOutIcon, name: 'rh-ui-zoom-out', reactName: 'RhUiZoomOutIcon', tooltip: 'Zoom out', note: '' },
{ Icon: RhUiZoomInIcon, name: 'rh-ui-zoom-in', reactName: 'RhUiZoomInIcon', tooltip: 'Zoom in', note: '' },
{ Icon: RhUiSyncIcon, name: 'rh-ui-sync', reactName: 'RhUiSyncIcon', tooltip: 'Sync', note: 'Choose the best fit for your scenario.' },
{ Icon: RhUiTrashIcon, name: 'rh-ui-trash', reactName: 'RhUiTrashIcon', tooltip: 'Delete', note: '' },
{ Icon: RhUiExportIcon, name: 'rh-ui-export', reactName: 'RhUiExportIcon', tooltip: 'Export', note: '' },
{ Icon: RhUiTaskIcon, name: 'rh-ui-task', reactName: 'RhUiTaskIcon', tooltip: 'Tasks', note: '' }
];

export const TooltipIconReferenceTable = () => {
const [copiedReactName, setCopiedReactName] = React.useState(null);

return (
<Table aria-label="Icon tooltip reference" variant="compact">
<Thead>
<Tr>
<Th>Icon</Th>
<Th>Name</Th>
<Th>{REACT_LABEL}</Th>
<Th>Tooltip content</Th>
<Th>Note</Th>
</Tr>
</Thead>
<Tbody>
{ROWS.map((row) => {
const Icon = row.Icon;
return (
<Tr key={row.reactName}>
<Td dataLabel="Icon">
<Tooltip content={row.tooltip} position={TooltipPosition.right}>
<Button variant="plain" aria-label={`Suggested tooltip label: ${row.tooltip}`}>
<Icon />
</Button>
</Tooltip>
</Td>
<Td dataLabel="Name" modifier="fitContent">
{row.name}
</Td>
<Td dataLabel={REACT_LABEL} modifier="fitContent">
<Tooltip
trigger="mouseenter focus click"
content={<div>{copiedReactName === row.reactName ? 'Copied' : 'Copy React name'}</div>}
position={TooltipPosition.left}
exitDelay={copiedReactName === row.reactName ? 1000 : 100}
onTooltipHidden={() => {
if (copiedReactName === row.reactName) {
setCopiedReactName(null);
}
}}
>
<span
style={{ cursor: 'pointer' }}
role="button"
tabIndex={0}
aria-label={`Copy ${row.reactName} to clipboard`}
onClick={() => {
navigator.clipboard.writeText(row.reactName);
setCopiedReactName(row.reactName);
}}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
navigator.clipboard.writeText(row.reactName);
setCopiedReactName(row.reactName);
}
}}
>
{row.reactName}
</span>
</Tooltip>
</Td>
<Td dataLabel="Tooltip content">{row.tooltip}</Td>
<Td dataLabel="Note">{row.note || null}</Td>
</Tr>
);
})}
</Tbody>
</Table>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,22 @@ section: content-design
subsection: writing-guides
---

import ArrowCircleUpIcon from '@patternfly/react-icons/dist/esm/icons/arrow-circle-up-icon';
import BellIcon from '@patternfly/react-icons/dist/esm/icons/bell-icon';
import CogIcon from '@patternfly/react-icons/dist/esm/icons/cog-icon';
import CopyIcon from '@patternfly/react-icons/dist/esm/icons/copy-icon';
import DownloadIcon from '@patternfly/react-icons/dist/esm/icons/download-icon';
import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon';
import PencilAltIcon from '@patternfly/react-icons/dist/esm/icons/pencil-alt-icon';
import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
import SearchMinusIcon from '@patternfly/react-icons/dist/esm/icons/search-minus-icon';
import SearchPlusIcon from '@patternfly/react-icons/dist/esm/icons/search-plus-icon';
import SyncAltIcon from '@patternfly/react-icons/dist/esm/icons/sync-alt-icon';
import TrashIcon from '@patternfly/react-icons/dist/esm/icons/trash-icon';
import ExportIcon from '@patternfly/react-icons/dist/esm/icons/export-icon';
import TaskIcon from '@patternfly/react-icons/dist/esm/icons/task-icon';
import QuestionCircleIcon from '@patternfly/react-icons/dist/esm/icons/question-circle-icon';
import { Button, Icon, Tooltip, Split, SplitItem } from '@patternfly/react-core'
import RhUiSettingsIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-settings-icon';
import RhUiCopyIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-copy-icon';
import RhUiSearchIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-search-icon';
import RhUiQuestionMarkCircleIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-question-mark-circle-icon';
import { Button, Tooltip, Split, SplitItem } from '@patternfly/react-core'
import { TooltipIconReferenceTable } from './TooltipIconReferenceTable.jsx';

A **tooltip** is a message box that is shown when a UI element, like a button or an icon, is in a hover state. They contain short descriptions that offer additional information to help users better understand elements within a UI.

<Split>
<SplitItem>
<Tooltip content={"This is a tooltip. It contains useful information that solves all your problems."} aria="describedby" >
<Button>I'm a button with a tooltip!</Button>
</Tooltip>
</SplitItem>
</Split>

When writing tooltips, follow these general recommendations:

Expand All @@ -36,7 +30,7 @@ When writing tooltips, follow these general recommendations:
| Don't repeat information that is already available in the UI. | Do write content that is succinct, clear, and effective. |
| Don't use tooltips for critical information. | Do use tooltips for additional, non-essential information. |
| Don't end sentence fragments in a period. | Do end full sentences in a period. |
| Don’t place tooltips on question-circle icons (<QuestionCircleIcon />). Instead, use a [popover](/components/popover). | Do follow [our tooltip development accessibility guidelines](/components/tooltip/accessibility) to ensure that tooltip content is available to all users.|
| Don’t place tooltips on question-mark icons (<RhUiQuestionMarkCircleIcon />). Instead, use a [popover](/components/popover). | Do follow [our tooltip development accessibility guidelines](/components/tooltip/accessibility) to ensure that tooltip content is available to all users.|

</div>

Expand All @@ -51,33 +45,18 @@ For example:

<Split>
<SplitItem>
<Tooltip content={"Settings"} aria="labelledby"> <Button variant="plain" aria-label="More information about settings"> <CogIcon /></Button> </Tooltip>
<Tooltip content={"Settings"} aria="labelledby"> <Button variant="plain" aria-label="More information about settings"> <RhUiSettingsIcon /></Button> </Tooltip>
</SplitItem>
<SplitItem>
<Tooltip content={"Copy"} aria="labelledby"> <Button variant="plain" aria-label="Copy"> <CopyIcon /></Button> </Tooltip>
<Tooltip content={"Copy"} aria="labelledby"> <Button variant="plain" aria-label="Copy"> <RhUiCopyIcon /></Button> </Tooltip>
</SplitItem>
<SplitItem>
<Tooltip content={"Search"} aria="labelledby"> <Button variant="plain" aria-label="Search"> <SearchIcon /></Button> </Tooltip>
<Tooltip content={"Search"} aria="labelledby"> <Button variant="plain" aria-label="Search"> <RhUiSearchIcon /></Button> </Tooltip>
</SplitItem>
</Split>

In PatternFly, there are commonly used icons that hold universal meanings. These should always use the same tooltip description, as shown in the following table:

|**Icon** | **Name** | **Tooltip content** | **Note** |
|------------|-----------|-----------|---- |
| <ArrowCircleUpIcon /> | fa-arrow-circle-up | Upgrade |
| <BellIcon /> | fa-bell | Notifications |
| <CogIcon /> | fa-cog | Settings |
| <CopyIcon /> | fa-copy | Copy |
| <DownloadIcon /> | fa-download | Download |
| <EllipsisVIcon /> | fa-ellipsis-v | More options |
| <PencilAltIcon /> | fa-pencil-alt | Edit |
| <SearchIcon /> | fa-search | Search |
| <SearchMinusIcon /> | fa-search-minus | Search minus |
| <SearchPlusIcon /> | fa-search-plus | Search plus |
| <SyncAltIcon /> | fa-sync-alt | Sync, Refresh, or Running | Choose the best fit for your scenario.|
| <TrashIcon /> | fa-trash | Delete |
| <ExportIcon /> | pficon-export | Export |
| <TaskIcon /> | pficon-task | Tasks |
<TooltipIconReferenceTable />

You can learn more about the usage of these icons in our [design foundations.](/foundations-and-styles/iconography)
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,21 @@ import {
} from '@patternfly/react-table';
import { iconsData } from './icons';
import { saveAs } from 'file-saver';
import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
import * as iconUnicodes from '@patternfly/patternfly/assets/icons/iconUnicodes.json';
import RhUiSearchIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-search-icon';

const REACT_COLUMN_LABEL = 'React name';

export const IconsTable = () => {
const columns = ['Icon', 'Name', 'Style', 'React', 'Usage', 'Unicode'];
const columns = ['Icon', 'Name', 'React', 'Usage'];
const [searchValue, setSearchValue] = React.useState('');
const [isCopied, setCopied] = React.useState(false);
const [sortByIndex, setSortByIndex] = React.useState(1);
const [sortDirection, setSortDirection] = React.useState('asc');
/** Which row’s React name was last copied (for tooltip feedback). */
const [copiedReactName, setCopiedReactName] = React.useState(null);

React.useEffect(() => {
setCopiedReactName(null);
}, [searchValue]);

const getSortParams = columnIndex => ({
sortBy: {
Expand Down Expand Up @@ -62,11 +68,6 @@ export const IconsTable = () => {
saveAs(blob, filename);
};

const clipboardCopyFunc = (event, text) => {
navigator.clipboard.writeText(text.toString());
setCopied(true);
};

const filteredRows = React.useMemo(() => {
return iconsData.filter(icon => {
return icon.Name.toLowerCase().includes(searchValue.toLowerCase()) ||
Expand Down Expand Up @@ -115,24 +116,21 @@ export const IconsTable = () => {
</Toolbar>
<Divider />
<Table
aria-label="Filterable PatternFly icons"
aria-label="Filterable Red Hat UI icons"
variant={'compact'}
id="ws-icons-table"
>
<Thead>
<Tr>
<Th>{columns[0]}</Th>
<Th sort={getSortParams(1)}>{columns[1]}</Th>
<Th>{columns[2]}</Th>
<Th>{columns[3]}</Th>
<Th sort={getSortParams(4)}>{columns[4]}</Th>
<Th modifier="fitContent">{columns[5]}</Th>
<Th>{REACT_COLUMN_LABEL}</Th>
<Th sort={getSortParams(3)}>{columns[3]}</Th>
</Tr>
</Thead>
<Tbody>
{sortedRows.map((icon, index) => {
const Icon = icons[icon.React_name];
const iconUnicode = icon.Unicode || iconUnicodes.default[icon.Name] || '';

return (
<Tr key={index}>
Expand All @@ -148,43 +146,66 @@ export const IconsTable = () => {
</Tooltip>
</Td>
<Td dataLabel={columns[1]} modifier="fitContent">{icon.Name}</Td>
<Td dataLabel={columns[2]}>{icon.Style}</Td>
<Td dataLabel={columns[4]}>{icon.React_name}</Td>
<Td dataLabel={columns[5]}>
{icon.Contextual_usage}
{icon.Extra_context && (
<React.Fragment>
<br/><br/>{icon.Extra_context}
</React.Fragment>
)}
</Td>
<Td dataLabel={columns[6]}>
<Td dataLabel={REACT_COLUMN_LABEL} modifier="fitContent">
<Tooltip
trigger="mouseenter focus click"
content={<div>{isCopied ? 'Copied' : 'Copy'}</div>}
content={<div>{copiedReactName === icon.React_name ? 'Copied' : 'Copy React name'}</div>}
position={TooltipPosition.left}
exitDelay={isCopied ? 1000 : 100}
onTooltipHidden={() => setCopied(false)}
exitDelay={copiedReactName === icon.React_name ? 1000 : 100}
onTooltipHidden={() => {
if (copiedReactName === icon.React_name) {
setCopiedReactName(null);
}
}}
>
<Button
aria-label={`Copy ${icon.Name} icon unicode to clipboard`}
variant="plain"
onClick={(event) => clipboardCopyFunc(event, iconUnicode)}
<span
role="button"
tabIndex={0}
className="ws-icons-react-name-copy"
aria-label={`Copy ${icon.React_name} to clipboard`}
onClick={() => {
navigator.clipboard.writeText(icon.React_name);
setCopiedReactName(icon.React_name);
}}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
navigator.clipboard.writeText(icon.React_name);
setCopiedReactName(icon.React_name);
}
}}
>
{iconUnicode}
</Button>
{icon.React_name}
</span>
</Tooltip>
</Td>
<Td dataLabel={columns[3]}>
{icon.Contextual_usage}
{icon.Extra_context && (
<React.Fragment>
<br/><br/>{icon.Extra_context}
</React.Fragment>
)}
</Td>
</Tr>
)
})}
</Tbody>
</Table>

{filteredRows.length === 0 && (
<EmptyState titleText={`No results found for "${ searchValue }"`} headingLevel="h4" icon={SearchIcon}>
<EmptyStateBody>We couldn't find any icons that matched your search. If none of the icons listed fit
your use case, you may use any additional 'fa' icons within <a href="https://fontawesome.com/icons?d=gallery&amp;m=free">Font Awesome's free set</a>.
<EmptyState titleText={`No results found for "${ searchValue }"`} headingLevel="h4" icon={RhUiSearchIcon}>
<EmptyStateBody>
We couldn't find any icons that matched your search. Try different keywords or browse the full list above.
If you need an icon that isn't listed, you can{' '}
<a
href="https://docs.google.com/forms/d/e/1FAIpQLSde61rTDD4keaZEA3JFzBPbQVJ5EgEkhNapsYoI6ajKCsX4_Q/viewform"
target="_blank"
rel="noopener noreferrer"
>
request a new icon from the Red Hat brand team
</a>
.
</EmptyStateBody>
</EmptyState>
)}
Expand Down
Loading
Loading