Making CSS type safe.
Writing CSS with TypeStyle will be just as fluent as writing JavaScript with TypeScript.
There are quite a few css in js frameworks out there. This one is different:
- Provides great TypeScript developer experience (rad idea!).
- No custom AST transform or module loader support needed.
- Works with any framework (react, angular2, cyclejs, whatever, doesn't matter).
- Zero config. Just use.
- super small (~1k)
Use it like you would use CSS modules or CSS in general with webpack etc, but this time you get to use TypeScript / JavaScript!
Install
npm install typestyle --save
Use
/** Import */
import {style} from "typestyle";
/** convert a style object to a CSS class name */
const className = style({color: 'red'});
/** Use the class name in a framework of choice */
// e.g. React
const MyButton =
({onClick,children})
=> <button className={className} onClick={onClick}>
{children}
</button>
// or Angular2
@Component({
selector: 'my-component',
template: `<div class="${className}">Tada</div>`
})
export class MyComponent {}
Just get the styles as CSS at any point and render it in a style tag yourself. e.g.
/** Import */
import {style, css} from "typestyle";
/** convert a style object to a CSS class name */
const className = style({color: 'red'});
/** Render to CSS style tag */
const styleTag = `<style>${css()}</style>`
/** ^ send this as a part of your HTML response */
Pseudo States
&:hover
, &:active
, &:focus
, &:disabled
as you would expect e.g.
/** Import */
import {style} from "typestyle";
/** convert a style object to a CSS class name */
const className = style({
color: 'blue',
'&:hover': {
color: 'red'
}
});
Child selectors
&:first-child
, &:last-child
, &>*
etc work too e.g. use it to design a vertical layout:
/** Import */
import {style} from "typestyle";
/** Share constants in TS! */
const spacing = '5px';
/** style -> className :) */
const className = style({
'&>*': {
marginTop: spacing,
marginBottom: spacing
},
'&:first-child': {
marginTop: '0px',
}
'&:last-child': {
marginBottom: '0px',
}
});
Media Queries
const colorChangingClass = style({
backgroundColor: 'red',
'@media (min-width: 400px)': {
backgroundColor: 'pink'
}
})
Merge Objects
Pass as many style objects to style
and they merge just right.
const redMaker = {color:'red'};
const alwaysRedClass = style(redMaker);
const greyOnHoverClass = style(
redMaker,
{'&:hover':{color: 'grey'}}
);
Compose Classes You can easily compose class names using classes
const tallClass = style({height:'100px'});
const redClass = style({color:'red'});
/** Compose classes */
const tallRedClass = typestyle.classes(tallClass, redClass);
/** Even conditionally (any falsy parameters are ignored in the composed class name) */
const mightBeRed = typestyle.classes(tallClass, hasError && redClass);
Animations
Use keyframes
to define an animation and get the animation name
const colorAnimationName = typestyle.keyframes({
from: { color: 'red' },
to: { color: 'blue' }
})
const ooooClass = typestyle.style({
animationName: colorAnimationName,
animationDuration: '1s'
});
TypeScript Protip: namespace
/** Think of it like an inline stylesheet */
namespace MyStyles {
const color = 'red';
export const alwaysRedClass = style({color});
export const onlyRedOnHoverClass = style({'&:hover':{color});
}
/** Use e.g. with React */
const AlwaysRed = ({text}) => <div className={MyStyles.alwaysRedClass}>{text}</div>
const OnlyRedOnHover = ({text}) => <div className={MyStyles.onlyRedOnHoverClass}>{text}</div>
There are two kinds of fallbacks in CSS and both are supported:
- Same key multiple values: Just use an array for the value e.g. background colors
const fallBackBackground = style({
backgroundColor: [
/* The fallback */
'rgb(200, 54, 54)',
/** Graceful upgrade */
'rgba(200, 54, 54, 0.5)'
]
});
- Vendor prefixing: Anything that starts with
-
is not case renamed (i.e. nofooBar
=>foo-bar
) e.g. for smooth scroll:
const scroll = style({
'-webkit-overflow-scrolling': 'touch',
overflow: 'auto'
});
Protip: Big fan of flexbox? Use csx as it provides the necessary vendor prefixes so you don't need to worry about them.
Note: We don't do automatic vendor prefixing for a few reasons:
- Code bloat, runtime performance, you might want more control (we don't make choices that you might need to undo).
- Vendor prefixing has no future: https://webkit.org/blog/6131/updating-our-prefixing-policy/
This works very much in the same principle as CSS modules in that it takes a style object and generates a non conflicting generated class name.
- FreeStyle converts a JS style object to a CSS className using hashing
- We keep a single style sheet updated as you register styles.
- Provide
css.d.ts
to help with autocomplete + error reporting.
Really apprecate as many PRs for css.d.ts
CSSProperties
as you can throw at us 🌹
Same as FreeStyle which is super simple and does the absolute minimum but necessary, so faster than other CSS in JS frameworks for sure. We'd love to be told otherwise.