Skip to main content

Input group

An input with addons inside its border: icons, text, buttons.

In Brand expressive

See it live​

Start Storybook to see it live: npm run storybook

When to use it​

In Brand expressive: A value with a unit, or a search with a clear button. Not for controls that are separate fields.

  • Use it when: A search with an icon and a clear button, a value with a unit or currency.
  • Not when: Controls that are separate fields (lay them out with field).

Instead:

Variants​

What each variant is for in any design system, then what Brand expressive decided and why. Each sample is the live story with that variant set.

inline-startalignUsed in Brand expressive
Start Storybook to see it live

What it is for

An addon before the text, on the same line: an icon or currency.

✓A search icon or a unit that comes first.
✕Something people press often; put it after the text.

In Brand expressive

The search icon before the text.

inline-endalignUsed in Brand expressive
Start Storybook to see it live

What it is for

An addon after the text: a unit, a clear button, a shortcut.

✓Clear, submit or a unit that follows the value.
✕A label that should be outside the field.

In Brand expressive

The unit after the value, or the clear button with a word: hover hints never show on phones.

block-startalignNot used in Brand expressive
Start Storybook to see it live

What it is for

An addon row above the text, inside the field.

✓A toolbar or a label row for a larger input.
✕Single-line fields in a toolbar.

In Brand expressive

Copy is short and sign-up is the one action, so fields stay one line.

block-endalignNot used in Brand expressive
Start Storybook to see it live

What it is for

An addon row below the text, inside the field.

✓A counter or actions under a larger input.
✕Single-line fields in a toolbar.

In Brand expressive

Copy is short and sign-up is the one action, so fields stay one line.

Why it works this way​

Input group looks the way it does because of 4 answers about this product. Each card is one answer, in three steps: the answer, what it decided for Input group, and what would move if it changed.

What do icons do?iconography.roles
1The answer
Those and decoration

Icons also decorate campaign pages.

2So Input group
  • ✓uses inline-start: The search icon before the text.
It also shapes Button: ghost Button: icon Empty: icon
3If it changed
1
Input group decision would reopen

and 1 answer that follow from it: Two.

What is the smallest target?accessibility.values
1The answer
Touch size

Visitors come from social posts on phones.

2So Input group
  • ✓uses inline-end: The unit after the value, or the clear button with a word: hover hints never show on phones.
It also shapes Button: default Button: compact Button: icon Field: horizontal Item: default Item: sm Toggle: default Toggle: sm
3If it changed
1
Input group decision would reopen

and 1 answer that follow from it: Those and pressed.

What is the main content?content.q1
1The answer
Images and campaigns

Images, campaigns and short punchy copy.

2So Input group
  • –does not use block-start: Copy is short and sign-up is the one action, so fields stay one line.
  • –does not use block-end: Copy is short and sign-up is the one action, so fields stay one line.
It also shapes Badge: info Empty: default
3If it changed
2
Input group decisions would reopen

and 10 answers that follow from it: One idea at a time, Browse and explore, Regular, and 7 more.

How often do people repeat actions?tasks.q2
1The answer
Rarely

One action: sign up.

2So Input group
  • –does not use block-start: Copy is short and sign-up is the one action, so fields stay one line.
  • –does not use block-end: Copy is short and sign-up is the one action, so fields stay one line.
It also shapes Alert: default Toggle: lg
3If it changed
2
Input group decisions would reopen

and 2 answers that follow from it: Three, Only what today's screens use.

Words​

  • Headlines are short and bold. Three to six words.
  • Verbs that move: Join, Try, Go.
  • Playful in headlines, plain in errors.
  • Use: Join, Drop, Go, Love. Avoid: Synergy, Leverage, Kindly.

The labels components use, from the voice tokens:

  • content.action.commit: Go
  • content.action.cancel: Not now
  • content.action.destroy: Remove
  • content.action.retry: Try again
  • content.action.empty-action: Explore the drop

See Voice and tone for the whole voice.

Accessibility and keyboard​

Test before you ship:

  • Addon buttons have names; icons that only decorate are hidden from screen readers. undefined

Use it in code​

npx open-ds add input-group

The component reads only component keys and semantic tokens, so it follows the brand and mode on <html>.

Tokens it reads​

Input group reads 37 tokens of its own, each an alias of a semantic token. Each row is one part: its own token, the semantic it aliases, and the value it ends at. Change a semantic and every component that reads it follows; override one of Input group's tokens to change Input group alone.

Changes with theme

Brand expressive decides what changes when you switch theme. Here a switch changes colors only, so the marked rows differ between light and dark; everything else holds steady.

PartIts token and the semantic it aliasesValue
Input group
Cornercomponent.input-group.radiusradius.controlvar(--input-group-radius)radius.999:9999px
Border
Changes with theme
component.input-group.bordercolor.border.strongvar(--input-group-border)Lighttaupe.light.500:#8A6F63Darktaupe.dark.400:#B5988A
Shadow
Changes with theme
component.input-group.shadowelevation.cardvar(--input-group-shadow)Lightshadow.cardDarkshadow.card-dark
Padding leftcomponent.input-group.padding-leftcomponent-spacing-map.x2var(--input-group-padding-left)space.8:0.5rem
Padding rightcomponent.input-group.padding-rightcomponent-spacing-map.x2var(--input-group-padding-right)space.8:0.5rem
Padding, bottomcomponent.input-group.padding-bottomspace.inset.control-xvar(--input-group-padding-bottom)space.28:1.75rem
Padding, topcomponent.input-group.padding-topspace.inset.control-xvar(--input-group-padding-top)space.28:1.75rem
Border 2
Changes with theme
component.input-group.border-2color.border.focusvar(--input-group-border-2)Lightpink.light.600:#D61F7ADarkpink.dark.600:#F59ACA
Focus ring
Changes with theme
component.input-group.focus-ringcolor.border.focusvar(--input-group-focus-ring)Lightpink.light.600:#D61F7ADarkpink.dark.600:#F59ACA
Border invalid
Changes with theme
when invalid
component.input-group.border-invalidcolor.status.dangervar(--input-group-border-invalid)Lightred.light.600:#C42B2BDarkred.dark.600:#F28B8B
Focus ring invalid
Changes with theme
when invalid
component.input-group.focus-ring-invalidcolor.status.dangervar(--input-group-focus-ring-invalid)Lightred.light.600:#C42B2BDarkred.dark.600:#F28B8B
Gapcomponent.input-group.gapspace.gap.defaultvar(--input-group-gap)space.16:1rem
Padding, top and bottomcomponent.input-group.padding-ycomponent-spacing-map.x2var(--input-group-padding-y)space.8:0.5rem
Text sizecomponent.input-group.font-sizetype.body.font-sizevar(--input-group-font-size)font.size.17:1.0625rem
Weightcomponent.input-group.font-weighttype.label.font-weightvar(--input-group-font-weight)font.weight.700:700
Text
Changes with theme
component.input-group.labelcolor.text.mutedvar(--input-group-label)Lighttaupe.light.600:#6B544ADarktaupe.dark.400:#B5988A
Disabled opacity disabled
when disabled
component.input-group.disabled-opacity-disabledopacity.disabledvar(--input-group-disabled-opacity-disabled)opacity.40:0.4
Icon sizecomponent.input-group.icon-sizesize.iconvar(--input-group-icon-size)size.20:1.25rem
Inline
Start padding leftcomponent.input-group.inline.start.padding-leftspace.inset.control-xvar(--input-group-inline-start-padding-left)space.28:1.75rem
End padding rightcomponent.input-group.inline.end.padding-rightspace.inset.control-xvar(--input-group-inline-end-padding-right)space.28:1.75rem
Block
Start padding xcomponent.input-group.block.start.padding-xspace.inset.control-xvar(--input-group-block-start-padding-x)space.28:1.75rem
Start padding topcomponent.input-group.block.start.padding-topspace.inset.control-xvar(--input-group-block-start-padding-top)space.28:1.75rem
Start padding top 2component.input-group.block.start.padding-top-2component-spacing-map.x3var(--input-group-block-start-padding-top-2)space.24:1.5rem
Start padding bottomcomponent.input-group.block.start.padding-bottomspace.inset.control-xvar(--input-group-block-start-padding-bottom)space.28:1.75rem
End padding xcomponent.input-group.block.end.padding-xspace.inset.control-xvar(--input-group-block-end-padding-x)space.28:1.75rem
End padding bottomcomponent.input-group.block.end.padding-bottomspace.inset.control-xvar(--input-group-block-end-padding-bottom)space.28:1.75rem
End padding bottom 2component.input-group.block.end.padding-bottom-2component-spacing-map.x3var(--input-group-block-end-padding-bottom-2)space.24:1.5rem
End padding topcomponent.input-group.block.end.padding-topspace.inset.control-xvar(--input-group-block-end-padding-top)space.28:1.75rem
Xs
Heightcomponent.input-group.xs.heightsize.control.compactvar(--input-group-xs-height)size.44:2.75rem
Gapcomponent.input-group.xs.gapspace.gap.tightvar(--input-group-xs-gap)space.8:0.5rem
Padding, left and rightcomponent.input-group.xs.padding-xcomponent-spacing-map.x2var(--input-group-xs-padding-x)space.8:0.5rem
Sm
Heightcomponent.input-group.sm.heightsize.control.defaultvar(--input-group-sm-height)size.52:3.25rem
Gapcomponent.input-group.sm.gapcomponent-spacing-map.x2var(--input-group-sm-gap)space.8:0.5rem
Cornercomponent.input-group.sm.radiusradius.controlvar(--input-group-sm-radius)radius.999:9999px
Padding, left and rightcomponent.input-group.sm.padding-xcomponent-spacing-map.x3var(--input-group-sm-padding-x)space.24:1.5rem
Icon
Sm sizecomponent.input-group.icon.sm.sizesize.control.defaultvar(--input-group-icon-sm-size)size.52:3.25rem
Control
Padding, top and bottomcomponent.input-group.control.padding-yspace.inset.control-xvar(--input-group-control-padding-y)space.28:1.75rem
From the system
Edge
Changes with theme
color.border.default
straight from the system, through --border
Lighttaupe.light.200 · #F2DCCFDarktaupe.dark.100 · #33241F