Select

Dropdown selection of a list of choices.

NOTE

Please be sure to read the Basic concepts part of the documentation first.

Overview

The role of the select is to offer the user a choice between a limited set of options. You have three ways of assigning these options:

  • via the choices prop,
  • by creating bt-form-select-choice components in the appropriate slots,
  • by requesting a remote server.

TIP

You can combine all of these ways, we'll see that later in the documentation.

The choices can be any type of data. They are normalized by the component to be manageable. You have a say in this normalization step that'll see later on.


When you select an item, a copy is made and stored in the list of selected choices.

NOTE

It's important to note that the selected choices are not required to be part of the list of available choices. The two are uncorrelated.

You can totally assign a value to the select that is not part of the dropdown.

You can see why this is important in the remote part of the documentation.

States

Here a demo that illustrates the different states a select can take:

    TIP

    By default, errors are "floating" (meaning they show as a popover), you can make them show under the field by setting floating-errors to false.

    But, the setting is ignored if the control is inside an addon of another component. In this case the errors will always be floating.

    Choices creation

    Here we'll look at the different ways you can add choices.

    From prop

    The choices prop expects an array of items. The array can contain any value you want and can change at any time.


      From slots

      Because you can combine the different ways of defining available choices, you have multiple slots at your disposal to control where the choices will go in the dropdown:

      • choices-before: these choices will always be first in the dropdown, before any remote choice or choice set via the choices prop,
      • choices: these choices will appear after any remote choice or choice set via the choices prop.
      • choices-after: these choices will always appear last.

        WARNING

        Please beware of always putting your choices in one of these slots. DO NOT put them in the default slot:

        <!-- BAD, the default slot is for the label. -->
        <bt-form-select>
            <bt-form-select-choice>A</bt-form-select-choice>
            <bt-form-select-choice>B</bt-form-select-choice>
        </bt-form-select>
        

        Do this instead:

        <!-- GOOD, the choices will appear in the dropdown. -->
        <bt-form-select>
            Hey, I'm the label!
            <template #choices>
                <bt-form-select-choice>A</bt-form-select-choice>
                <bt-form-select-choice>B</bt-form-select-choice>
            </template>
        </bt-form-select>
        

        Each bt-form-select-choice can take the following props:

        Option Description Default
        The value to assign to the control when the choice is selected. If undefined, the text of the slot is used. undefined
        The text to show in selection resume of the select. If null, the text of the slot is used. null
        To force the item to be disabled. undefined
        To force the item to be selected on initialization. Only works if the control has no value. undefined

        Here's a demo that illustrates the usage of these props:


          From server

          You can also load your choices from a remote location.

          The select component is fully integrated with the HttpService and ApiService of Banquette. If you're not familiar with them, I encourage you to look it up first, as there are many useful concepts to know about.

          Here's a basic select with remote choices:


            Using a model:

            A remote choice can be transformed into a Model automatically if you set the remote-model prop:

            <bt-form-select remote-url="..." remote-model="Country">[...]</bt-form-select>
            

            The server's response will be automagically converted into an array of Country object using the TransformService. Here's an example:


              Using a global endpoint:

              You can also use an Endpoint instead of an url:

              import { ApiEndpointStorageService } from "@banquette/api";
              import { Injector } from "@banquette/dependency-injection";
              import { HttpMethod } from "@banquette/http";
              
              Injector.Get(ApiEndpointStorageService).registerEndpoint(
                  'get_users',
                  '/users/{type}',
                  HttpMethod.GET,
                  {type: '*'}
              );
              
              <bt-form-select remote-endpoint="get_users" :remote-url-params="{type: 'admin'}">
                  Choose an administrator
              </bt-form-select>
              

              Using a model's endpoint:

              import { Endpoint } from "@banquette/api";
              
              @Alias('Country')
              @Endpoint('get_all', '/countries')
              class Country {
                  @Api() public name!: string;
                  @Api() public code!: string;
              }
              
              
              <bt-form-select remote-endpoint="get_all" remote-model="Country">
                  Choose a country
              </bt-form-select>
              

              TIP

              If you're not familiar with these concepts, please check out the following docs:

              Choices grouping

              You can group your choices in separate sections for better readability:

                Choices normalization

                No matter how the choices are given to the select component, they always go through a normalization phase, that converts them into a Choice object that is used internally.

                For each choice, the component needs to figure out the following data from the input:

                • what's the label?
                • what's the identifier?
                • what's the value?
                • what's the group?
                • is it disabled?
                • is it selected?

                For each of these questions, the answer will depend on the input and the configuration.


                1) What's the label?

                • If the prop choices-label is a function, it will always be called to get the label.
                • Else if the input is a , it is used as label.
                • Else if the input is an object, the prop choices-label is expected to contain the name of the attribute to get the label from.
                <!-- Tell the select that the "name" attribute should be used as label. -->
                <bt-form-select choices-label="name" :choices="[obj1, obj2]"></bt-form-select>
                
                <!-- OR -->
                
                <!-- Tell the select to execute a function for each item, that will return the label. -->
                <bt-form-select :choices-label="(o) => o.name" :choices="[obj1, obj2]"></bt-form-select>
                
                <!-- ALSO -->
                
                <!-- "choices-label" can contain replaceable segments. -->
                <!-- Here "{fullName}" and "{adherentId}" will be replaced by the value in each object. -->
                <bt-form-select choices-label="{fullName} (n°{adherentId})" :choices="[userObj1, userObj2]"></bt-form-select>
                

                NOTE

                The label is used in the dropdown (if the choice is not defined in a slot) and in the selection resume. A label is always a simple string, it cannot contain HTML nor components.


                2) What's the identifier?

                • If the prop choices-identifier is a function, it will always be called to get the identifier.
                • Else if the input is a , it is used as identifier.
                • Otherwise, choices-identifier is expected to contain the name of the attribute to get the identifier from.
                <!-- Tell the select that the "id" attribute should be used as identifier. -->
                <bt-form-select choices-identifier="id" :choices="[obj1, obj2]"></bt-form-select>
                
                <!-- OR -->
                
                <!-- Tell the select to execute a function for each item, that will return the identifier. -->
                <bt-form-select :choices-identifier="(o) => o.id" :choices="[obj1, obj2]"></bt-form-select>
                

                WARNING

                The identifier must be unique between the whole list of choices (even from different sources). Items with duplicate identifier will be ignored and a warning will show in the console.

                WARNING

                Also, the identifier is necessarily a

                (excluding undefined).


                3) What's the value?

                • If the prop choices-value is a function, it will always be called to get the value.
                • Else if the input is a OR if choices-value is not defined, the input is used as value.
                • Else, choices-value is expected to contain the name of the attribute to get the value from.
                <!-- Tell the select that the "id" attribute should be used as value. -->
                <bt-form-select choices-value="id" :choices="[obj1, obj2]"></bt-form-select>
                
                <!-- OR -->
                
                <!-- Tell the select to execute a function for each item, that will return the value. -->
                <bt-form-select :choices-label="(o) => o.id" :choices="[obj1, obj2]"></bt-form-select>
                
                <!-- OR -->
                
                <!-- The input is used as value, as is, no matter its type. -->
                <bt-form-select :choices="[obj1, obj2]"></bt-form-select>
                

                4) What's the group?

                • If the prop choices-group is a function, it will always be called to get the group name.
                • Else if the prop choices-group is a string AND if the input is an object, it is expected to be the name of the attribute that holds the name of the group in the object.
                • Otherwise, the item will not be part of a group.
                <!-- Tell the select that the "category" attribute should be used as group. -->
                <bt-form-select choices-group="category" :choices="[obj1, obj2]"></bt-form-select>
                
                <!-- OR -->
                
                <!-- Tell the select to execute a function for each item, that will return the group. -->
                <bt-form-select :choices-group="(o) => o.group" :choices="[obj1, obj2]"></bt-form-select>
                

                5) Is it disabled?

                • If the prop choices-disabled is a function, it will always be called to get a boolean.
                • Else if the prop choices-disabled is a string AND if the input is an object, it is expected to be the name of the attribute that holds a boolean answering the question.
                • Otherwise, the item will not be disabled.
                <!-- Tell the select that the "disabled" attribute should -->
                <!-- be used to know if the choice is disabled. -->
                <bt-form-select choices-disabled="disabled" :choices="[obj1, obj2]"></bt-form-select>
                
                <!-- OR -->
                
                <!-- Tell the select to execute a function for each item, that will return a boolean. -->
                <bt-form-select :choices-disabled="(o) => !o.name" :choices="[obj1, obj2]"></bt-form-select>
                

                6) Is it selected?

                To know if an item should be selected, the select will look at the current selection (because remember, the selection is uncorrelated to the choices).

                If a selected item has the same id of the item being normalized, it will be selected automatically.

                This means that the selection can precede the choices (very important for remote choices).

                Multiple selection

                You can allow multiple values to be selected by setting the multiple prop to true:

                  You can constrain the select height to prevent it from growing when the number of items selected doesn't fit via the lock-height prop:

                    Clearable

                    You can allow the user to clear the value of the select via the clearable prop:

                      To enable filtering, use the seach-type prop. It can take the following values:

                      • none: the search is disabled (default value),
                      • local: filters the local list of choices,
                      • remote: no choices are visible in the dropdown until the user searches something. At which point a request is made to fetch the corresponding choices.

                      Local search:

                      Below an example of a local search:

                        NOTE

                        Please note that the search type local also works for remote choices. In the example above the choices are fetched form a remote server and the search type is local.

                        A local search simply means it is performed on the local list of choices.


                        Remote search:

                        When the search type is set to remote, the choices are not fetched until the user searches something. This is intended for large data sets.

                        You have two more parameters that come with it:

                        • search-remote-param-name (default: search): the name of the parameter that holds the search text to include in the ajax request. You can set an array, in which case each item of the array will create a parameter that contains the search text.
                        • search-min-length *(default: 0): minimum number of characters in the search before a request is sent.

                        Below an example of a remote search:

                          Allow creation

                          You can allow the user to add new choices with allow-creation:

                            Debug

                            If you add the debug attribute to the component, a little icon shows on the right, allowing you to inspect the whole viewData object exposed by the component.

                            If you don't know what the viewData object is, please refer to this part of the documentation.

                              Props

                              Method Description Default
                              Bidirectional binding for the value of the control. undefined
                              The original value given by the end-user through the html element. undefined
                              The label of the field. Overridden by the default slot. null
                              A placeholder value to show when there is no value selected. null
                              A help text to show to the user. Overridden by the help slot. null
                              If true the label will float above the control and act as a placeholder is there is none. true
                              If true the errors will appear as an icon on the right side of the input that shows a popover.
                              This value is overridden to true internally if the control is in a group to preserve layout integrity.
                              true
                              If true the help text will appear as an icon on the right side of the input that shows a popover.
                              This value is overridden to true internally if the control is in a group to preserve layout integrity.
                              false
                              If true, a little asterisk extra is shown, indicating to the user that the field is mandatory. false
                              For external control of the disabled state of the control. false
                              For external control of the busy state of the control. false
                              If true, show the debug overlay. false
                              HTML tab index (for keyboard navigation). 0
                              If true, the control will try to gain focus when mounted. false
                              Array of elements to use as choices.
                              They are cumulative with other sources (like the choices slot or a remote source).
                              null
                              Define how to resolve the choice's label. See Nodes normalization for detail. 'label'
                              Define how to resolve the choice's identifier. See Nodes normalization for detail. 'id'
                              Define how to resolve the choice's value. See Nodes normalization for detail. null
                              Define how to resolve the choice's disable state. See Nodes normalization for detail. 'disabled'
                              Define how to resolve the choice's group name. See Nodes normalization for detail. 'group'
                              If true the select allow for multiple values. false
                              If true, the height of the select will not grow when multiple choices are selected. false
                              If true, the user can enter custom values using the input, they will be added to the selected values even if not available in the list of choices. false
                              If true, the user can clear the value of the select. false
                              If true: the dropdown is always closed when a selection is made.
                              If false: the dropdown is never closed when a selection is made.
                              If auto: the dropdown is only closed when the select is not multiple.
                              'auto'
                              An optional model identifier. If defined the choices will be transformed into an entity of the model. null
                              A raw url to call to get available choices. null
                              Name of the endpoint to call to get the choices. null
                              The HTTP method to use when performing the request. 'GET'
                              Parameters to add to the url. If a variable with the same name is found in the url (surrounded by { }), it will replace it. Otherwise, it will be added to the query string (after ?). {}
                              Additional headers to add to the request. {}
                              Different strategies to search on the set of choices.
                              • none: the search is disabled.
                              • local: when the dropdown is opened, the selected value becomes a search input. Filters on the local set of choices.
                              • remote: no results are visible in the dropdown until the user searches something. At which point a request is made to fetch the corresponding choices.
                              'none'
                              Name of the parameter to add to the search request. If an array is given, a parameter with the value of the search will be created for each of them.
                              Only applicable if search-type is remote.
                              'search'
                              Minimum length of the search string before a search is performed. 0
                              Target to teleport the dropdown to. null
                              CSS z-index value for the dropdown. undefined

                              Slots

                              Name Description
                              choice

                              A slot that is called for each slot that needs to be rendered, no matter its origin. Example:

                              <bt-form-select>
                                  <template #choice="{choice}">
                                      <img :src="choice.originalValue.url" alt="" /> 
                                      <b>{{ choice.label }}</b>
                                  </template>
                              </bt-form-select>
                              

                              Choices defined here are shown just before the choices added in the choices-after slot.


                              Props:

                              • choice: the Choice object of the current item.
                              choices

                              A slot where inline choices can be defined. Example:

                              <bt-form-select>
                                  <template #choices>
                                      <bt-form-select-choice :value="1">First</bt-form-select-choice>
                                      <bt-form-select-choice :value="2">Second</bt-form-select-choice>
                                  </template>
                              </bt-form-select>
                              

                              Choices defined here are shown just before the choices added in the choices-after slot.


                              Props: none

                              choices-after

                              A slot where inline choices can be defined.

                              Choices defined here are shown after any other choice, no matter their origin.


                              Props: none

                              choices-before

                              A slot where inline choices can be defined.

                              Choices defined here are shown before any other choice, no matter their origin.


                              Props: none

                              default or label

                              Defines the label of the field. This slot takes priority over the label prop.


                              Props: none

                              help

                              Defines the help text of the field. This slot takes priority over the help prop.


                              Props: none

                              before

                              Defines the content of the addon to show before the field.


                              Props: none

                              before-raw

                              Defines the content of the un-styled addon to show before the field.


                              Props: none

                              after

                              Defines the content of the addon to show after the field.


                              Props: none

                              after-raw

                              Defines the content of the un-styled addon to show after the field.


                              Props: none

                              extras-before

                              Defines custom floating extras that appear before the built-in ones.


                              Props: none

                              extras-after

                              Defines custom floating extras that appear after the built-in ones.


                              Props: none

                              Theming

                              Below the list of all CSS variables and selectors available to customize the appearance of the component. If you're not familiar on how the theming works, please refer to the VueThemes documentation.

                              Variables

                              Variable Default Comment
                              fontFamily var(--bt-font-family-base) -
                              fontSize var(--bt-font-size-base) -
                              fontWeight var(--bt-font-weight-normal) -
                              textColor var(--bt-text-color-base) -
                              backgroundColor var(--bt-color-white) -
                              backgroundDisabledColor Same as backgroundColor -
                              borderColor var(--bt-color-gray-200) -
                              borderRadius var(--bt-border-radius-base) -
                              borderWidth var(--bt-border-width-base) -
                              borderStyle var(--bt-border-style-base) -
                              borderFocusWidth Same as borderWidth -
                              borderFocusColor var(--bt-color-primary) -
                              borderErrorWidth Same as borderWidth -
                              borderErrorColor var(--bt-color-red-500) -
                              borderDisabledColor var(--bt-color-gray-200) -
                              placeholderX 0.8rem -
                              placeholderY 0.75rem -
                              labelTextColor var(--bt-text-color-light) -
                              labelTransitionDuration 0.2s -
                              helpTextColor var(--bt-text-color-light) -
                              helpFontSize var(--bt-font-size-sm) -
                              errorTextColor var(--bt-color-red-500) -
                              errorFontSize var(--bt-font-size-sm) -
                              disabledOpacity 0.5 -
                              addonBackgroundColor var(--bt-color-gray-50) -
                              addonTextColor var(--bt-text-color-light) -
                              inputMinWidth 150px -
                              choiceTextColor var(--bt-color-primary) -
                              choiceCheckIconColor var(--bt-color-primary) -
                              choiceTrashIconColor var(--bt-color-red-500) -
                              choiceBackgroundFocusColor var(--bt-color-gray-50) -
                              groupPaddingX 1em -
                              groupPaddingY 0.8em -
                              groupLabelTextColor var(--bt-color-gray-450) -
                              groupLabelFontWeight var(--bt-font-weight-semibold) -
                              groupLabelFontSize var(--bt-font-size-sm) -
                              groupSeparatorColor var(--bt-color-gray-100) -
                              tagTextColor var(--bt-color-gray-550) Tags are for multiple selection.
                              tagBorderColor var(--bt-color-gray-150) -
                              tagBackgroundColor var(--bt-color-gray-50) -
                              tagMaxWidth 200px -
                              tagCloseFillColor Same as tagTextColor -
                              tagCloseFillHoverColor Same as tagTextColor -
                              tagCloseBackgroundHoverColor Same as tagBorderColor -
                              clearIconColor var(--bt-text-color-light) -

                              Selectors

                              Name Comment
                              root The root container.
                              label The container of the label.
                              help The non floating help text container.
                              before The before slot container.
                              after The after slot container.
                              floatingExtras The container of the floating extras.
                              inputGroup A container that only include the form field.
                              input The actual form control.

                              Examples:

                              cssSelectors: {
                                  input: {
                                      background: '...'
                                  },
                                  floatingExtras: {
                                      color: '...'
                                  }
                              }