Switch
A control element that allows for a binary selection.
Usage
import { Switch, type SwitchProps } from '~/components/ui'
export const Demo = (props: SwitchProps) => {
return (
<Switch defaultChecked {...props}>
Label
</Switch>
)
}
Installation
npx @park-ui/cli components add switch
1
Styled Primitive
Copy the code snippet below into ~/components/ui/primitives/switch.tsx
'use client'
import type { Assign } from '@ark-ui/react'
import { Switch } from '@ark-ui/react/switch'
import { type SwitchRecipeVariantProps, switchRecipe } from 'styled-system/recipes'
import type { ComponentProps, HTMLStyledProps } from 'styled-system/types'
import { createStyleContext } from '~/lib/create-style-context'
const { withProvider, withContext } = createStyleContext(switchRecipe)
export type RootProviderProps = ComponentProps<typeof RootProvider>
export const RootProvider = withProvider<
HTMLLabelElement,
Assign<Assign<HTMLStyledProps<'label'>, Switch.RootProviderBaseProps>, SwitchRecipeVariantProps>
>(Switch.RootProvider, 'root')
export type RootProps = ComponentProps<typeof Root>
export const Root = withProvider<
HTMLLabelElement,
Assign<Assign<HTMLStyledProps<'label'>, Switch.RootBaseProps>, SwitchRecipeVariantProps>
>(Switch.Root, 'root')
export const Control = withContext<
HTMLSpanElement,
Assign<HTMLStyledProps<'span'>, Switch.ControlBaseProps>
>(Switch.Control, 'control')
export const Label = withContext<
HTMLSpanElement,
Assign<HTMLStyledProps<'span'>, Switch.LabelBaseProps>
>(Switch.Label, 'label')
export const Thumb = withContext<
HTMLSpanElement,
Assign<HTMLStyledProps<'span'>, Switch.ThumbBaseProps>
>(Switch.Thumb, 'thumb')
export {
SwitchContext as Context,
SwitchHiddenInput as HiddenInput,
} from '@ark-ui/react/switch'
import { type Assign, Switch } from '@ark-ui/solid'
import type { ComponentProps } from 'solid-js'
import { type SwitchRecipeVariantProps, switchRecipe } from 'styled-system/recipes'
import type { HTMLStyledProps } from 'styled-system/types'
import { createStyleContext } from '~/lib/create-style-context'
const { withProvider, withContext } = createStyleContext(switchRecipe)
export type RootProviderProps = ComponentProps<typeof RootProvider>
export const RootProvider = withProvider<
Assign<Assign<HTMLStyledProps<'label'>, Switch.RootProviderBaseProps>, SwitchRecipeVariantProps>
>(Switch.RootProvider, 'root')
export type RootProps = ComponentProps<typeof Root>
export const Root = withProvider<
Assign<Assign<HTMLStyledProps<'label'>, Switch.RootBaseProps>, SwitchRecipeVariantProps>
>(Switch.Root, 'root')
export const Control = withContext<Assign<HTMLStyledProps<'span'>, Switch.ControlBaseProps>>(
Switch.Control,
'control',
)
export const Label = withContext<Assign<HTMLStyledProps<'span'>, Switch.LabelBaseProps>>(
Switch.Label,
'label',
)
export const Thumb = withContext<Assign<HTMLStyledProps<'span'>, Switch.ThumbBaseProps>>(
Switch.Thumb,
'thumb',
)
export {
SwitchContext as Context,
SwitchHiddenInput as HiddenInput,
} from '@ark-ui/solid'
No snippet found
Extend ~/components/ui/primitives/index.ts
with the following line:
export * as Switch from './switch'
2
Add Composition
Copy the code snippet below into ~/components/ui/switch.tsx
import { forwardRef } from 'react'
import { Switch as ArkSwitch } from '~/components/ui/primitives'
export interface SwitchProps extends ArkSwitch.RootProps {}
export const Switch = forwardRef<HTMLLabelElement, SwitchProps>((props, ref) => {
const { children, ...rootProps } = props
return (
<ArkSwitch.Root ref={ref} {...rootProps}>
<ArkSwitch.Control>
<ArkSwitch.Thumb />
</ArkSwitch.Control>
{children && <ArkSwitch.Label>{children}</ArkSwitch.Label>}
<ArkSwitch.HiddenInput />
</ArkSwitch.Root>
)
})
Switch.displayName = 'Switch'
import { Show, children } from 'solid-js'
import { Switch as ArkSwitch } from '~/components/ui/primitives'
export interface SwitchProps extends ArkSwitch.RootProps {}
export const Switch = (props: SwitchProps) => {
const getChildren = children(() => props.children)
return (
<ArkSwitch.Root {...props}>
<ArkSwitch.Control>
<ArkSwitch.Thumb />
</ArkSwitch.Control>
<Show when={getChildren()}>
<ArkSwitch.Label>{getChildren()}</ArkSwitch.Label>
</Show>
<ArkSwitch.HiddenInput />
</ArkSwitch.Root>
)
}
Extend ~/components/ui/index.ts
with the following line:
export * from './primitives'
export { Switch, type SwitchProps } from './switch'
3
Integrate Recipe
If you're not using @park-ui/preset
, add the following recipe to yourpanda.config.ts
:
import { switchAnatomy } from '@ark-ui/anatomy'
import { defineSlotRecipe } from '@pandacss/dev'
export const switchRecipe = defineSlotRecipe({
className: 'switchRecipe',
jsx: ['Switch', /Switch\.+/],
slots: switchAnatomy.keys(),
base: {
root: {
alignItems: 'center',
colorPalette: 'accent',
display: 'flex',
position: 'relative',
},
control: {
alignItems: 'center',
background: 'bg.emphasized',
borderRadius: 'full',
cursor: 'pointer',
display: 'inline-flex',
flexShrink: '0',
transitionDuration: 'normal',
transitionProperty: 'background',
transitionTimingFunction: 'default',
_checked: {
background: 'colorPalette.default',
},
},
label: {
color: 'fg.default',
fontWeight: 'medium',
},
thumb: {
background: 'bg.default',
borderRadius: 'full',
boxShadow: 'xs',
transitionDuration: 'normal',
transitionProperty: 'transform, background',
transitionTimingFunction: 'default',
_checked: {
transform: 'translateX(100%)',
background: { _light: 'bg.default', _dark: 'colorPalette.fg' },
},
},
},
defaultVariants: {
size: 'md',
},
variants: {
size: {
sm: {
root: {
gap: '2',
},
control: {
width: '7',
p: '0.5',
},
thumb: {
width: '3',
height: '3',
},
label: {
textStyle: 'sm',
},
},
md: {
root: {
gap: '3',
},
control: {
width: '9',
p: '0.5',
},
thumb: {
width: '4',
height: '4',
},
label: {
textStyle: 'md',
},
},
lg: {
root: {
gap: '4',
},
control: {
width: '11',
p: '0.5',
},
thumb: {
width: '5',
height: '5',
},
label: {
textStyle: 'lg',
},
},
},
},
})