joe-bell / cva

Class Variance Authority
https://cva.style
Apache License 2.0
5.78k stars 110 forks source link

Feature Request: Pass function as variant definition that gets `options` as argument #242

Closed ivosabev closed 11 months ago

ivosabev commented 11 months ago

It would be great if the variant definitions could also take a function as in the following example, where we have two type of buttons - with solid background and outline background, but we also want to specify which color the button to use separately.

const buttonVariants = cva('inline-flex', {
  defaultVariants: {
    appearance: 'solid',
    color: 'default',
  },
  variants: {
    appearance: {
      outline: ({color}: any) => `border-${color}-500`,
      solid: ({color}: any) => `bg-${color}-500`,
    },
    color: {
      default: '',
    },
  },
});

<Button appearance="solid" color="orange">Solid Orange</Button>
<Button appearance="outline" color="blue">Outline Blue</Button>

It is a naive example, but I hope it gets the point.

joe-bell commented 11 months ago

Sadly this won't work as you expect :(

https://github.com/joe-bell/cva/discussions/218

ivosabev commented 11 months ago

I am moving the discussion back here, because I think my request is different than passing arbitrary values.

My emphasis is on the ability of values to be not only string, but also functions. So based on the Tailwind docs, to avoid the dynamic classes you just have to write them in full.

function borderColor(color) {
  switch (color) {
    case 'orange':
      return 'border-orange-500';
    default:
      return 'border-gray-200';
  }
}

function bgColor(color) {
  switch (color) {
    case 'orange':
      return 'bg-orange-500';
    default:
      return 'bg-gray-200';
  }
}

const buttonVariants = cva('inline-flex', {
  defaultVariants: {
    appearance: 'solid',
    color: 'default',
  },
  variants: {
    appearance: {
      outline: ({color}: any) => borderColor(color),
      solid: ({color}: any) => bgColor(color),
    },
    color: {
      default: '',
    },
  },
});

<Button appearance="solid" color="orange">Solid Orange</Button>
<Button appearance="outline" color="blue">Outline Blue</Button>