A pressable tile with a picture and a short label under it, for choosing among looks, presets or templates in a gallery.
Options
| Choice | Values | Default | What it does |
|---|---|---|---|
ratiosmbk-picture-tile--ratio-<value> | 4-31-1 | 4-3 | The picture's proportion, width to height: 4:3 or square. |
selectedsmbk-picture-tile--selected | On or off | Off | The chosen tile: the rim edge at the emphasis width and a tick at the picture's corner. Pressed for assistive technology. |
Examples
Usage
A gallery of looks, two to a row: one is chosen, and the others are toggles that are off.
Ratios
The picture at 4:3 or square.
States
Chosen tiles show the stronger edge and the tick; disabled tiles dim their picture and label.
Loading and missing pictures
A skeleton while the picture loads; an image placeholder when there is none.
A wrapping grid
Tiles fill their cells and wrap; a long label is cut short with an ellipsis.
Guidelines
Purpose
Lets someone choose among things best told apart by a picture: a look, a preset, a template, a theme. Each tile is one button with a picture on top and a short label under it, laid out in a grid that wraps. Pointing at a tile can preview it; pressing it chooses it.
When to use
- A gallery of options that look different, where the picture says more than the name: filters, styles, layouts, templates.
- With one tile chosen, as a set of toggles where one is on.
When not to use
- For an article or a product with a title, a description and actions. Use a card.
- For options that differ only by name. Use radios, a segmented control or a select.
- For a picture that opens a larger view and nothing else. Use a link around the picture.
Usage rules
Do
- Keep labels to a word or two.
- Show the same subject in every tile, so only the option changes.
- Give each tile the same proportion in one gallery.
Don't
- Put a button or a link inside a tile.
- Mix tiles that choose with tiles that run an action in one gallery.
Show the same subject in every tile, so only the look changes.
Tiles of different proportions in one gallery break its rows.
Anatomy
- The block, one button: a frame on the default surface with a thin edge and a small rounded corner, as wide as the cell it is given.
- The picture part, at a 4:3 or square proportion on the sunken surface. It holds the picture, an image placeholder while there is none, or a skeleton while it loads.
- The label part, one line of small body text under the picture, cut short with an ellipsis when it is too long.
- The tick part, shown on the chosen tile only: a check on a brand-colored disc at the picture's top corner.
Behavior
The tile fills the cell it is given and is never narrower than a small minimum, so a grid of tiles wraps on a narrow screen. Pointing at a tile strengthens its edge; pressing sinks it onto the sunken surface; keyboard focus draws the focus ring around it. The chosen tile shows a stronger edge at double width, a slight lift and the tick; pointing at it changes nothing more. A disabled tile dims its picture and label and cannot be pressed. A picture that fails to load gives way to the image placeholder, named by the picture's alternative text when it has one, so the tile never shows the browser's broken-picture mark.
Accessibility
What it does for you
- The whole tile is one native button and one Tab stop, named by its label.
- With
selectedset, true or false, the tile is a toggle and a screen reader says whether it is pressed. - The picture is decoration with an empty text alternative, since the label names the tile.
- The tick, not only the edge's color, shows which tile is chosen. In high contrast mode the chosen edge and the tick take the highlight color.
- The label is cut short with an ellipsis when long, but the button's name is the whole label.
- A picture that fails to load gives way to the image placeholder, named by the picture's alternative text when it has one.
What you must do
- Leave
selectedout for a tile that does something once when pressed. - Give the picture a text alternative when it shows something the label does not say.
- Preview anything a tile previews on pointing also on keyboard focus: nothing may be shown by pointing alone.
- Keep labels short so everyone sees all of them.
How to test
- Tab to a tile: the focus ring shows around it, in both themes and in a forced-color mode.
- Press Enter, then Space: each presses the tile. A disabled tile cannot be pressed.
- With a screen reader, a tile is read as a button by its whole label. A selecting tile is read as pressed or not pressed.
- With text at 200% and the page 320 pixels wide, the tiles wrap into fewer columns and each keeps its label.
- In a forced-color mode, the chosen tile's edge and tick are drawn in the highlight color.
Keyboard
| Key | What it does |
|---|---|
| Tab | Moves focus to the tile. A disabled tile is skipped. |
| EnterorSpace | Presses the tile. |
Source
The files the picture tile is made of. Its folder on GitHub (opens in a new tab) holds them with its wrapper and its document.
Stylesheet
/* smbk-picture-tile — Picture tile. Figma "Picture tile" 7119:143 (Selected × State × Ratio, 20 variants).
* One native button: a picture on top, at 4:3 or 1:1, and a short label under
* it, in a frame of the default surface with a hairline edge in the subtle
* border color and a small container's corner. It fills the cell it is given,
* never narrower than the 88 size step, so a grid of them wraps. Pointing
* strengthens the edge; pressing sinks the frame onto the sunken surface;
* focus draws the shared ring outside it. Chosen, the edge turns the rim color
* at the emphasis width, drawn inside so nothing moves, the tile lifts with
* the control elevation, and a tick on a brand disc marks the picture's
* corner: the shape says it is chosen, not the color alone. Disabled dims the
* picture and the label. */
.smbk-picture-tile {
box-sizing: border-box;
position: relative;
display: flex;
flex-direction: column;
gap: var(--smbk-space-stack-sm);
width: 100%;
min-width: var(--smbk-size-88);
margin: 0;
padding: var(--smbk-space-inset-2xs);
border: var(--smbk-border-width-hairline) solid var(--smbk-color-border-subtle);
border-radius: var(--smbk-radius-container-sm);
background: var(--smbk-color-surface-default);
color: var(--smbk-color-text-default);
font: inherit;
text-align: start;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
}
/* The picture: the tile's width at the ratio, on the sunken surface, with the inset corner. Whatever it holds
(a picture, an image placeholder, a skeleton) fills it. */
.smbk-picture-tile__picture {
display: block;
overflow: hidden;
aspect-ratio: 4 / 3;
border-radius: var(--smbk-radius-inset);
background: var(--smbk-color-surface-sunken);
}
.smbk-picture-tile__picture > * {
display: block;
width: 100%;
height: 100%;
}
.smbk-picture-tile__picture > img {
object-fit: cover;
}
.smbk-picture-tile--ratio-1-1 .smbk-picture-tile__picture {
aspect-ratio: 1 / 1;
}
/* The label: one line of Body SM, cut short with an ellipsis; the button's name stays the whole label. */
.smbk-picture-tile__label {
display: block;
overflow: hidden;
padding: var(--smbk-space-inset-xs) var(--smbk-space-inset-md) var(--smbk-space-inset-md);
font-family: var(--smbk-typography-body-sm-font-family);
font-size: var(--smbk-typography-body-sm-font-size);
font-weight: var(--smbk-typography-body-sm-font-weight);
line-height: var(--smbk-typography-body-sm-line-height);
letter-spacing: var(--smbk-typography-body-sm-letter-spacing);
text-overflow: ellipsis;
white-space: nowrap;
}
/* The tick: a brand disc with a check, 8 in from the tile's top and end corner. Shown only when chosen. */
.smbk-picture-tile__tick {
position: absolute;
inset-block-start: var(--smbk-space-inset-md);
inset-inline-end: var(--smbk-space-inset-md);
display: none;
align-items: center;
justify-content: center;
width: var(--smbk-size-20);
height: var(--smbk-size-20);
border-radius: var(--smbk-radius-full);
background: var(--smbk-color-action-brand-background);
color: var(--smbk-color-icon-on-brand);
}
.smbk-picture-tile__tick .smbk-icon {
font-size: var(--smbk-size-icon-xs);
}
/* ---- states ---- */
@media (hover: hover) {
.smbk-picture-tile:hover:enabled:not(.smbk-picture-tile--selected) {
border-color: var(--smbk-color-border-strong);
}
}
.smbk-picture-tile:active:enabled {
background: var(--smbk-color-surface-sunken);
}
.smbk-picture-tile:focus-visible {
outline: var(--smbk-focus-ring-width) solid var(--smbk-color-border-focus);
outline-offset: var(--smbk-focus-ring-offset);
}
/* Chosen: the rim at the emphasis width, the hairline border plus the rest drawn inside, and the lift. */
.smbk-picture-tile--selected {
border-color: var(--smbk-color-border-rim);
box-shadow: inset 0 0 0 calc(var(--smbk-border-width-emphasis) - var(--smbk-border-width-hairline)) var(--smbk-color-border-rim), var(--smbk-elevation-control);
}
.smbk-picture-tile--selected .smbk-picture-tile__tick {
display: flex;
}
.smbk-picture-tile:disabled {
cursor: default;
}
.smbk-picture-tile:disabled .smbk-picture-tile__picture {
opacity: var(--smbk-opacity-disabled);
}
.smbk-picture-tile:disabled .smbk-picture-tile__label {
color: var(--smbk-color-text-disabled);
}
/* ---- high contrast (forced colors) ---- */
/* In Windows high-contrast mode the browser drops fills and shadows; this puts the meaning back with the
user's own colors. Nothing here applies outside that mode. */
@media (forced-colors: active) {
/* The chosen edge's inner half is a shadow and would vanish: the edge takes Highlight at full width. The
tick's disc is a fill: it keeps its shape in Highlight with the check in the highlight's text color. */
.smbk-picture-tile--selected {
border-width: var(--smbk-border-width-emphasis);
border-color: Highlight;
padding: calc(var(--smbk-space-inset-2xs) - var(--smbk-border-width-emphasis) + var(--smbk-border-width-hairline));
}
.smbk-picture-tile__tick {
forced-color-adjust: none;
background: Highlight;
color: HighlightText;
}
.smbk-picture-tile:disabled {
border-color: GrayText;
}
}Tokens it reads
| Token and CSS | Value | Preview | Foundation |
|---|---|---|---|
| space.stack.sm--smbk-space-stack-sm | comfortable: 8pxcompact: 6pxchanges with density | Spacing | |
| size.88--smbk-size-88 | 88px | Size | |
| space.inset.2xs--smbk-space-inset-2xs | 2px | Spacing | |
| border-width.hairline--smbk-border-width-hairline | 1px | Border width | |
| color.border.subtle--smbk-color-border-subtle | light: #c4cdd8dark: #2d3237changes with theme | Color | |
| radius.container.sm--smbk-radius-container-sm | 8px | Radius | |
| color.surface.default--smbk-color-surface-default | light: #f3f5f8dark: #181a1cchanges with theme | Color | |
| color.text.default--smbk-color-text-default | light: #232527dark: #e7ebf0changes with theme | Color | |
| radius.inset--smbk-radius-inset | 2px | Radius | |
| color.surface.sunken--smbk-color-surface-sunken | light: #373d430ddark: #00000066changes with theme | Color | |
| space.inset.xs--smbk-space-inset-xs | 4px | Spacing | |
| space.inset.md--smbk-space-inset-md | comfortable: 8pxcompact: 6pxchanges with density | Spacing | |
| typography.body-sm--smbk-typography-body-sm-font-family--smbk-typography-body-sm-font-size--smbk-typography-body-sm-font-weight--smbk-typography-body-sm-line-height--smbk-typography-body-sm-letter-spacing--smbk-typography-body-sm-text-transform | fontFamily: Geist, Geist Fallback, system-ui, sans-seriffontSize: 14pxfontWeight: 400lineHeight: 1.5letterSpacing: 0px | The quick brown fox | Typography |
| size.20--smbk-size-20 | 20px | Size | |
| radius.full--smbk-radius-full | 9999px | Radius | |
| color.action.brand.background--smbk-color-action-brand-background | #cc0d0d | Color | |
| color.icon.on-brand--smbk-color-icon-on-brand | #f9fafb | Color | |
| size.icon.xs--smbk-size-icon-xs | 12px | Size | |
| color.border.strong--smbk-color-border-strong | light: #9ba5b1dark: #373d43changes with theme | Color | |
| focus.ring.width--smbk-focus-ring-width | 2px | Focus | |
| color.border.focus--smbk-color-border-focus | light: #cc0d0ddark: #f34336changes with theme | Color | |
| focus.ring.offset--smbk-focus-ring-offset | 2px | Focus | |
| color.border.rim--smbk-color-border-rim | light: #ffffffe6dark: #ffffff0dchanges with theme | Color | |
| border-width.emphasis--smbk-border-width-emphasis | 2px | Border width | |
| elevation.control--smbk-elevation-control | light: 0px 0px 1px 0px #373d430d, 0px 1px 2px 0px #373d431a, 0px 2px 4px 0px #373d430ddark: 0px 0px 1px 0px #0000001a, 0px 1px 2px 0px #00000026, 0px 2px 4px 0px #0000001a | Elevation | |
| opacity.disabled--smbk-opacity-disabled | 0.5 | Opacity | |
| color.text.disabled--smbk-color-text-disabled | light: #7c8692dark: #606a75changes with theme | Color |
Manifest
{
"name": "picture-tile",
"block": "smbk-picture-tile",
"summary": "A pressable tile with a picture and a short label under it, for choosing among looks, presets or templates in a gallery.",
"adapt": "css",
"axes": {
"ratio": {
"values": [
"4-3",
"1-1"
],
"default": "4-3",
"description": "The picture's proportion, width to height: 4:3 or square."
}
},
"flags": {
"selected": {
"description": "The chosen tile: the rim edge at the emphasis width and a tick at the picture's corner. Pressed for assistive technology."
}
},
"parts": [
"picture",
"label",
"tick"
],
"figmaNodeId": "7119:143"
}