# Iconography (/docs/iconography)



Luke UI includes one icon set. All the icons have the same weight, and all use a 24 by 24 grid. The
build collects the icons into one spritesheet file. The `Icon` component shows one symbol from that
file.

## Browse [#browse]

<IconGallery />

## Use an icon [#use-an-icon]

Import `Icon` and give it a name from the set. The `name` prop accepts only the names in the gallery
above. The compiler rejects any other name. See [Icon](/components/visuals/icon) for the component
API.

## Size [#size]

Set `size` to `xsmall`, `small`, `medium`, or `large`. Each size is a theme token, not a pixel
value. A custom theme can give each size a different value.

apps/docs/src/examples/icon/sizes.tsx

```tsx
import { Box } from '@luke-ui/react/box';
import { Icon } from '@luke-ui/react/icon';
import { Text } from '@luke-ui/react/text';
import type { PropsWithChildren } from 'react';

export default () => {
	return (
		<Box alignItems="flex-end" display="flex" flexWrap="wrap" gap="sp16">
			<FlexCol>
				<Icon name="search" size="xsmall" />
				<Text color="secondary" typography="caption">
					X-small
				</Text>
			</FlexCol>
			<FlexCol>
				<Icon name="search" size="small" />
				<Text color="secondary" typography="caption">
					Small
				</Text>
			</FlexCol>
			<FlexCol>
				<Icon name="search" size="medium" />
				<Text color="secondary" typography="caption">
					Medium
				</Text>
			</FlexCol>
			<FlexCol>
				<Icon name="search" size="large" />
				<Text color="secondary" typography="caption">
					Large
				</Text>
			</FlexCol>
		</Box>
	);
};

function FlexCol({ children }: PropsWithChildren) {
	return (
		<Box alignItems="center" display="flex" flexDirection="column" gap="sp4">
			{children}
		</Box>
	);
}
```

The default size is `medium`.

To give a group of icons the same size, put an `IconSizeProvider` around them. An icon that has its
own `size` prop keeps that size.

apps/docs/src/examples/icon/size-context.tsx

```tsx
import { Box } from '@luke-ui/react/box';
import { Icon, IconSizeProvider } from '@luke-ui/react/icon';

export default () => {
	return (
		<IconSizeProvider size="small">
			<Box alignItems="center" display="flex" gap="sp16">
				<Icon name="chevronLeft" title="Previous" />
				<Icon name="chevronRight" title="Next" />
			</Box>
		</IconSizeProvider>
	);
};
```

## Colour [#colour]

An icon takes the colour of the text around it. To change the colour of an icon, set the colour on
the icon or on a parent element.

apps/docs/src/examples/icon/colours.tsx

```tsx
import { Box } from '@luke-ui/react/box';
import { Icon } from '@luke-ui/react/icon';
import { Text } from '@luke-ui/react/text';
import type { PropsWithChildren } from 'react';

export default () => {
	return (
		<Box alignItems="center" display="flex" flexWrap="wrap" gap="sp16">
			<FlexCol>
				<Text color="primary">
					<Icon name="checkCircle" />
				</Text>
				<Text color="secondary">Primary</Text>
			</FlexCol>
			<FlexCol>
				<Text color="secondary">
					<Icon name="checkCircle" />
				</Text>
				<Text color="secondary">Secondary</Text>
			</FlexCol>
			<FlexCol>
				<Text color="accent">
					<Icon name="checkCircle" />
				</Text>
				<Text color="secondary">Accent</Text>
			</FlexCol>
			<FlexCol>
				<Text color="info">
					<Icon name="checkCircle" />
				</Text>
				<Text color="secondary">Info</Text>
			</FlexCol>
			<FlexCol>
				<Text color="success">
					<Icon name="checkCircle" />
				</Text>
				<Text color="secondary">Success</Text>
			</FlexCol>
			<FlexCol>
				<Text color="warning">
					<Icon name="checkCircle" />
				</Text>
				<Text color="secondary">Warning</Text>
			</FlexCol>
			<FlexCol>
				<Text color="danger">
					<Icon name="checkCircle" />
				</Text>
				<Text color="secondary">Danger</Text>
			</FlexCol>
		</Box>
	);
};

function FlexCol({ children }: PropsWithChildren) {
	return (
		<Box alignItems="center" display="flex" flexDirection="column" gap="sp4">
			{children}
		</Box>
	);
}
```

An icon that gives information must have a contrast ratio of 3 to 1 or more against its background.
An icon that only decorates adjacent text has no contrast requirement.

## Accessibility [#accessibility]

Each icon is decorative or informative.

The icon is decorative when the text next to it gives the meaning. Do not give it a title. The
component then hides the icon from assistive technology.

apps/docs/src/examples/icon/decorative.tsx

```tsx
import { Box } from '@luke-ui/react/box';
import { Icon } from '@luke-ui/react/icon';
import { Text } from '@luke-ui/react/text';

export default () => {
	return (
		<Box alignItems="center" display="flex" gap="sp4">
			<Text>Continue</Text>
			<Icon aria-hidden name="externalLink" size="xsmall" />
		</Box>
	);
};
```

The icon is informative when it appears alone. Give it a `title`. The component then shows the icon
to assistive technology as an image.

apps/docs/src/examples/icon/informative.tsx

```tsx
import { Icon } from '@luke-ui/react/icon';

export default () => {
	return <Icon name="checkCircle" title="Payment complete" />;
};
```

Do not set `aria-hidden` and `title` on the same icon.

## Set up the spritesheet [#set-up-the-spritesheet]

The `Icon` component reads its symbols from a spritesheet file. The package supplies this file at
`@luke-ui/react/spritesheet.svg`.

Put an `IconSpritesheetProvider` around your application. Give the provider the URL of the
spritesheet file.

apps/docs/src/samples/iconography/spritesheet-provider.tsx

```tsx
import { IconSpritesheetProvider } from '@luke-ui/react/icon';
import type { PropsWithChildren } from 'react';

export function AppSpritesheetProvider({ children }: PropsWithChildren) {
	return (
		<IconSpritesheetProvider href="/assets/spritesheet.svg">{children}</IconSpritesheetProvider>
	);
}
```

Your bundler must give a URL for the spritesheet file. It must not inline the file as a `data:` URL,
because a `<use>` reference to a `data:` URL does not resolve in all browsers. In Vite, the
`?url&no-inline` query gives this result.

```ts
import spriteSheetHref from '@luke-ui/react/spritesheet.svg?url&no-inline';
```

## When the set does not have an icon [#when-the-set-does-not-have-an-icon]

Use `createIcon` to make a component for a symbol that the set does not include. The new component
gets the same size behaviour and accessibility behaviour as `Icon`.

## Continue learning [#continue-learning]

<Cards>
  <Card href="/components/visuals/icon" title="Icon">
    The component API, and how to make a custom icon.
  </Card>

  <Card href="/components/actions/icon-button" title="Icon Button">
    Give an icon an accessible name to make a small button.
  </Card>
</Cards>
