Skip to content
5 changes: 5 additions & 0 deletions .changeset/lucky-bees-whisper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/clerk-js': patch
---

Correct the HTML structure of the UI components to ensure validity
1 change: 1 addition & 0 deletions packages/clerk-js/src/ui/common/NotificationCountBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const NotificationCountBadge = (props: NotificationCountBadgeProps) => {
<Flex
justify='center'
align='center'
as='span'
sx={[
t => ({
marginLeft: t.space.$1x5,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,25 +180,25 @@ const OrganizationListPageList = (props: { onCreateOrganizationClick: () => void
})}

{(hasNextPage || isLoading) && <PreviewListSpinner ref={ref} />}

<Action
elementDescriptor={descriptors.organizationListCreateOrganizationActionButton}
icon={Add}
label={localizationKeys('organizationList.action__createOrganization')}
onClick={handleCreateOrganizationClicked}
sx={t => ({
borderTopWidth: t.borderWidths.$normal,
borderTopStyle: t.borderStyles.$solid,
borderTopColor: t.colors.$neutralAlpha100,
padding: `${t.space.$5} ${t.space.$5}`,
})}
iconSx={t => ({
width: t.sizes.$9,
height: t.sizes.$6,
})}
/>
</Actions>
</PreviewListItems>

<Action
elementDescriptor={descriptors.organizationListCreateOrganizationActionButton}
icon={Add}
label={localizationKeys('organizationList.action__createOrganization')}
onClick={handleCreateOrganizationClicked}
sx={t => ({
borderTopWidth: t.borderWidths.$normal,
borderTopStyle: t.borderStyles.$solid,
borderTopColor: t.colors.$neutralAlpha100,
padding: `${t.space.$5} ${t.space.$5}`,
})}
iconSx={t => ({
width: t.sizes.$9,
height: t.sizes.$6,
})}
/>
</Col>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ const _OrganizationSwitcher = withFloatingTree(() => {
ref={reference}
onClick={toggle}
isOpen={isOpen}
aria-controls={switcherButtonMenuId}
aria-controls={isOpen ? switcherButtonMenuId : undefined}
Comment thread
panteliselef marked this conversation as resolved.
aria-expanded={isOpen}
/>
<Popover
nodeId={nodeId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ const _UserButton = withFloatingTree(() => {
ref={reference}
onClick={toggle}
isOpen={isOpen}
aria-controls={userButtonMenuId}
aria-controls={isOpen ? userButtonMenuId : undefined}
Comment thread
panteliselef marked this conversation as resolved.
aria-expanded={isOpen}
/>
<Popover
nodeId={nodeId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const UserButtonTopLevelIdentifier = ({ showName }: UserButtonTopLevelIde
return (
<Text
variant='subtitle'
as='span'
elementDescriptor={descriptors.userButtonOuterIdentifier}
sx={[
t => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const UserButtonTrigger = withAvatarShimmer(
elementDescriptor={descriptors.userButtonBox}
isOpen={props.isOpen}
align='center'
as='span'
gap={2}
>
<UserButtonTopLevelIdentifier showName={showName} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ export const ConnectedAccountsSection = withCardStateProvider(() => {
/>
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden' }}>
<Flex
as={'span'}
gap={2}
center
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,7 @@ export const EmailsSection = () => {
id='emailAddresses'
hoverable
>
<Flex
as='span'
sx={t => ({ overflow: 'hidden', gap: t.space.$1 })}
>
<Flex sx={t => ({ overflow: 'hidden', gap: t.space.$1 })}>
<Text
sx={t => ({ color: t.colors.$colorText })}
truncate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ export const EnterpriseAccountsSection = () => {
/>
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden' }}>
<Flex
as={'span'}
gap={2}
center
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ export const Web3Section = withCardStateProvider(() => {
)}
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden' }}>
<Flex
as={'span'}
gap={2}
justify='start'
>
Expand Down
2 changes: 2 additions & 0 deletions packages/clerk-js/src/ui/elements/Actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export const ExtraSmallAction = (props: Omit<ActionProps, 'label'>) => {
elementDescriptor={iconBoxElementDescriptor}
elementId={iconBoxElementId}
justify='center'
as='span'
>
{status.isLoading ? (
<Spinner
Expand Down Expand Up @@ -208,6 +209,7 @@ export const Action = (props: ActionProps) => {
elementDescriptor={iconBoxElementDescriptor}
elementId={iconBoxElementId}
justify='center'
as='span'
sx={[t => ({ flex: `0 0 ${t.sizes.$9}`, gap: t.space.$2, alignItems: 'center' }), iconBoxSx]}
>
{status.isLoading ? (
Expand Down
1 change: 1 addition & 0 deletions packages/clerk-js/src/ui/elements/ArrowBlockButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export const ArrowBlockButton = React.forwardRef<HTMLButtonElement, ArrowBlockBu
)}
<Flex
gap={2}
as='span'
sx={[
{
overflow: 'hidden',
Expand Down
6 changes: 3 additions & 3 deletions packages/clerk-js/src/ui/elements/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ export const Avatar = (props: AvatarProps) => {
title={title}
alt={title}
src={imageUrl || ''}
width='100%'
height='100%'
sx={{ objectFit: 'cover' }}
sx={{ objectFit: 'cover', width: '100%', height: '100%' }}
onError={() => setError(true)}
size={imageFetchSize}
/>
Expand All @@ -51,6 +49,7 @@ export const Avatar = (props: AvatarProps) => {
// TODO: Revise size handling. Do we need to be this dynamic or should we use the theme instead?
return (
<Flex
as='span'
elementDescriptor={[boxElementDescriptor, descriptors.avatarBox]}
sx={[
t => ({
Expand All @@ -73,6 +72,7 @@ export const Avatar = (props: AvatarProps) => {
* The ":after" selector is responsible for the border shimmer animation.
*/}
<Box
as='span'
sx={t => ({
overflow: 'hidden',
background: t.colors.$colorShimmer,
Expand Down
5 changes: 5 additions & 0 deletions packages/clerk-js/src/ui/elements/OrganizationPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,15 @@ export const OrganizationPreview = (props: OrganizationPreviewProps) => {
elementId={descriptors.organizationPreview.setId(elementId)}
gap={3}
align='center'
as='span'
Comment thread
panteliselef marked this conversation as resolved.
sx={[{ minWidth: '0' }, sx]}
{...rest}
>
<Flex
elementDescriptor={descriptors.organizationPreviewAvatarContainer}
elementId={descriptors.organizationPreviewAvatarContainer.setId(elementId)}
justify='center'
as='span'
sx={{ position: 'relative' }}
>
<OrganizationAvatar
Expand All @@ -76,12 +78,14 @@ export const OrganizationPreview = (props: OrganizationPreviewProps) => {
elementId={descriptors.organizationPreviewTextContainer.setId(elementId)}
direction='col'
justify='center'
as='span'
sx={{ minWidth: '0px', textAlign: 'left' }}
>
<Text
elementDescriptor={descriptors.organizationPreviewMainIdentifier}
elementId={descriptors.organizationPreviewMainIdentifier.setId(elementId)}
variant={mainTextSize}
as='span'
truncate
sx={mainIdentifierSx}
>
Expand All @@ -92,6 +96,7 @@ export const OrganizationPreview = (props: OrganizationPreviewProps) => {
elementDescriptor={descriptors.organizationPreviewSecondaryIdentifier}
elementId={descriptors.organizationPreviewSecondaryIdentifier.setId(elementId)}
localizationKey={localizeCustomRole(membership?.role) || unlocalizedRoleLabel}
as='span'
truncate
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ const PhoneInputBase = forwardRef<HTMLInputElement, PhoneInputProps & { feedback
>
<Text
colorScheme='primary'
as='span'
sx={{
textTransform: 'uppercase',
}}
Expand Down
7 changes: 6 additions & 1 deletion packages/clerk-js/src/ui/elements/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,12 @@ export const SelectButton = (
show = selectedOption ? (
buttonRenderOption(selectedOption)
) : (
<Text sx={t => ({ opacity: t.opacity.$inactive })}>{placeholder}</Text>
<Text
as='span'
sx={t => ({ opacity: t.opacity.$inactive })}
>
{placeholder}
</Text>
);
}

Expand Down
1 change: 1 addition & 0 deletions packages/clerk-js/src/ui/elements/SocialButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ const SocialButtonBlock = (props: SocialButtonProps): JSX.Element => {
<Flex
justify='center'
align='center'
as='span'
gap={3}
sx={{
width: '100%',
Expand Down
1 change: 1 addition & 0 deletions packages/clerk-js/src/ui/elements/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export const TabsList = (props: TabsListProps) => {
<Flex
elementDescriptor={descriptors.tabListContainer}
onKeyDown={onKeyDown}
role='tablist'
sx={[
t => ({
borderBottomStyle: t.borderStyles.$solid,
Expand Down
7 changes: 7 additions & 0 deletions packages/clerk-js/src/ui/elements/UserPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export const UserPreview = (props: UserPreviewProps) => {
elementDescriptor={descriptors.userPreview}
elementId={descriptors.userPreview.setId(elementId)}
align='center'
as='span'
sx={[t => ({ minWidth: '0px', width: 'fit-content', gap: t.space.$4 }), sx]}
{...rest}
>
Expand All @@ -95,6 +96,7 @@ export const UserPreview = (props: UserPreviewProps) => {
elementDescriptor={descriptors.userPreviewAvatarContainer}
elementId={descriptors.userPreviewAvatarContainer.setId(elementId)}
justify='center'
as='span'
sx={{ position: 'relative' }}
>
<UserAvatar
Expand All @@ -114,6 +116,7 @@ export const UserPreview = (props: UserPreviewProps) => {
<Flex
elementDescriptor={descriptors.userPreviewAvatarIcon}
sx={[{ position: 'absolute', left: 0, bottom: 0 }, iconSx]}
as='span'
>
{icon}
</Flex>
Expand All @@ -125,6 +128,7 @@ export const UserPreview = (props: UserPreviewProps) => {
elementDescriptor={descriptors.userPreviewAvatarContainer}
elementId={descriptors.userPreviewAvatarContainer.setId(elementId)}
justify='center'
as='span'
sx={t => ({
height: getAvatarSizes(t),
})}
Expand All @@ -137,12 +141,14 @@ export const UserPreview = (props: UserPreviewProps) => {
elementId={descriptors.userPreviewTextContainer.setId(elementId)}
direction='col'
justify='center'
as='span'
sx={{ minWidth: '0px', textAlign: 'left' }}
>
<Text
elementDescriptor={descriptors.userPreviewMainIdentifier}
elementId={descriptors.userPreviewMainIdentifier.setId(elementId)}
variant={mainIdentifierSize}
as='span'
sx={[theme => ({ display: 'flex', gap: theme.sizes.$1, alignItems: 'center' }), mainIdentifierSx]}
>
{previewTitle && (
Expand All @@ -163,6 +169,7 @@ export const UserPreview = (props: UserPreviewProps) => {
elementDescriptor={descriptors.userPreviewSecondaryIdentifier}
elementId={descriptors.userPreviewSecondaryIdentifier.setId(elementId)}
truncate
as='span'
localizationKey={subtitle || identifier}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ describe('PlainInput', () => {
expect(getByLabelText('some label')).not.toHaveAttribute('disabled');
expect(getByLabelText('some label')).not.toHaveAttribute('required');
expect(getByLabelText('some label')).toHaveAttribute('aria-invalid', 'false');
expect(getByLabelText('some label')).toHaveAttribute('aria-describedby', '');
expect(getByLabelText('some label')).toHaveAttribute('aria-required', 'false');
expect(getByLabelText('some label')).toHaveAttribute('aria-disabled', 'false');
});
Expand Down
2 changes: 1 addition & 1 deletion packages/clerk-js/src/ui/primitives/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>((props, ref)
required={_required}
id={props.id || fieldControlProps.id}
aria-invalid={_hasError}
aria-describedby={errorMessageId}
aria-describedby={errorMessageId ? errorMessageId : undefined}
Comment thread
panteliselef marked this conversation as resolved.
aria-required={_required}
aria-disabled={_disabled}
data-feedback={feedbackType}
Expand Down