1First–class type safety
Unwind was built with Typescript and great DX in mind providing you with confidence, auto-completion in you IDE and speed when developing UI.
import type { ClassNameProp } from '@unwind/class-name'
import { defineClassName, mergeClassNames, resolveClassName } from '@unwind/class-name'
import { memo, PropsWithChildren } from 'react'
const unwindClassName = defineClassName('unwind-input')
type FunkyButtonProps = PropsWithChildren<{
className?: ClassNameProp<typeof unwindClassName>;
}>
export const FunkyButton = memo<FunkyButtonProps>(({ className, children }) => {
return (
<button className={resolveClassName({}, mergeClassNames(unwindClassName, className))}>
{children}
</button>
)
})
FunkyButton.displayName = 'FunkyButton'
2Start small, go BIG
Never again get scared by the dreadful complexity of the nested components. Unwind has you covered.
String class names
import type { ClassNameProp } from '@unwind/class-name'
import { defineClassName, mergeClassNames, resolveClassName } from '@unwind/class-name'
import { memo, PropsWithChildren } from 'react'
const unwindClassName = defineClassName('unwind-input')
type FunkyButtonProps = PropsWithChildren<{
className?: ClassNameProp<typeof unwindClassName>;
}>
export const FunkyButton = memo<FunkyButtonProps>(({ className, children }) => {
return (
<button className={resolveClassName({}, mergeClassNames(unwindClassName, className))}>
{children}
</button>
)
})
FunkyButton.displayName = 'FunkyButton'
Array class names
import type { ClassNameProp } from '@unwind/class-name'
import { defineClassName, mergeClassNames, resolveClassName } from '@unwind/class-name'
import { memo, PropsWithChildren } from 'react'
const unwindClassName = defineClassName(['unwind-input', 'active'])
type FunkyButtonProps = PropsWithChildren<{
className?: ClassNameProp<typeof unwindClassName>;
}>
export const FunkyButton = memo<FunkyButtonProps>(({ className, children }) => {
return (
<button className={resolveClassName({}, mergeClassNames(unwindClassName, className))}>
{children}
</button>
)
})
FunkyButton.displayName = 'FunkyButton'
Callback class names
import { ClassNameProp, defineClassName, mergeClassNames, resolveClassName } from '@unwind/class-name';
import { memo, PropsWithChildren, useCallback, useState } from 'react';
const unwindClassName = defineClassName(
({ active }: { active: boolean }, previous) => [...previous, 'unwind-input', `active:${active}`],
)
type FunkyButtonProps = PropsWithChildren<{
className?: ClassNameProp<typeof unwindClassName>;
}>
export const FunkyButton = memo<FunkyButtonProps>(({ className, children }) => {
const [active, setActive] = useState(false)
const onClick = useCallback(() => { setActive(!active) }, [active])
return (
<button
className={resolveClassName({ active }, mergeClassNames(unwindClassName, className))}
onClick={onClick}
>
{children}
</button>
)
})
FunkyButton.displayName = 'FunkyButton'
Object class names
import { ClassNameProp, defineClassName, HOST_KEY, mergeClassNames, resolveClassName } from '@unwind/class-name';
import React, { memo, PropsWithChildren, ReactNode, useCallback, useState } from 'react';
type UnwindClassNameState = {
active: boolean
}
// $ property represents the host element (container) key
const unwindClassName = defineClassName({
[HOST_KEY]: ({ active }: UnwindClassNameState, previous) => [...previous, 'unwind-input', `active:${active}`],
icon: ({ active }: UnwindClassNameState, previous) => [...previous, 'unwind-input-icon', `active:${active}`],
})
type FunkyButtonProps = PropsWithChildren<{
className?: ClassNameProp<typeof unwindClassName>;
icon?: ReactNode
}>
export const FunkyButton = memo<FunkyButtonProps>(({ className, icon, children }) => {
const [active, setActive] = useState(false)
const onClick = useCallback(() => {
setActive(!active)
}, [active])
const styles = mergeClassNames(unwindClassName, className)
return (
<button
className={resolveClassName({ active }, styles)}
onClick={onClick}
>
{icon && <span className={resolveClassName({ active }, styles.icon)}>{icon}</span>}
{children}
</button>
)
})
FunkyButton.displayName = 'FunkyButton'
3Add, filter or redefine everything
With unwind components you are not tied to tied to adding more and more CSS classes to change the behavior or look of underlying DOM elements.
You can do whatever you need.
Add string to className
<FunkyButton className={'hello world'} icon="👋">
Click me!
</FunkyButton>
Add array of strings to className
<FunkyButton className={['hello', 'world']} icon="👋">
Click me!
</FunkyButton>
Filter previous className
values with callback
<FunkyButton
className={({ active }, previous) => [
// 👇 keep the 'active'/'not:active' <button> classes
...previous.filter(v => v.match(/active/)),
]}
icon="👋"
>
Click me!
</FunkyButton>
Replace className
with callback
<FunkyButton
// Omit the second 👇 parameter altogether to discard values from previous call
className={({ active }) => [
'border-0 text-white rounded-full px-3 py-1 flex gap-x-2 items-center',
active ? 'bg-blue-600' : 'bg-blue-500',
]}
icon="👋"
>
Click me!
</FunkyButton>
Replace className
with object
<FunkyButton
className={{
[HOST_KEY]: ({ active }) => [
'border-0 text-white rounded-full px-3 py-1 flex gap-x-2 items-center',
`${active ? 'bg-blue-600' : 'bg-blue-500'}`,
],
icon: ({ active }) => [
'border rounded-full w-7 h-7 -ml-2 inline-flex items-center justify-center',
active ? 'bg-white border-transparent' : 'border-white',
],
}}
icon="👋"
>
Click me!
</FunkyButton>