Movatterモバイル変換


[0]ホーム

URL:


Advanced Usage

Theming

styled-components has full theming support by exporting a<ThemeProvider> wrapper component.This component provides a theme to all React components underneath itself via the context API. In the rendertree all styled-components will have access to the provided theme, even when they are multiple levels deep.

To illustrate this, let's create our Button component, but this time we'll pass some variables downas a theme.

Function themes

You can also pass a function for the theme prop. This function will receive the parent theme, that is fromanother<ThemeProvider> higher up the tree. This way themes themselves can be made contextual.

This example renders our above themed Button and a second one that uses a second ThemeProvider to invert thebackground and foreground colors. The functioninvertTheme receives the upper theme and creates a new one.

Getting the theme without styled components

viawithTheme higher-order component

If you ever need to use the current theme outside styled components (e.g. inside big components), you can usethewithTheme higher order component.

import{ withTheme}from'styled-components'classMyComponentextendsReact.Component{render(){console.log('Current theme: ',this.props.theme)// ...}}exportdefaultwithTheme(MyComponent)

viauseContext React hook
v4

You can also useuseContext to access the current theme outside of styled components when working with React Hooks.

import{ useContext}from'react'import{ThemeContext}from'styled-components'constMyComponent=()=>{const themeContext=useContext(ThemeContext)console.log('Current theme: ', themeContext)// ...}

viauseTheme custom hook
v5

You can also useuseTheme to access the current theme outside of styled components when working with React Hooks.

import{ useTheme}from'styled-components'constMyComponent=()=>{const theme=useTheme()console.log('Current theme: ', theme)// ...}

Thetheme prop

A theme can also be passed down to a component using thetheme prop.

This is useful to circumvent a missingThemeProvider or to override it.

Refs
v4

Passing aref prop to a styled component will give you one of two things depending on the styled target:

  • the underlying DOM node (if targeting a basic element, e.g.styled.div)
  • a React component instance (if targeting a custom component e.g. extended fromReact.Component)
Note

Using an older version of styled-components (below 4.0.0) or of React? Use theinnerRef prop instead.

Security

Since styled-components allows you to use arbitrary input as interpolations, you must becareful to sanitize that input. Using user input as styles can lead to any CSS being evaluated in the user'sbrowser that an attacker can place in your application.

This example shows how bad user input can even lead to API endpoints being called on a user'sbehalf.

// Oh no! The user has given us a bad URL!const userInput='/api/withdraw-funds'constArbitraryComponent= styled.div`  background: url(${userInput});  /* More styles here... */`

Be very careful! This is obviously a made-up example, but CSS injection can be unobvious andhave bad repercussions. Some IE versions even execute arbitrary JavaScript within url declarations.

There is an upcoming standard to sanitize CSS from JavaScript,CSS.escape. It's not very well supported across browsers yet, so we recommend using thepolyfill by Mathias Bynens in your app.

Existing CSS

There are a couple of implementation details that you should be aware of, if you choose to usestyled-components together with existing CSS.

styled-components generates an actual stylesheet with classes, and attaches those classes tothe DOM nodes of styled components via theclassName prop.It injects the generated stylesheet at the end of the head of the document during runtime.

Styling normal React components

If you use thestyled(MyComponent) notation andMyComponent does notrender the passed-inclassName prop, then no styles will be applied.To avoid this issue, make sure your component attaches the passed-inclassName to a DOM node:

classMyComponentextendsReact.Component{render(){// Attach the passed-in className to the DOM nodereturn<divclassName={this.props.className}/>}}

If you have pre-existing styles with a class, you can combine the global class with thepassed-in one:

classMyComponentextendsReact.Component{render(){// Attach the passed-in className to the DOM nodereturn<divclassName={`some-global-class${this.props.className}`}/>}}

Issues with specificity

If you apply a global class together with a styled component class, the result might not bewhat you're expecting. If a property is defined in both classes with the same specificity,the last one will win.

// MyComponent.jsconstMyComponent= styled.div`background-color: green;`;// my-component.css.red-bg{  background-color: red;}// For some reason this component still has a green background,// even though you're trying to override it with the "red-bg" class!<MyComponentclassName="red-bg"/>

In the above example the styled component class takes precedence over the global class, sincestyled-components injects its styles during runtime at the end of the<head> by default.Thus its styles win over other single classname selectors.

One solution is to bump up the specificity of the selectors in your stylesheet:

/* my-component.css */.red-bg.red-bg{background-color:red;}

Avoiding conflicts with third-party styles and scripts

If you deploy styled-components on a page you don't fully control, you may need to takeprecautions to ensure that your component styles don't conflict with those of the host page.

The most common problem is insufficient specificity. For example, consider a host page with thisstyle rule:

body.my-body button{padding:24px;}

Since the rule contains a classname and two tag names, it has higher specificity than the singleclassname selector generated by this styled component:

styled.button`  padding: 16px;`

There's no way to give your components complete immunity from the host page's styles, but you canat least boost the specificity of their style rules withbabel-plugin-styled-components-css-namespace,which allows you to specify a CSS namespace for all of your styled components. A good namespacewould be something like#my-widget, if all of your styled-components render in a containerwithid="my-widget", since ID selectors have more specificity than any number of classnames.

A rarer problem is conflicts between two instances of styled-components on the page. You can avoidthis by definingprocess.env.SC_ATTR in the code bundle with your styled-components instance.This value overrides the default<style> tag attribute,data-styled (data-styled-components in v3 and lower), allowingeach styled-components instance to recognize its own tags.

Tagged Template Literals

Tagged Template Literals are a new feature in ES6. They let you define custom string interpolation rules,which is how we're able to create styled components.

If you pass no interpolations, the first argument your function receives is an array with a string in it.

// These are equivalent:fn`some string here`;fn(['some string here']);

Once you pass interpolations, the array contains the passed string, split at the positions of the interpolations.The rest of the arguments will be the interpolations, in order.

const aVar='good';// These are equivalent:fn`this is a${aVar} day`;fn(['this is a ',' day'], aVar);

This is a bit cumbersome to work with, but it means that we can receive variables, functions, or mixins(css helper) in styled components and can flatten that into pure CSS.

Speaking of which, during flattening, styled-components ignores interpolations that evaluate toundefined,null,false, or an empty string (""), which means you're free to useshort-circuit evaluationto conditionally add CSS rules.

constTitle= styled.h1<{ $upsideDown?:boolean;}>`  /* Text centering won't break if props.$upsideDown is falsy */${props=> props.$upsideDown&&'transform: rotate(180deg);'}  text-align: center;`;

If you want to learn more about tagged template literals, check out Max Stoiber's article:The magic behind 💅🏾 styled-components

Server Side Rendering
v2+

styled-components supports concurrent server side rendering, with stylesheet rehydration.The basic idea is that everytime you render your app on the server, you can createaServerStyleSheet and add a provider to your React tree, that accepts stylesvia a context API.

This doesn't interfere with global styles, such askeyframes orcreateGlobalStyle andallows you to use styled-components with React DOM's various SSR APIs.

Tooling setup

In order to reliably perform server side rendering and have the client side bundle pick up without issues, you'll need to use ourbabel plugin. It prevents checksum mismatches by adding a deterministic ID to each styled component. Refer to thetooling documentation for more information.

For TypeScript users, our resident TS guru Igor Oleinikov put together aTypeScript plugin for the webpack ts-loader / awesome-typescript-loader toolchain that accomplishes some similar tasks.

If possible, we definitely recommend using the babel plugin though because it is updated the most frequently. It's now possible tocompile TypeScript using Babel, so it may be worth switching off TS loader and onto a pure Babel implementation to reap the ecosystem benefits.

Example

The basic API goes as follows:

import{ renderToString}from'react-dom/server';import{ServerStyleSheet}from'styled-components';const sheet=newServerStyleSheet();try{const html=renderToString(sheet.collectStyles(<YourApp/>));const styleTags= sheet.getStyleTags();// or sheet.getStyleElement();}catch(error){// handle errorconsole.error(error);}finally{  sheet.seal();}

ThecollectStyles method wraps your element in a provider. Optionally you can usetheStyleSheetManager provider directly, instead of this method. Just make sure not touse it on the client-side.

import{ renderToString}from'react-dom/server';import{ServerStyleSheet,StyleSheetManager}from'styled-components';const sheet=newServerStyleSheet();try{const html=renderToString(<StyleSheetManagersheet={sheet.instance}><YourApp/></StyleSheetManager>);const styleTags= sheet.getStyleTags();// or sheet.getStyleElement();}catch(error){// handle errorconsole.error(error);}finally{  sheet.seal();}

Thesheet.getStyleTags() returns a string of multiple<style> tags.You need to take this into account when adding the CSS string to your HTML output.

Alternatively theServerStyleSheet instance also has agetStyleElement() methodthat returns an array of React elements.

If rendering fails for any reason it's a good idea to usetry...catch...finally to ensure that thesheet object will always be available for garbage collection. Make suresheet.seal() is only called aftersheet.getStyleTags() orsheet.getStyleElement() have been called otherwise a different error will be thrown.

Note

sheet.getStyleTags() andsheet.getStyleElement() can only be called after your element is rendered. As a result, components fromsheet.getStyleElement() cannot be combined with<YourApp /> into a larger component.

Next.js

With Babel

Basically you need to add a custompages/_document.js (if you don't have one). Thencopy the logic for styled-components to inject the server side rendered styles into the<head>.

Refer toour example in the Next.js repo for an up-to-date usage example.

With SWC

Since version 12, Next.js uses a Rust compiler called SWC. If you're not using any babel plugin, you should refer tothis example instead.

On this version, youonly need to addstyledComponents: true, at the compiler options in thenext.config.js file and modify_document file withgetInitialProps as in thisexample to support SSR.

App directory

For routes defined in theapp/ directory, in Next.js v13+, you'll need to put a styled-components registry in one of your layout files, asdescribed in Next.js docs. Note that this depends on styled-components v6+. Also note that the'use client' directive is used - so while your page will be server-side rendered, styled-components will still appear in your client bundle.

Gatsby

Gatsby has an official plugin that enables server-side rendering for styled-components.

Refer tothe plugin's page for setup and usage instructions.

Streaming Rendering

styled-components offers a streaming API for use withReactDOMServer.renderToNodeStream(). There are two parts to a streaming implementation:

On the server:

ReactDOMServer.renderToNodeStream emits a "readable" stream that styled-components wraps. As whole chunks of HTML are pushed onto the stream, if any corresponding styles are ready to be rendered, a style block is prepended to React's HTML and forwarded on to the client browser.

import{ renderToNodeStream}from'react-dom/server';import styled,{ServerStyleSheet}from'styled-components';// if you're using express.js, you'd have access to the response object "res"// typically you'd want to write some preliminary HTML, since React doesn't handle thisres.write('<html><head><title>Test</title></head><body>');constHeading= styled.h1`  color: red;`;const sheet=newServerStyleSheet();const jsx= sheet.collectStyles(<Heading>HelloSSR!</Heading>);const stream= sheet.interleaveWithNodeStream(renderToNodeStream(jsx));// you'd then pipe the stream into the response object until it's donestream.pipe(res,{ end:false});// and finalize the response with closing HTMLstream.on('end',()=> res.end('</body></html>'));

On the client:

import{ hydrate}from'react-dom';hydrate();// your client-side react implementation

After client-side rehydration is complete, styled-components will take over as usual and inject any further dynamic styles after the relocated streaming ones.

Referring to other components

Note

This is aweb-specific API and youwon't be able to use it in react-native.

There are many ways to apply contextual overrides to a component's styling. That being said,it rarely is easy without rigging up a well-known targeting CSS selector paradigmand then making them accessible for use in interpolations.

styled-components solves this use case cleanly via the "component selector" pattern. Whenevera component is created or wrapped by thestyled() factory function, it is also assigned astable CSS class for use in targeting. This allows for extremely powerful composition patternswithout having to fuss around with naming and avoiding selector collisions.

A practical example: here, our Icon component defines its response to the parent Link being hovered:

We could have nested the color-changing rule within our Link component, but then we'd have toconsider both sets of rules to understand why Icon behaves as it does.

Caveat

This behaviour is only supported within the context ofStyled Components:attempting to mountB in the following example will fail because componentA is an instance ofReact.Component not a Styled Component.

classAextendsReact.Component{render(){return<div/>}}constB= styled.div`${A} {  }`

The error thrown -Cannot call a class as a function - occurs because thestyled component is attempting to call the component as an interpolation function.

However, wrappingA in astyled() factory makes it eligible for interpolation -- justmake sure the wrapped component passes alongclassName.

classAextendsReact.Component{render(){return<divclassName={this.props.className}/>}}constStyledA=styled(A)``constB= styled.div`${StyledA} {  }`

Style Objects

styled-components optionally supports writing CSS as JavaScript objects instead of strings. This is particularly useful when you have existing style objects and want to gradually move to styled-components.

Continue on the next page

API Reference


[8]ページ先頭

©2009-2025 Movatter.jp