Advanced

Forwarding Ref

Use the withRef method to pass the ref down to the underlying DOM element. This uses React's forwardRef functionality behind the scenes. Then use the useRef hook to access its value.

import React, { useRef } from 'react';

const Div = styled
  .div()
  .withRef();

const Button = styled.button();

const Composition = () => {
  const divRef = useRef();

  const clickHandler = () => {
    console.log('divRef', divRef.current);
  };

  return (
    <>
      <Div ref={divRef} />
      <Button onClick={clickHandler}>
        click me!
      </Button>
    </>
  );
};

PropTypes

Built-in typechecking support for React propsTypes. Just chain the withProps method to an already defined Styled Component and pass the propTypes object as its only argument. This is the same as assigning the propTypes property on a Component.

import PropTypes from 'prop-types';

type ButtonColour =
  | 'blue'
  | 'blue'
  | 'purple';

type ButtonProps = {
  isDisabled?: boolean;
  colour?: ButtonColour;
};

const Button = styled
  .button<ButtonProps>({
    // base button styles

    [style.prop('isDisabled')]: {
      color: 'light grey',
      cursor: 'not-allowed'
    },

    [style.prop('colour')]: (colour: ButtonColour) => ({
      backgroundColor: colour,
      borderColour: colour
    })
  })
  .withProps({
    isDisabled: PropTypes.bool,
    colour: PropTypes.oneOf(['blue', 'green', 'purple'])
  });

Server Side Rendering

SSR is supported out of the box, no extra setup required. To get the CSS rendered (including their wrapping style tags), just import and invoke the getStyles method.

import express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { getStyles } from '@n3e/styled';

import App from 'path/to/App';

/**
 * @param {string} html
 * @param {string} sheets
 * @returns {string}
 */
const renderPage = (html, sheets) =>
  `<!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>App: served by express</title>
    ${sheets}
    <script defer src="path/to/script.js"></script>
  <head>
  <body>
    <div id="root">${html}</div>
  </body>
  </html>`;

const app = express();

app.use((_, res) => {
  // render the component to a string
  const html = renderToString(<App />);

  // get generated styles after component is rendered
  const sheets = getStyles();

  return res
    .status(200)
    .contentType('text/html')
    .send(renderPage(html, sheets));
});

app.listen('9000');

Experimental

Although Styled works with NextJS, please use with caution as these features have not been finalised.

First, create a component at the root directory, it can be called anything you like.

import { ServerStyles } from '@n3e/styled';

export default async function RootStyles() {
  return <ServerStyles />;
}

Then import the component created above and insert it as a child of the head tag.

import type { Metadata } from 'next';
import RootStyles from './RootStyles';

export const metadata: Metadata = {
  // meta data properties
};

type RootLayoutProps = Readonly<{
  children?: React.ReactNode;
}>;

export default async RootLayout RootStyles({
  children
}: RootLayoutProps) {
  return (
    <html land='en'>
      <head>
        <RootStyles />
      </head>
      <body>
        {children}
      </body>
    </html>
  );
}