csscomp v1.10.5
Installation
npm install csscomp
Theming
Start by creating a theme for your application and define your design system in here. The theme you define will be merged with the default theme which comes with a set of default values for the colors
, space
, radii
, durations
and breakpoints
properties. Read more about how this works below.
import { lighten, darken } from 'csscomp'
const Theme = {
breakpoints: ['320px', '480px', '768px', '1024px', '1200px'],
fonts: {
base: '"Noto Sans", sans-serif',
title: '"Noto Sans", sans-serif',
code: '"Fira Code", sans-serif',
},
fontSizes: {
xs: '0.75em',
s: '0.9em',
m: '1em',
l: '1.1em'
},
colors: {
white: darken('white', 5),
black: lighten('black', 5),
primary: 'springgreen',
primaryLight: lighten('springgreen', 10),
primaryDark: darken('springgreen', 10),
secondary: darken('plum', 10),
secondaryLight: lighten('plum', 0),
secondaryDark: darken('plum', 10)
},
space: {
1: '0.25rem',
2: '0.5rem',
3: '0.75rem',
4: '1rem',
5: '1.25rem',
6: '1.5rem',
7: '1.75rem',
8: '2rem',
9: '2.25rem',
10: '2.5rem',
11: '2.75rem',
12: '3rem',
13: '3.25rem',
14: '3.5rem',
15: '3.75rem',
16: '4rem',
17: '4.25rem',
18: '4.5rem',
19: '4.75rem',
20: '5rem'
},
borders: {
main: '1px solid',
thick: '2px solid',
},
radii: {
1: '0.1rem',
2: '0.2rem',
3: '0.3rem',
4: '0.4rem',
5: '0.5rem',
6: '0.6rem',
7: '0.7rem',
8: '0.8rem',
},
durations: {
1: '0.25s',
2: '0.5s',
3: '0.75s',
4: '1s',
5: '1.25s',
6: '1.5s',
7: '1.75s',
8: '2s',
}
}
- breakpoints are used to create responsive styles together with array values, each value in the array will be defined in a media query based on the defined
breakpoints
, with exception to the first item to keep a mobile first approach. The default theme provides the values shown in the example above - fonts affects the
fontFamily
property. The default theme doesn't provide any values for this property. - fontSizes affects the
fontSize
property. The default theme doesn't provide any values for this property. - colors affects
color
,backgroundColor
,borderColor
etc. The default theme only comes with agrey
property which is a scale of greytones from0
to100
, accessible like'grey.25'
or'grey[25]'
. - spacings affects
left
,right
,top
,bottom
,margin
,padding
etc. The default theme provides an 8pt grid system (divided by half) with rem values to be responsive to the rootfontSize
. The values are accessible by passing numbers like{ padding: 4 }
. - sizes affects
width
,height
,size
etc. The default theme doesn't provide any values for this property. - borders affects only the
border
property. The default theme provides the values shown in the example above. - radii affects only the
borderRadius
property. The default theme provides the values shown in the example above - durations affects
transition
,animation
etc. The default theme provides the values shown in the example above
After defining your theme wrap your application in a <CSSProvider />
and pass your theme to it.
import { CSSProvider } from 'csscomp'
import { Theme } from './theme'
export default function App () {
return (
<CSSProvider theme={Theme}>
...
</CSSProvider>
)
}
Creating Components
Create components by calling a method matching the name of the element you want to create, pass styles to it in object format, or use the callback function to interact with props. These components support some pretty cool features under the hood.
- Property abbreviations are supported
- Theme variables are accessible by passing keys as string values
- Responsive styles are defined by passing arrays of values
- Color manipulation can be done by passing strings that follow a certain pattern
Use plain objects:
import { comp } from 'csscomp'
export const Box = comp.div({})
export const Container = comp.div({
d: 'flex',
w: '100%',
maw: ['800px', '1000px', '1200px', '1400px'],
px: 6,
})
export const Section = comp.div({
d: 'flex',
bgc: 'white',
py: [4, 8, 12, 16],
})
export const Button = comp.button({
bgc: 'primary',
c: 'white',
p: 4,
cur: 'pointer',
trs: 'all .4s ease',
'&:hover': {
bgc: 'primaryDark',
}
})
export const Input = comp.input({
bgc: 'white',
bd: 'main',
bdc: 'primary',
px: 5,
py: 2,
'&:focus': {
bd: 'thick',
bdc: 'primaryDark',
}
})
Use functions when interacting with props:
import { comp } from 'csscomp'
export const Spacer = comp.div<{ gutter?: number; direction?: 'column' | 'row' }>(
({ gutter = 4, direction = 'column' }) => ({
d: 'flex',
fxd: direction,
...(direction === 'column' ? {
jc: 'center'
} : {
ai: 'center'
}),
'> :not(:last-child)': {
...(direction === 'column' ? {
mb: gutter
} : {
mr: gutter
})
}
})
)
export const Checkbox = comp.div<{ checked?: boolean }>(
({ checked }) => ({
pos: 'relative',
d: 'flex',
ai: 'center',
jc: 'center',
size: '1rem',
bd: 'main',
bdc: 'primary',
bdrs: 2,
cur: 'pointer',
'&:after': {
cont: "''",
pos: 'absolute',
size: '50%',
bgc: checked ? 'primary' : 'transparent',
bdrs: 1
}
})
)
Use functions when you need to construct a value with the theme that isn't resolved automatically yet:
import { comp, darken } from 'csscomp'
export const ButtonCta = comp.button(({ theme }) => ({
bgi: `radial-gradient(
${darken(theme.colors.primary, 5)} 25%,
${darken(theme.colors.primary, 10)} 100%
)`,
bs: `0 0 10px 0 ${theme.colors.grey[88]}`,
c: 'white',
p: 5,
cur: 'pointer',
}))
Using Components
Components are exposed with a css
prop for inline styling, this prop works the same way as you define your components. You can also change the element type of any component with the as
prop.
Here is an example of a register form component built with the components defined in the previous section.
import { useState } from 'react'
import {
Box,
Spacer,
Checkbox,
Input,
Button
} from './components'
export const Register = () => {
const [registerData, setRegisterData] = useState({})
const updateRegisterData = (event) => {
setRegisterData({ ...registerData, [event.target.name]: event.target.value })
}
const register = () => {
// TODO: submit form
}
return (
<Box
as='form'
onSubmit={register}
css={{
w: '100%',
p: 5,
maw: '640px',
bgc: 'white',
bdrs: 4,
}}
>
<Spacer>
<Spacer gutter={2}>
<p>Username</p>
<Input type='text' name='username' onChange={updateRegisterData} />
</Spacer>
<Spacer gutter={2}>
<p>Email</p>
<Input type='text' name='email' onChange={updateRegisterData} />
</Spacer>
<Spacer gutter={2}>
<p>Password</p>
<Input type='password' name='password' onChange={updateRegisterData} />
</Spacer>
<Spacer
as='label'
gutter={2}
direction='row'
css={{
d: 'flex',
ai: 'center',
cur: 'pointer'
}}
>
<Box
as='input'
type='checkbox'
name='stayUpdated'
onChange={updateRegisterData}
css={{
d: 'none'
}}
/>
<Checkbox checked={new Boolean(formData.stayUpdated)} />
<p>Stay updated</p>
</Spacer>
<Button type='submit'>Submit</Button>
</Spacer>
</Box>
)
Extending components
Components are extendable, just wrap an existing component in the comp
constructor and use the return function to add more styling to the extended component.
import { comp } from 'csscomp'
import { Section, Button, Checkbox } from './components'
export const SectionHighlight = comp(Section)({
bgc: 'primary',
c: 'white',
jc: 'center',
py: [8, 16, 24, 32],
})
export const ButtonSecondary = comp(Button)({
bgc: 'secondary',
'&:hover': {
bgc: 'secondaryDark',
}
})
export const ButtonOutline = comp(Button)({
bgc: 'transparent',
c: 'primary',
bd: 'main',
bdc: 'primary',
'&:hover': {
bgc: 'transparent',
c: 'primaryDark',
bdc: 'primaryDark',
}
})
export const CheckboxSecondary = comp(Checkbox)(({ checked }) => ({
bdc: 'secondary',
'&:after': {
bgc: checked ? 'secondary' : 'transparent',
}
}))
Global styling
You can create global stylesheet components with the css
constructor. Which has the same capabilities as the component constructor.
import { CSSProvider, css } from 'csscomp'
import { Theme } from './theme'
export const RootStyle = css<{ rootFontSizes: string[] }>(
({ rootFontSizes }) => ({
'*': {
boxs: 'border-box'
},
':root': {
ff: 'base',
fs: rootFontSizes || '16px',
bgc: 'black',
scrollBehavior: 'smooth',
'-webkit-font-smoothing': 'antialiased',
'-moz-osx-font-smoothing': 'grayscale',
}
})
)
const App = () => {
return (
<CSSProvider theme={Theme}>
<RootStyle rootFontSizes={['14px', '15px', '16px']} />
...
</CSSProvider>
)
}
Keyframes
You can create keyframes
definitions to use in animations. The keyframes helper injects the definition into the page and returns a generated ID which you can use to set the animationName
property.
import { comp, keyframes } from 'csscomp'
const Spin = keyframes({
'0%': { tf: 'rotate(0deg)' },
'100%': { tf: 'rotate(360deg)' }
})
export const Spinner = comp.div({
size: '5rem',
bd: '.5rem solid',
bdc: 'primary',
bdbc: 'transparent',
bdr: '100%',
anim: `${Spin} 1s linear infinite`,
})
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago