Select (TSelect)
VueJs reactive <select></select>
component with configurable classes, variants, and most common events. Friendly with utility-first frameworks like TailwindCSS..
Playground:
Basic example
<t-select
placeholder="Select an option"
:options="['Option A', 'Option B', 'Option C']"
variant="demo"
></t-select>
Props
Property | Type | Default value | Description |
---|---|---|---|
value (v-model ) | [Array, String, Number] | undefined | The value for the element |
id | String | undefined | HTML attribute |
autofocus | Boolean | undefined | HTML attribute |
disabled | Boolean | undefined | HTML attribute |
name | String | undefined | HTML attribute |
readonly | Boolean | undefined | HTML attribute |
required | Boolean | undefined | HTML attribute |
tabindex | [String, Number] | undefined | HTML attribute |
multiple | Boolean | undefined | HTML attribute |
placeholder | String | undefined | When set it prepend an empty option tag with the value as text and the option value of null |
options | [Array, Object] | undefined | The options of the select (see options format) |
textAttribute | String | undefined | Optional attribute from the option to use as the text (see define the value/text attributes) |
valueAttribute | String | undefined | Optional attribute to use as the value of the option tag (see define the value/text attributes) |
wrapped | Boolean | undefined | If set the input will be wrapped in a div within a svg icon (see wrap select) |
classes | [String, Object, Array] | 'form-select' | The default CSS classes |
fixedClasses | [String, Object, Array] | undefined | Fixed CSS classes that will be merged with the active set of classes |
variants | Object | undefined | The different variants of classes the component have |
variant | [String, Object] | undefined | The variant that will be used |
Options format
This component accepts the options
in different formats:
Array of objects
<!-- `value`, `text` attributes (Preferred) -->
<t-select :options="[
{ value: 1, text: 'Option 1' },
{ value: 2, text: 'Option 2' },
{ value: 3, text: 'Option 3', disabled: true }
]" />
<!-- `id` instead of `value` as attribute -->
<t-select :options="[
{ id: 1, text: 'Option 1' },
{ id: 2, text: 'Option 2' },
{ id: 3, text: 'Option 3', disabled: true }
]" />
<!-- `label` instead of `text` as attribute -->
<t-select :options="[
{ value: 1, label: 'Option 1' },
{ value: 2, label: 'Option 2' },
{ value: 3, label: 'Option 3', disabled: true }
]" />
<!-- All the examples above will render: -->
<select>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option disabled value="3">Option 3</option>
</select>
Objec t with value:text pairs
<t-select :options="{
A: 'Option A',
B: 'Option B',
C: 'Option C'
}" />
<!-- Will Render: -->
<select>
<option value="A">Option A</option>
<option value="B">Option B</option>
<option value="C">Option C</option>
</select>
Array of strings
<t-select :options="['Red', 'Blue', 'Yellow']" />
<!-- Will Render: -->
<select>
<option value="Red">Red</option>
<option value="Blue">Blue</option>
<option value="Yellow">Yellow</option>
</select>
Array of numbers
<t-select :options="[18, 19, 20]" />
<!-- Will Render: -->
<select>
<option value="18">18</option>
<option value="19">19</option>
<option value="20">20</option>
</select>
Define the value/text attributes
When your options come in a format that is not handled by the component you can define which attributes you want to use as the value
and the text
of every option tag.
Example:
Consider the following example where the options are an array of roles where the role
should be the value of the option and the nested name
inside the details
attribute should be the text:
<t-select
:options="[
{ role: 'root', details: { name: 'Root', expires: '2020-20-12' }, active: true },
{ role: 'admin', details: { name: 'Root', expires: '2020-20-12' }, active: true },
{ role: 'user', details: { name: 'Root', expires: '2020-20-12' }, active: true },
].map((option) => ({ value: option.role, text: option.details.name }))"
/>
<t-select
:options="[
{ role: 'root', details: { name: 'Root', expires: '2020-20-12' }, active: true },
{ role: 'admin', details: { name: 'Root', expires: '2020-20-12' }, active: true },
{ role: 'user', details: { name: 'Root', expires: '2020-20-12' }, active: true },
]"
value-attribute="role"
text-attribute="details.name"
/>
Wrap select
This component accepts the wrapped
setting (or prop) that when set it will wrap the select
tag in a div
and will add a sibling span
with an svg
icon. This can give you more flexibility to customize your component.
Remember that the component can set as "wrapped" when installed or by using the wrapped
prop (see wrap inputs for more info):
// When installed
const settings = {
TSelect: {
wrapped: true,
// classes, variants, etc...
},
// ...
}
Vue.use(VueTailwind, settings)
<!-- // Using the wrapped prop -->
<t-select wrapped />
A wrapped select will be rendered like this:
<div>
<select><!-- --></select>
<span>
<svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path clip-rule="evenodd" fill-rule="evenodd" d="M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z"></path>
</svg>
</span>
</div>
Classes for wrapped select
When the select is wrapped the classes, variants, etc need to be an object with the following properties:
Property | Description |
---|---|
wrapper | div that wraps the whole component |
input | select tag |
arrowWrapper | span that is a sibling of the select tag that is used to wrap the icon |
arrow | svg icon |
Example
const settings = {
TSelect: {
wrapped: true,
classes: {
wrapper: 'relative',
input: 'appearance-none bg-white focus:outline-none focus:shadow-outline border border-gray-300 rounded py-2 px-4 block w-full leading-normal',
arrowWrapper: 'pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700',
arrow: 'fill-current h-4 w-4',
}
// Variants and fixed classes in the same `object` format ...
},
// ...
}
Vue.use(VueTailwind, settings)
If you use the settings above the component will be rendered like this:
Customize the select icon
If you want to use your own HTML instead of the default SVG icon you can use the arrow
or arrowWrapper
slots, use the first one if you only want to override the SVG icon and the second one if you want to override the whole icon wrapper.
Both slots yield in the slot scope the current variant, the original classes the element has (from the theme), and the current value of the component in case you want to use those values inside the slot.
Example:
Let's say that for some reason you want to use an ascii down arrow instead of the default SVG icon, an angry emoji when it has an error
variant and just because you can show a potato emoji when the current value is >=2
, you know, a typical real-world use:
<t-select wrapped :options="[1,2,3]" variant="wrappedDemo">
<template slot="arrow" slot-scope="{ className, variant, value }">
<span v-if="variant==='error'" class="pr-2">😡</span>
<span v-else-if="value>=2" class="pr-2">🥔</span>
<span
v-else
:class="className"
>â–¼</span>
</template>
</t-select>
The example above will look like this: