diff --git a/.changeset/few-houses-grow.md b/.changeset/few-houses-grow.md new file mode 100644 index 00000000000..abfa07751d1 --- /dev/null +++ b/.changeset/few-houses-grow.md @@ -0,0 +1,29 @@ +--- +"@aws-amplify/ui-react": minor +"@aws-amplify/ui": minor +--- + +feat(theming) add custom component style rendering + +```jsx +const customComponentTheme = defineComponentTheme({ + name: 'custom-component', + theme(tokens) { + return { + color: tokens.colors.red[10] + } + } +}); + +export function CustomComponent() { + return ( + <> + + + // This will create a style tag with only the styles in the component theme + // the styles are scoped to the global theme + + + ) +} +``` diff --git a/packages/react/__tests__/__snapshots__/exports.ts.snap b/packages/react/__tests__/__snapshots__/exports.ts.snap index de8d2ffb9e8..2d0d524fcea 100644 --- a/packages/react/__tests__/__snapshots__/exports.ts.snap +++ b/packages/react/__tests__/__snapshots__/exports.ts.snap @@ -122,6 +122,7 @@ exports[`@aws-amplify/ui-react/internal exports should match snapshot 1`] = ` exports[`@aws-amplify/ui-react/server exports should match snapshot 1`] = ` [ + "ComponentStyle", "ThemeStyle", "createComponentClasses", "createTheme", diff --git a/packages/react/src/components/ThemeProvider/ComponentStyle.tsx b/packages/react/src/components/ThemeProvider/ComponentStyle.tsx new file mode 100644 index 00000000000..dac347e478b --- /dev/null +++ b/packages/react/src/components/ThemeProvider/ComponentStyle.tsx @@ -0,0 +1,53 @@ +import * as React from 'react'; +import { WebTheme, createComponentCSS } from '@aws-amplify/ui'; +import { + BaseComponentProps, + ElementType, + ForwardRefPrimitive, + Primitive, + PrimitiveProps, +} from '../../primitives/types'; +import { primitiveWithForwardRef } from '../../primitives/utils/primitiveWithForwardRef'; +import { BaseComponentTheme } from '@aws-amplify/ui'; +import { Style } from './Style'; + +interface BaseComponentStyleProps extends BaseComponentProps { + /** + * Provide a server generated nonce which matches your CSP `style-src` rule. + * This will be attached to the generated tag and add a + The answer depends on whether the code is rendered on the client or server side. + + Client side + - To prevent XSS inside of the tag, it will still be interpreted as CSS text by the browser. + - Therefore, there is not an XSS vulnerability on the client side. + + Server side + - When React code is rendered on the server side (e.g., NextJS), the code is sent to the browser as HTML text. + - Therefore, it *IS* possible to insert a closing tag and escape the CSS context, which opens an XSS vulnerability. + + Q: How are we mitigating the potential attack vector? + A: To fix this potential attack vector on the server side, we need to filter out any closing tags, + as this the only way to escape from the context of the browser interpreting the text as CSS. + We also need to catch cases where there is any kind of whitespace character , such as tabs, carriage returns, etc: + + Therefore, by only rendering CSS text which does not include a closing '' tag, + we ensure that the browser will correctly interpret all the text as CSS. + */ + if (cssText === undefined || /<\/style/i.test(cssText)) { + return null; + } + + return ( + tag and add a - The answer depends on whether the code is rendered on the client or server side. - - Client side - - To prevent XSS inside of the tag, it will still be interpreted as CSS text by the browser. - - Therefore, there is not an XSS vulnerability on the client side. - - Server side - - When React code is rendered on the server side (e.g., NextJS), the code is sent to the browser as HTML text. - - Therefore, it *IS* possible to insert a closing tag and escape the CSS context, which opens an XSS vulnerability. - - Q: How are we mitigating the potential attack vector? - A: To fix this potential attack vector on the server side, we need to filter out any closing tags, - as this the only way to escape from the context of the browser interpreting the text as CSS. - We also need to catch cases where there is any kind of whitespace character , such as tabs, carriage returns, etc: - - Therefore, by only rendering CSS text which does not include a closing '' tag, - we ensure that the browser will correctly interpret all the text as CSS. - */ - if (/<\/style/i.test(cssText)) { - return null; - } else { - return ( -