Skip to content
This repository was archived by the owner on Sep 11, 2021. It is now read-only.

Replace customization API #18

Merged
merged 6 commits into from
Jun 21, 2019
Merged

Replace customization API #18

merged 6 commits into from
Jun 21, 2019

Conversation

adamwathan
Copy link
Member

The old customization API tried to be as minimal as possible but in my own experience dogfooding it it fell apart extremely quickly.

This PR replaces that customization API with a new one that is basically just CSS, and as a result has no limits on flexibility.

Here's how it works, taken from the updated docs:


Customizing the default styles

You can customize the default styles applied by this plugin in the theme.customForms.default
section of your tailwind.config.js file.

Each form element can be customized under the input, textarea, select, multiselect, checkbox, and radio keys respectively.

// tailwind.config.js
module.exports = {
  theme: {
    customForms: theme => ({
      input: {
        borderRadius: theme('borderRadius.lg'),
        backgroundColor: theme('colors.gray.200'),
        '&:focus': {
          backgroundColor: theme('colors.white'),
        }
      },
      select: {
        borderRadius: theme('borderRadius.lg'),
        boxShadow: theme('boxShadow.default'),
      },
      checkbox: {
        width: theme('spacing.6'),
        height: theme('spacing.6'),
      }
    })
  },
  plugins: [
    require('@tailwindcss/custom-forms'),
  ]
}

The configuration format is the same CSS-in-JS syntax used to author Tailwind plugins, so you are free to customize or add any CSS properties you like.

See the default options used by the plugin for a complete reference of styles that are applied
out of the box.

Customizing the select, checkbox, and radio icons

Providing a carefully encoded SVG data URI to the backgroundImage property can be a bit cumbersome, so to make icon customization easier this plugin allows you to provide a normal unencoded SVG using a special icon property instead:

// tailwind.config.js
module.exports = {
  theme: {
    customForms: theme => ({
      select: {
        icon: '<svg fill="#e2e8f0" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"/></svg>',
      },
      checkbox: {
        icon: '<svg fill="#fff" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" ><path d="M0 11l2-2 5 5L18 3l2 2L7 18z"/></svg>'
      },
      radio: {
        icon: '<svg fill="#fff" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" r="3"/></svg>'
      },
    })
  },
  plugins: [
    require('@tailwindcss/custom-forms'),
  ]
}

You can also switch to a different icon for different states, like if you wanted to change the checkmark on hover:

// tailwind.config.js
module.exports = {
  theme: {
    customForms: theme => ({
      checkbox: {
        icon: '<svg fill="#1a202c" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" ><path d="M0 11l2-2 5 5L18 3l2 2L7 18z"/></svg>',
        '&:hover': {
          icon: '<svg fill="#4a5568" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" ><path d="M0 11l2-2 5 5L18 3l2 2L7 18z"/></svg>',
        }
      },
    })
  },
  plugins: [
    require('@tailwindcss/custom-forms'),
  ]
}

Checkbox and radio icons are automatically hidden unless the elements are :checked, so you don't need to include that pseudo-selector in your configuration when using the special icon property.

Customizing the icon color

If you are happy with the default icons and just want to customize the color, you can use the special iconColor property to customize the color without re-specifying the entire SVG:

// tailwind.config.js
module.exports = {
  theme: {
    customForms: theme => ({
      select: {
        iconColor: theme('colors.white'),
      },
      checkbox: {
        iconColor: theme('colors.indigo-700'),
      },
      radio: {
        iconColor: theme('colors.indigo-700'),
      },
    })
  },
  plugins: [
    require('@tailwindcss/custom-forms'),
  ]
}

You can also change the iconColor for different states:

// tailwind.config.js
module.exports = {
  theme: {
    customForms: theme => ({
      checkbox: {
        iconColor: theme('colors.gray.800'),
        '&:hover': {
          iconColor: theme('colors.gray.700'),
        }
      },
    })
  },
  plugins: [
    require('@tailwindcss/custom-forms'),
  ]
}

Just like with the icon property, you don't need to worry about including the :checked pseudo-selector for checkboxes and radios.

If you are using a custom icon and still want to use the iconColor property to make it easy to change the color without re-specifying your entire custom SVG, define your custom icon as a callback that receives the icon color:

// tailwind.config.js
module.exports = {
  theme: {
    customForms: theme => ({
      checkbox: {
        icon: iconColor => '<svg fill="${iconColor}" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" ><path d="M0 11l2-2 5 5L18 3l2 2L7 18z"/></svg>',
        iconColor: theme('colors.gray.800'),
        '&:hover': {
          iconColor: theme('colors.gray.700'),
        }
      },
    })
  },
  plugins: [
    require('@tailwindcss/custom-forms'),
  ]
}

Disabling a default style

Although we've tried to make the default styles as neutral as possible while still looking well-designed, sometimes one of the styles we're providing out-of-the-box might be too opinionated for your project and painful to simply override.

If you'd like to completely unset one of the default styles, explicitly set that property to undefined to prevent the plugin from including that property in the final CSS:

// tailwind.config.js
module.exports = {
  theme: {
    customForms: theme => ({
      input: {
      '&:focus': {
        boxShadow: undefined,
        borderColor: undefined,
      },
    })
  },
  plugins: [
    require('@tailwindcss/custom-forms'),
  ]
}

Configuring multiple elements at once

Often you'll want to set the same defaults for several different elements, and duplicating all of those styles can be a little verbose.

To specify styles for multiple elements at the same time, simply provide all of the elements you'd like to style as a comma-separated list:

// tailwind.config.js
module.exports = {
  theme: {
    customForms: theme => ({
      'input, textarea, multiselect, select': {
        borderRadius: theme('borderRadius.lg'),
      },
      'input, textarea, multiselect': {
        backgroundColor: theme('colors.gray.900'),
      },
      select: {
        backgroundColor: theme('colors.gray.600'),
      },
    })
  },
  plugins: [
    require('@tailwindcss/custom-forms'),
  ]
}

Adding modifier classes

You'll often need multiple form element styles in a single project, for example light form controls that are meant for light backgrounds, and dark form controls for dark backgrounds.

This plugin lets you create "modifiers" for your form classes by adding extra top-level keys in the theme.customForms section of your config file.

For example, this configuration adds a dark modifier:

// tailwind.config.js
module.exports = {
  theme: {
    customForms: theme => ({
      dark: {
        'input, textarea, multiselect, checkbox, radio': {
          backgroundColor: theme('colors.gray.900'),
        },
        select: {
          backgroundColor: theme('colors.gray.600'),
        },
      }
    })
  },
  plugins: [
    require('@tailwindcss/custom-forms'),
  ]
}

This generates extra classes like form-input-dark, form-textarea-dark, form-select-dark, etc.

It's important to note that modifiers are not automatically merged with the default styles and
are designed to be used with the multi-class modifier pattern.

That means you should always include the default class for an element when using a modifier:

<input class="form-input form-input-dark">

This makes it easy to create modifiers that serve different purposes that can still be composed.

For example, here we're configuring a dark color modifier, and a sm size modifier:

// tailwind.config.js
module.exports = {
  theme: {
    customForms: theme => ({
      dark: {
        'input, textarea, multiselect, checkbox, radio': {
          backgroundColor: theme('colors.gray.900'),
        },
        select: {
          backgroundColor: theme('colors.gray.600'),
        },
      },
      sm: {
        'input, textarea, multiselect, select': {
          fontSize: theme('fontSize.sm'),
          padding: `${theme('spacing.1')} ${theme('spacing.2')}`,
        },
        select: {
          paddingRight: `${theme('spacing.4')}`,
        },
        'checkbox, radio': {
          width: theme('spacing.3'),
          height: theme('spacing.3'),
        },
      }
    })
  },
  plugins: [
    require('@tailwindcss/custom-forms'),
  ]
}

By using the multi-class pattern, we can combine these modifiers in our HTML to produce form
elements that are both dark and small, without creating any new classes:

<input class="form-input form-input-dark form-input-sm">

It would be nice if I had more than one commit here but c'est la vie.
This commit history would have been a dumpster fire of me constantly
changing my mind and implementing, unimplemeneting, then reimplementing
the same things over and over anyways.
@adamwathan adamwathan merged commit 5d1a941 into master Jun 21, 2019
@LucaRed
Copy link

LucaRed commented May 1, 2020

Just a heads-up to anyone reading this pull request. The examples in this pull request don't work (at least with the latest Tailwind version).

The correct way to use the customization API is by wrapping everything in a default key as you can see on the documentation page:

// tailwind.config.js
module.exports = {
  theme: {
    customForms: theme => ({
      // ---- This one: ----
      default: {
        input: {
          borderRadius: theme('borderRadius.lg'),
          backgroundColor: theme('colors.gray.200'),
          '&:focus': {
            backgroundColor: theme('colors.white'),
          }
        },
        select: {
          borderRadius: theme('borderRadius.lg'),
          boxShadow: theme('boxShadow.default'),
        },
        checkbox: {
          width: theme('spacing.6'),
          height: theme('spacing.6'),
        },
      },
    })
  },
  plugins: [
    require('@tailwindcss/custom-forms'),
  ]
}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants