diff --git a/.changeset/loud-spoons-explode.md b/.changeset/loud-spoons-explode.md
new file mode 100644
index 00000000000..a34200c9342
--- /dev/null
+++ b/.changeset/loud-spoons-explode.md
@@ -0,0 +1,5 @@
+---
+'@primer/react': minor
+---
+
+Migrated `VisuallyHidden` to CSS Modules
diff --git a/packages/react/src/DataTable/Pagination.tsx b/packages/react/src/DataTable/Pagination.tsx
index 7a3bfdfea70..42ee2a1fccb 100644
--- a/packages/react/src/DataTable/Pagination.tsx
+++ b/packages/react/src/DataTable/Pagination.tsx
@@ -373,7 +373,7 @@ function Range({pageStart, pageEnd, totalCount}: RangeProps) {
{start}
- through
+ through
‒
{end} of {totalCount}
diff --git a/packages/react/src/VisuallyHidden/VisuallyHidden.dev.stories.tsx b/packages/react/src/VisuallyHidden/VisuallyHidden.dev.stories.tsx
new file mode 100644
index 00000000000..2941dcf449a
--- /dev/null
+++ b/packages/react/src/VisuallyHidden/VisuallyHidden.dev.stories.tsx
@@ -0,0 +1,15 @@
+import React from 'react'
+import type {Meta} from '@storybook/react'
+import {VisuallyHidden} from './VisuallyHidden'
+
+export default {
+ title: 'Components/VisuallyHidden/Dev',
+ component: VisuallyHidden,
+} as Meta
+
+export const Default = () => (
+
+ Visible Text
+ Visually Hidden Text
+
+)
diff --git a/packages/react/src/VisuallyHidden/VisuallyHidden.module.css b/packages/react/src/VisuallyHidden/VisuallyHidden.module.css
new file mode 100644
index 00000000000..0b7ea0f8148
--- /dev/null
+++ b/packages/react/src/VisuallyHidden/VisuallyHidden.module.css
@@ -0,0 +1,10 @@
+.VisuallyHidden {
+ &:not(:focus):not(:active):not(:focus-within) {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ overflow: hidden;
+ white-space: nowrap;
+ clip-path: inset(50%);
+ }
+}
diff --git a/packages/react/src/VisuallyHidden/VisuallyHidden.tsx b/packages/react/src/VisuallyHidden/VisuallyHidden.tsx
index 546b6d2d812..da4e99be21b 100644
--- a/packages/react/src/VisuallyHidden/VisuallyHidden.tsx
+++ b/packages/react/src/VisuallyHidden/VisuallyHidden.tsx
@@ -1,6 +1,13 @@
import styled from 'styled-components'
import type {SxProp} from '../sx'
import sx from '../sx'
+import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent'
+import {clsx} from 'clsx'
+import {useFeatureFlag} from '../FeatureFlags'
+import React, {type HTMLAttributes} from 'react'
+import classes from './VisuallyHidden.module.css'
+
+const CSS_MODULES_FEATURE_FLAG = 'primer_react_css_modules_team'
/**
* Provides a component that implements the "visually hidden" technique. This is
@@ -12,17 +19,34 @@ import sx from '../sx'
*
* @see https://www.scottohara.me/blog/2023/03/21/visually-hidden-hack.html
*/
-export const VisuallyHidden = styled.span`
- &:not(:focus):not(:active):not(:focus-within) {
- clip-path: inset(50%);
- height: 1px;
- overflow: hidden;
- position: absolute;
- white-space: nowrap;
- width: 1px;
- }
+const StyledVisuallyHidden = toggleStyledComponent(
+ CSS_MODULES_FEATURE_FLAG,
+ 'span',
+ styled.span`
+ &:not(:focus):not(:active):not(:focus-within) {
+ clip-path: inset(50%);
+ height: 1px;
+ overflow: hidden;
+ position: absolute;
+ white-space: nowrap;
+ width: 1px;
+ }
+
+ ${sx}
+ `,
+)
- ${sx}
-`
+export const VisuallyHidden = ({className, children, ...rest}: VisuallyHiddenProps) => {
+ const enabled = useFeatureFlag(CSS_MODULES_FEATURE_FLAG)
+ return (
+
+ {children}
+
+ )
+}
-export type VisuallyHiddenProps = React.ComponentPropsWithoutRef
+export type VisuallyHiddenProps = React.PropsWithChildren<
+ HTMLAttributes & {
+ className?: string
+ } & SxProp
+>