From bb559d327f98c243b426aaf036653199b09cf553 Mon Sep 17 00:00:00 2001 From: Preston Booth Date: Wed, 1 Jul 2026 11:10:00 -0600 Subject: [PATCH] feat(ui): increase button and input height for larger touch targets Buttons and inputs get taller by growing their default vertical padding from 6px to 7px, and to 8px on mobile (<=480px). Social provider icon buttons match the new height and their icons scale from 16px to 20px on mobile. --- .changeset/tall-buttons-inputs.md | 5 +++++ packages/ui/src/elements/SocialButtons.tsx | 7 +++++++ packages/ui/src/foundations/sizes.ts | 2 ++ packages/ui/src/primitives/Button.tsx | 9 +++++++-- packages/ui/src/primitives/Input.tsx | 9 +++++++-- 5 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 .changeset/tall-buttons-inputs.md diff --git a/.changeset/tall-buttons-inputs.md b/.changeset/tall-buttons-inputs.md new file mode 100644 index 00000000000..acfd29da095 --- /dev/null +++ b/.changeset/tall-buttons-inputs.md @@ -0,0 +1,5 @@ +--- +'@clerk/ui': patch +--- + +Increase the default height of buttons and inputs for larger, easier-to-tap touch targets, especially on mobile. Their default vertical padding grows from 6px to 7px, and to 8px on mobile (≤480px). Social provider icon buttons match the taller height, and their icons scale from 16px to 20px on mobile. diff --git a/packages/ui/src/elements/SocialButtons.tsx b/packages/ui/src/elements/SocialButtons.tsx index 7b3d8b76186..561355d6fa9 100644 --- a/packages/ui/src/elements/SocialButtons.tsx +++ b/packages/ui/src/elements/SocialButtons.tsx @@ -195,6 +195,11 @@ export const SocialButtons = React.memo((props: SocialButtonsRootProps) => { isLoading={card.loadingMetadata === strategy} isDisabled={card.isLoading} alt={`Sign in with ${strategyToDisplayData[strategy].name}`} + // Icon-only buttons get a 16px glyph on desktop and 20px on mobile to + // stay proportional to the taller button; block buttons keep 16px, which + // fits their fixed icon slot. + size='$4' + sx={preferBlockButtons ? undefined : t => ({ [mqu.sm]: { width: t.sizes.$5, height: t.sizes.$5 } })} elementDescriptor={[descriptors.providerIcon, descriptors.socialButtonsProviderIcon]} elementId={descriptors.socialButtonsProviderIcon.setId(strategyToDisplayData[strategy].id)} /> @@ -250,8 +255,10 @@ const SocialButtonIcon = forwardRef((props: SocialButtonProps, ref: Ref ({ + // Match the taller block/primary buttons so the icon row lines up. minHeight: t.sizes.$8, width: '100%', + [mqu.sm]: { minHeight: t.sizes.$9 }, })} {...rest} > diff --git a/packages/ui/src/foundations/sizes.ts b/packages/ui/src/foundations/sizes.ts index 5ca3de87f4b..f4dc87aeba3 100644 --- a/packages/ui/src/foundations/sizes.ts +++ b/packages/ui/src/foundations/sizes.ts @@ -18,6 +18,7 @@ const spacingScale = Object.freeze({ '0x5': { rem: '0.125rem', multiplier: 0.5 }, '1': { rem: '0.25rem', multiplier: 1 }, '1x5': { rem: '0.375rem', multiplier: 1.5 }, + '1x75': { rem: '0.4375rem', multiplier: 1.75 }, '2': { rem: '0.5rem', multiplier: 2 }, '2x5': { rem: '0.625rem', multiplier: 2.5 }, '3': { rem: '0.75rem', multiplier: 3 }, @@ -96,6 +97,7 @@ const spaceUnits = Object.freeze({ '0x5': spacingScale['0x5'].rem, '1': spacingScale['1'].rem, '1x5': spacingScale['1x5'].rem, + '1x75': spacingScale['1x75'].rem, '2': spacingScale['2'].rem, '2x5': spacingScale['2x5'].rem, '3': spacingScale['3'].rem, diff --git a/packages/ui/src/primitives/Button.tsx b/packages/ui/src/primitives/Button.tsx index 3a10dd034cc..37dadd20858 100644 --- a/packages/ui/src/primitives/Button.tsx +++ b/packages/ui/src/primitives/Button.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { descriptors, Icon, Spinner } from '../customizables'; import { TriangleRight } from '../icons'; import type { PrimitiveProps, StyleVariants } from '../styledSystem'; -import { common, createCssVariables, createVariants } from '../styledSystem'; +import { common, createCssVariables, createVariants, mqu } from '../styledSystem'; import { applyDataStateProps } from './applyDataStateProps'; import { Flex } from './Flex'; @@ -40,7 +40,12 @@ const { applyVariants, filterProps } = createVariants( padding: `${theme.space.$1} ${theme.space.$3}`, }, sm: { - padding: `${theme.space.$1x5} ${theme.space.$3}`, + // Taller controls on mobile (8px) than desktop (7px) for easier tapping. + padding: `${theme.space.$1x75} ${theme.space.$3}`, + [mqu.sm]: { + paddingTop: theme.space.$2, + paddingBottom: theme.space.$2, + }, }, md: { padding: `${theme.space.$2x5} ${theme.space.$5}`, diff --git a/packages/ui/src/primitives/Input.tsx b/packages/ui/src/primitives/Input.tsx index 6ef03a6e9f2..b1a4e9d7b5c 100644 --- a/packages/ui/src/primitives/Input.tsx +++ b/packages/ui/src/primitives/Input.tsx @@ -10,13 +10,13 @@ const { applyVariants, filterProps } = createVariants((theme, props) => ({ base: { boxSizing: 'border-box', margin: 0, - padding: `${theme.space.$1x5} ${theme.space.$3}`, + padding: `${theme.space.$1x75} ${theme.space.$3}`, backgroundColor: theme.colors.$colorInput, color: theme.colors.$colorInputForeground, // outline support for Windows contrast themes outline: 'transparent solid 2px', outlineOffset: '2px', - maxHeight: theme.sizes.$9, + maxHeight: theme.sizes.$10, width: props.type === 'checkbox' ? theme.sizes.$4 : '100%', accentColor: theme.colors.$primary500, ...(props.type === 'checkbox' @@ -35,6 +35,11 @@ const { applyVariants, filterProps } = createVariants((theme, props) => ({ : {}), ...common.textVariants(theme).body, ...common.disabled(theme), + // Taller inputs on mobile (8px) than desktop (7px) for easier tapping. + [mqu.sm]: { + paddingTop: theme.space.$2, + paddingBottom: theme.space.$2, + }, // This is a workaround to prevent zooming on iOS when focusing an input [mqu.ios]: { fontSize: theme.fontSizes.$lg,