Basic Concepts

A brief introduction to glamorous

Motivation

Why does glamorous exist?

The Problem

You like CSS in JS, but you don't like having to create entire component functions just for styling purposes. You don't want to give a name to something that's purely style-related. And it's just kind of annoying to do the style-creating, className assigning, and props-forwarding song and dance.

For example, this is what you have to do with raw glamor (or aphrodite or similar for that matter):

const styles = glamor.css({
  fontSize: 20,
  textAlign: 'center',
})
function MyStyledDiv({className = '', ...rest}) {
  return (
    <div
      className={`${styles} ${className}`}
      {...rest}
    />
  )
}

This Solution

With glamorous, that example above looks as simple as this:

const MyStyledDiv = glamorous.div({
  fontSize: 20,
  textAlign: 'center',
})

In fact, it's even better, because there are a bunch of features that make composing these components together really nice!

Oh, and what if you didn't care to give MyStyledDiv a name? If you just want a div that's styled using glamor? You can do that too:

const { Div } = glamorous

function App() {
  return (
    <Div
      fontSize={20}
      textAlign="center"
    >
      Hello world!
    </Div>
  )
}

Try this out in your browser here!

So that's the basics of this solution... Let's get to the details!

Installation

This module is distributed via npm which is bundled with node and should be installed as one of your project's dependencies:

npm install --save glamorous

This also depends on react and glamor so you'll need those in your project as well (if you don't already have them):

npm install --save react glamor

NOTE: If you're using React v15.5 or greater, you'll also need to have prop-types installed: npm install --save prop-types

You can then use one of the module formats:

  • main: dist/glamorous.cjs.js - exports itself as a CommonJS module
  • global: dist/glamorous.umd.js and dist/glamorous.umd.min.js - exports itself as a umd module which is consumable in several environments, the most notable as a global.
  • jsnext:main and module: dist/glamorous.es.js - exports itself using the ES modules specification, you'll need to configure webpack to make use of this file do this using the resolve.mainFields property.

The most common use-case is consuming this module via CommonJS:

const glamorous = require('glamorous')
const {ThemeProvider} = glamorous
// etc.

If you're transpiling (and/or using the jsnext:main):

import glamorous, {ThemeProvider} from 'glamorous'

// you can also import specific Glamorous Components (see section below on "Built-in" components)
import {Div, H2} from 'glamorous'

// tags with the same name as built-in JavaScript objects are importable with a Tag suffix
// and tag names that contain dashes are transformed to CamelCase
import {MapTag, ColorProfile} from 'glamorous'

If you want to use the global:

<!-- Load dependencies -->
<script src="https://unpkg.com/react/dist/react.js"></script>
<script src="https://unpkg.com/prop-types/prop-types.js"></script>
<script src="https://unpkg.com/glamor/umd/index.js"></script>
<!-- load library -->
<script src="https://unpkg.com/glamorous/dist/glamorous.umd.js"></script>
<script>
// Use window.glamorous here...
const glamorous = window.glamorous
const {ThemeProvider} = glamorous
</script>

Getting Started

start using glamorous

Video Screenshot

Here is a basic example that shows you how to get started making component with css-in-js magic.

const { Div } = glamorous

function App() {
	return (
		<Div
			fontSize={20}
			textAlign="center"
		>
			Hello Glamorous!
		</Div>
	)
}

render(<App/>)
Hello Glamorous!

Core Concepts

glamorous

The glamorous function is the default export. It allows you to create glamorous components that render the styles to the component you give it. This is done by forwarding a className prop to the component you tell it to render. But before we get into how you wrap custom components, let's talk about the built-in DOM components.

built-in DOM component factories

For every DOM element, there is an associated glamorous component factory attached to the glamorous function. As above, you can access these factories like so: glamorous.div, glamorous.a, glamorous.article, etc.

const MyStyledSection = glamorous.section({ margin: 1 })

<MyStyledSection>content</MyStyledSection>
// rendered output: <section class="<glamor-generated-class>">content</section>
// styles applied: {margin: 1}

GlamorousComponent

The GlamorousComponent is what is returned from the glamorousComponentFactory. Its job is to get all the styles together, get a className (from glamor) and forward that on to your component.

built-in GlamorousComponents

Often you want to style something without actually giving it a name (because naming things is hard). So glamorous also exposes a pre-created GlamorousComponent for each DOM node type which makes this reasonable to do:

const { Div, Span, A, Img } = glamorous

function MyUserInterface({name, tagline, imageUrl, homepage, size}) {
  const nameSize = size
  const taglineSize = size * 0.5
  return (
    <Div display="flex" flexDirection="column" justifyContent="center">
      <A href={homepage} textDecoration="underline" color="#336479">
        <Img borderRadius="50%" height={180} src={imageUrl} />
        <Div fontSize={nameSize} fontWeight="bold">{name}</Div>
      </A>
      <Span fontSize={taglineSize} color="#767676">
        {tagline}
      </Span>
    </Div>
  )
}

Try this out in your browser here!

Having to name all of that stuff could be tedious, so having these pre-built components is handy. The other handy bit here is that the props are the styles for these components. Notice that glamorous can distinguish between props that are for styling and those that are have semantic meaning (like with the Img and A components which make use of src and href props).

The css prop can be used to provide styles as an object.

import glamorous, {withTheme} from 'glamorous'
const { Div, Span } = glamorous

const predefinedStyle = {
  color: '#767676',
  fontSize: 18,
}

const MyUserInterface = withTheme(function ({tagline, theme}) {
  return (
    <Div
      css={{
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'center',
        [theme.mq.tablet]: {
          flexDirection: 'row'
        }
      }}
     >
      <Span css={predefinedStyle}>
        {tagline}
      </Span>
    </Div>
  )
})

One other tip... This totally works:

<glamorous.Div color="blue">
  JSX is pretty wild!
</glamorous.Div>

Overriding component styles

The most common scenario for using props is to override the style of an existing component (generated by glamorous or not). That can be achieved by using the props className, css and theme or simply component composition with the glamorous() function.

If you're interested in knowing more about using the theme prop, see the Theming section instead for a more detailed explanation. In this section we'll explain how to use className, css and composition to override the styles of a component.

Let's see how that can be done in the examples below.

Try this out in your browser here!

We'll use this as our GlamorousComponent:

const MyStyledDiv = glamorous.div({margin: 1, fontSize: 1, padding: 1})
using className

For each className you provide, the GlamorousComponent will check to see whether it is a glamor generated className (can be from raw glamor or from glamorous, doesn't matter). If it is, it will get the original styles that were used to generate that className and merge those with the styles for the element that's rendered in a way that the provided className's styles win in the event of a conflict.

Any classNames that is not generated by glamor, will just be concatenated with the one that is.

const myCustomGlamorStyles = glamor.css({fontSize: 2})
<MyStyledDiv className={`${myCustomGlamorStyles} custom-class`} />
// styles applied:
// {margin: 1, fontSize: 2, padding: 1}
// as well as any styles custom-class applies
using css

This can be the same type as any of the styles provided (as in glamorous.div(...styles)). If specified, it will be merged with this component's styles and take highest priority over the component's predefined styles.

const myCustomGlamorStyles = glamor.css({fontSize: 2, padding: 2})
<MyStyledDiv
  className={`${myCustomGlamorStyles} custom-class`}
  css={{padding: 3}}
/>
// styles applied:
// {margin: 1, fontSize: 2, padding: 3}
// as well as any styles custom-class applies
using glamorous() composition

If we just want to extend the styles of an existing component it can be done by using the glamorous() function.

const MyComposedStyledDiv = glamorous(MyStyledDiv)({fontSize: 4, padding: 4})
<MyComposedStyledDiv />
// styles applied:
// {margin: 1, fontSize: 4, padding: 4}

In fact, the built-in DOM component factories provided are just an abstraction of this function, so glamorous.div could be written as glamorous('div') instead.

Dynamic Styles + Static Styles

One of the nice bits of glamorous is that it allows you to make a clear separation between your dynamic and static styles by forcing you to choose between an object literal and a function. Here's an example of having both dynamic and static styles:

const MyLink = glamorous.a(
	{
		color: 'blue',
		textDecoration: 'none',
	},
	({size = 'small'}) => ({
		fontSize: size === 'big' ? 24 : 16,
	})
	// you can continue to provide any number of arguments
	// and `glamor` will merge them. In the event of a
	// style conflict, the last one wins.
)

render(
	<div>
		<MyLink href="#">Default is small</MyLink>
		<br />
		<MyLink href="#" size="big">size="big"</MyLink>
	</div>
)

Try this out in your browser here!

Can use arrays to merge styles together

Animation

To do animation with glamorous, you can use regular CSS transitions for simple things, and for more advanced stuff, you can use keyframes via glamor's css.keyframes API.

// import * as glamor from 'glamor'

// Define the animation styles
const animationStyles = props => {
	const bounce = glamor.css.keyframes({
		'0%': { transform: `scale(1.01)` },
		'100%': { transform: `scale(0.99)` }
	})
	return {animation: `${bounce} 0.2s infinite ease-in-out alternate`}
}

// Define the element
const AnimatedDiv = glamorous.div(animationStyles)

render(
	<AnimatedDiv>
		Bounce.
	</AnimatedDiv>
)
Bounce.
CodeSandbox

glamorous-native

React Native

glamorous offers a version for React Native projects called glamorous-native.

npm install glamorous-native --save

You can learn more at the glamorous-native project.

Contributors:

kentcdodds's GitHub avatar