pickerId/picker_id is a required prop to instantiate the Date Picker. The presence of pickerId/picker_id in your Date Picker also associates the label with the input, providing the ability to focus the Date Picker by clicking the label.
The defaultDate/default_date prop has a null or empty string value by default. You can pass an ISO date string (preferred rails method) or date object (preferred JS method) if you want a default value on page load. Use Ruby UTC DateTime objects and convert them to ISO date strings with DateTime.now.utc.iso8601.
If you use a Date object without UTC time standardization the Date Picker kit may misinterpret that date as yesterdays date (consequence of timezone differentials and the Javascript Date Object constructor). See this GitHub issue for more information and the anti-pattern examples below.
You can leverage the defaultDate/default_date prop with custom logic in your filter or controller files where the determination of the default value changes based on user interaction. The page can load with an initial default date picker value or placeholder text, then after filter submission save the submitted values as the "new default" (via state or params).
import React from 'react' import { DatePicker } from 'playbook-ui' const DatePickerDefaultDate = (props) => ( <div> <DatePicker defaultDate="07/31/2020" label="Default Date String" pickerId="date-picker-default-date1" /> <DatePicker defaultDate={new Date().fp_incr(1)} label="Default Date Dynamic" pickerId="date-picker-default-date2" /> <DatePicker label="Default Behavior" pickerId="date-picker-default-date4" /> </div> ) export default DatePickerDefaultDate
Setting the allowInput prop to true permits users to key values directly into the input. This prop is set to false by default.
The date picker is built with the text input kit. Text input props you pass to the date picker kit will be forwarded to the input, with a few exceptions. The value attribute is automatically handled and bound to whatever date string is contained by the input field. You cannot pass a custom value prop. id props passed to the date picker kit will be assigned to it's parent/wrapper div. The pickerId prop is passed directly to the input and is required to instatiate the date picker.
You must use inputAria or input_aria and inputData or input_data props if you wish to pass data or aria attributes to the text input kit. If you use data or aria props they will be passed to the date picker kit itself instead. Also be aware the default behavior of text input aria and data props is to pass those props to attributes on the wrapping div not on the input itself.
The placeholder prop has a default string value: "Select Date". You can replace this with your own string or an empty string if you'd prefer it blank.
import React from 'react' import { DatePicker } from 'playbook-ui' const DatePickerInput = (props) => ( <div> <DatePicker inputAria={{ label: 'input-field' }} inputData={{ key: 'value', key2: 'value2' }} label="Aria, Name, and Data Attributes" name="date-field" pickerId="date-picker-input1" /> <DatePicker label="Custom Placeholder" pickerId="date-picker-input2" placeholder="custom-placeholder" /> <DatePicker label="Blank Placeholder" pickerId="date-picker-input3" placeholder="" /> <DatePicker disableInput label="Disable Input" pickerId="date-picker-input4" placeholder="Disabled Input" /> </div> ) export default DatePickerInput
Default label prop is "Date Picker". To remove the label set the hideLabel prop in React or the hide_label prop in Rails to true.
Your change handler function has access to two arguments: dateStr and selectedDates.
The first, dateStr, is a string of the chosen date. The second, selectedDates, is an array of selected date objects. In many use cases selectedDates will have only one value but you'll still need to access it from index 0.
NOTE: On Change does not account for manual input by users, so if your date picker sets allowInput, you should use the onClose method instead.
import React, { useState } from 'react' import { DatePicker, LabelValue } from 'playbook-ui' const DatePickerOnChange = (props) => { const today = new Date() const [dateString, setDateString] = useState(today.toLocaleDateString()) const [dateObj, setDateObj] = useState([today]) const changeHandler = (dateStr, selectedDates) => { setDateString(dateStr) setDateObj(selectedDates) } return ( <div> <DatePicker defaultDate={dateString} marginBottom="lg" onChange={changeHandler} pickerId="date-picker-onchange" /> <LabelValue label="Date Object" marginBottom="lg" value={dateObj[0] ? dateObj[0].toString() : ''} /> <LabelValue label="Date String" value={dateString} /> </div> ) } export default DatePickerOnChange
The onClose handler function has access to two arguments: dateStr and selectedDates.
The first, dateStr, is a string of the chosen date. The second, selectedDates, is an array of selected date objects. In many use cases selectedDates will have only one value but you'll still need to access it from index 0.
NOTE: onClose is the ideal handler function to use when allowInput is enabled.
/* eslint-disable react/no-multi-comp */ import React, { useState } from 'react' import { DatePicker, LabelValue } from 'playbook-ui' const DatePickerOnClose = (props) => { const today = new Date() const [dateString, setDateString] = useState(today.toLocaleDateString()) const [dateObj, setDateObj] = useState([today]) const handleOnClose = (selectedDates, dateStr) => { setDateString(dateStr) setDateObj(selectedDates) } return ( <div> <DatePicker defaultDate={dateString} enableTime marginBottom="lg" onClose={handleOnClose} pickerId="date-picker-on-close" showTimezone /> <LabelValue label="Date Object" marginBottom="lg" value={dateObj[0] ? dateObj[0].toString() : ''} /> <LabelValue label="Date String" value={dateString} /> </div> ) } export default DatePickerOnClose
To use the quickpick:
mode must be set to rangeselectionType must be set to quickpickUse the onClose handler function to access the startDate and endDate values. Check the onClose example for more information.
import React from "react" import { DatePicker } from 'playbook-ui' const DatePickerQuickPickReact = (props) => ( <> <DatePicker allowInput mode="range" pickerId="date-picker-quick-pick" placeholder="mm/dd/yyyy to mm/dd/yyyy" selectionType="quickpick" /> </> ) export default DatePickerQuickPickReact
Use this_ranges_end_today/thisRangesEndToday to set end date on all ranges that start with 'this' to today's date. For instance, by default 'This Year' will set end day to 12/31/(current year), but if the this_ranges_end_today/thisRangesEndToday prop is used, end date on that range will be today's date.
import React from 'react' import { DatePicker } from 'playbook-ui' const DatePickerQuickPickRangeLimit = (props) => ( <> <DatePicker allowInput mode="range" pickerId="thisRangesEndToday" placeholder="mm/dd/yyyy to mm/dd/yyyy" selectionType="quickpick" thisRangesEndToday /> </> ) export default DatePickerQuickPickRangeLimit
The customQuickPickDates/custom_quick_pick_dates prop allows for the user/dev to define their own quick pick dates.
The prop accepts an object with two key/value pairs: dates & override (separate doc example below).
The dates property accepts an array of objects. Each object in the array has label and value properties. The label is what will be displayed in the UI of the dropdown menu. The value property is just the date that is going to be passed to the datepicker. The value property can be an array of two strings that represent a range, allowing for the dev to be extremely specific. Additionally, the dates array allows for a clean, simple API under that automatically converts dates in a common vernacular.
The timePeriod property accepts "days", "weeks", "months", "quarters" or "years", representing past time periods.
The amount property accepts any number.
import React from "react" import { DatePicker } from 'playbook-ui' const DatePickerQuickPickCustom = (props) => ( <> <DatePicker allowInput customQuickPickDates={{ dates: [ // Allow Playbook to handle the logic... { label: "Last 15 months", value: { timePeriod: "months", amount: 15, }, }, // Or, be explicit with an exact date range for more control... { label: "First Week of June 2022", value: ["06/01/2022", "06/07/2022"], }, ], }} mode='range' pickerId='date-picker-quick-pick-custom-override' placeholder='mm/dd/yyyy to mm/dd/yyyy' selectionType='quickpick' /> </> ) export default DatePickerQuickPickCustom
The customQuickPickDates/custom_quick_pick_dates prop allows for an override boolean. The override allows for the user to completely override the quick pick dates that ship with the component. Default of override is set to true. If you would like to simply append your dates to the default quick pick dates, set this prop to false explicitly.
import React from "react" import { DatePicker } from 'playbook-ui' const DatePickerQuickPickCustomOverride = (props) => ( <> <DatePicker allowInput customQuickPickDates={{ override: false, dates: [ { label: "Last 15 months", value: { timePeriod: "months", amount: 15, }, }, { label: "First Week of June 2022", value: ["06/01/2022", "06/07/2022"], }, ], }} marginTop='lg' mode='range' pickerId='date-picker-quick-pick-custom' placeholder='mm/dd/yyyy to mm/dd/yyyy' selectionType='quickpick' /> </> ) export default DatePickerQuickPickCustomOverride
To set a default value using Quick Pick, use the defaultDate or default_date prop. This prop should match one of the labels displayed in the UI of the dropdown menu.
import React from "react" import { DatePicker } from 'playbook-ui' const DatePickerQuickPickDefaultDate = (props) => ( <> <DatePicker allowInput defaultDate="This month" mode="range" pickerId="quick-pick-default-date" placeholder="mm/dd/yyyy to mm/dd/yyyy" selectionType="quickpick" /> <DatePicker allowInput customQuickPickDates={{ dates: [ { label: "Last 15 months", value: { timePeriod: "months", amount: 15, }, }, { label: "First Week of June 2022", value: ["06/01/2022", "06/07/2022"], }, ], }} defaultDate="First Week of June 2022" label="Custom Date Picker" mode="range" pickerId="custom-quick-pick-default-date" placeholder="mm/dd/yyyy to mm/dd/yyyy" selectionType="quickpick" /> </> ) export default DatePickerQuickPickDefaultDate
You can link a Dropdown (quickpick variant) to standard DatePickers using the following props:
For the Dropdown:
controlsStartId: ID of the DatePicker that should receive the start date.
controlsEndId: ID of the DatePicker that should receive the end date.
When a quickpick option like “This Year” is selected, it automatically populates the linked start and end inputs.
For the Start/End DatePickers:
syncStartWith: ID of the quickpick this start date is synced to.
syncEndWith: ID of the quickpick this end date is synced to.
When a user manually edits the start or end date, it clears the selected quickpick to prevent conflicting values.
import React from "react"; import { Dropdown, DatePicker } from 'playbook-ui' const DatePickerAndDropdownRange = (props) => { return ( <> <Dropdown controlsEndId="end-date-picker1" controlsStartId="start-date-picker1" id="dropdown-as-quickpick" label="Date Range" marginBottom="sm" placeholder="Select a Date Range" variant="quickpick" /> <DatePicker label="Start Date" pickerId="start-date-picker1" placeholder="Select a Start Date" syncStartWith="dropdown-as-quickpick" /> <DatePicker label="End Date" pickerId="end-date-picker1" placeholder="Select an End Date" syncEndWith="dropdown-as-quickpick" /> </> ); }; export default DatePickerAndDropdownRange;
A full list of formatting tokens, i.e. "m/d/Y" can be found here.
import React from 'react' import { DatePicker } from 'playbook-ui' const DatePickerFormat = (props) => ( <div> <DatePicker defaultDate={new Date()} format="m-d-Y" pickerId="date-picker-format1" /> <DatePicker defaultDate={new Date()} format="m/d/y" pickerId="date-picker-format2" /> <DatePicker defaultDate={new Date()} format="n-j-y" pickerId="date-picker-format3" /> <DatePicker defaultDate={new Date()} format="Y-d-m" pickerId="date-picker-format4" /> </div> ) export default DatePickerFormat
import React from 'react' import { DatePicker } from 'playbook-ui' const DatePickerDisabled = (props) => ( <div> <DatePicker disableDate={[new Date().fp_incr(1)]} label="Disable Single Date" pickerId="single-disabled-date" /> <DatePicker disableDate={[new Date().fp_incr(1), new Date().fp_incr(3)]} label="Disable Multiple Dates" pickerId="multiple-disabled-dates" /> <DatePicker disableRange={[ { from: new Date().fp_incr(1), to: new Date().fp_incr(7), }, ]} label="Disable Single Range" pickerId="single-date-range" /> <DatePicker disableRange={[ { from: new Date().fp_incr(1), to: new Date().fp_incr(3), }, { from: new Date().fp_incr(7), to: new Date().fp_incr(14), }, ]} label="Disable Multiple Ranges" pickerId="multiple-date-ranges" /> <DatePicker disableWeekdays={['Sunday', 'Saturday']} label="Disable Specific Weekdays" pickerId="disabled-weekdays" /> </div> ) export default DatePickerDisabled
import React from 'react' import { DatePicker } from 'playbook-ui' const DatePickerMinMax = (props) => ( <div> <DatePicker label="Dynamic dates using flatpickr increment function" maxDate={new Date().fp_incr(3)} minDate={new Date().fp_incr(-3)} pickerId="date-picker-min-max1" /> <DatePicker format="m/d/Y" label="Absolute formatted dates" maxDate="10/20/2020" minDate="10/10/2020" pickerId="date-picker-min-max2" /> </div> ) export default DatePickerMinMax
import React, { useEffect } from 'react' import { DatePicker, Button } from 'playbook-ui' const DatePickerFlatpickrMethods = () => { let fpInstance useEffect(() => { fpInstance = document.querySelector('#fp-methods')._flatpickr }, []) const clickHandlerClear = () => { fpInstance.clear() } const clickHandlerClose = () => { fpInstance.close() } const clickHandlerToday = () => { fpInstance.setDate(new Date(), true) } return ( <div> <Button marginRight="sm" onClick={clickHandlerClose} text="Close" /> <Button marginRight="sm" onClick={clickHandlerClear} text="Clear" /> <Button onClick={clickHandlerToday} text="Today" /> <DatePicker hideLabel marginTop="sm" pickerId="fp-methods" /> </div> ) } export default DatePickerFlatpickrMethods
You can find a full list of flatpickr events and hooks in their documentation.
Use window.addEventListener("DOMContentLoaded", () => {}), not document.addEventListener("DOMContentLoaded", () => {}).
import React from 'react' import { DatePicker } from 'playbook-ui' const DatePickerHooks = (props) => { // Define hooks const changeHook = () => { alert('date changed') } const openHook = () => { alert('calendar opened') } // Access flatpickr instances with picker ids and assign them variables window.addEventListener('DOMContentLoaded', () => { const fpChange = document.querySelector('#date-picker-hooks-onchange')._flatpickr const fpOpen = document.querySelector('#date-picker-hooks-onopen')._flatpickr // Push one or more hooks to flatpickr instance's Event config arrays fpChange.config.onChange.push(changeHook) fpOpen.config.onOpen.push(openHook) }) return ( <div> <DatePicker label="onChange" pickerId="date-picker-hooks-onchange" /> <DatePicker label="onOpen" pickerId="date-picker-hooks-onopen" /> </div> ) } export default DatePickerHooks
Defaults to [1900, 2100]. Combine with min-max prop for best results.
import React from 'react' import { DatePicker } from 'playbook-ui' const DatePickerYearRange = (props) => ( <div> <DatePicker defaultDate="05/05/2015" maxDate="12/31/2018" minDate="01/01/2015" pickerId="date-picker-year-range" yearRange={[2015, 2018]} /> </div> ) export default DatePickerYearRange
import React from 'react' import { DatePicker } from 'playbook-ui' const DatePickerMarginBottom = (props) => ( <div> <DatePicker marginBottom="none" pickerId="date-picker-none" /> <DatePicker marginBottom="xs" pickerId="date-picker-xs" /> <DatePicker marginBottom="sm" pickerId="date-picker-sm" /> <DatePicker marginBottom="md" pickerId="date-picker-md" /> <DatePicker marginBottom="lg" pickerId="date-picker-lg" /> <DatePicker marginBottom="xl" pickerId="date-picker-xl" /> </div> ) export default DatePickerMarginBottom
By default selectType prop is disabled. To activate it set selectionType prop in JSX/TSX to month. To activate it set selection_type prop in a rails file to month.
By default selectType prop is disabled. To activate it set selectionType prop in JSX/TSX to week. To activate it set selection_type prop in a rails file to week.
To select time as well, you should pass the enableTime boolean prop. You can also enable timezone display by passing showTimezone.
/* eslint-disable react/no-multi-comp */ import React, { useMemo, useState } from 'react' import { DatePicker, Body } from 'playbook-ui' const DEFAULT_DATE = new Date() DEFAULT_DATE.setHours(12) DEFAULT_DATE.setMinutes(0) const DatePickerTime = (props) => { const [selectedDateTime, setSelectedDateTime] = useState(DEFAULT_DATE) const refExample = React.createRef() const handleOnInputChanged = (dateTime) => { setSelectedDateTime(dateTime) } return ( <div ref={refExample}> <Body marginBottom="md">{selectedDateTime.toString()}</Body> {useMemo(() => ( <DatePicker closeOnSelect={false} defaultDate={DEFAULT_DATE} enableTime onChange={handleOnInputChanged} pickerId="date-picker-time" showTimezone /> ), [props])} </div> ) } export default DatePickerTime
Datepicker supports position options from Flatpickr Options Documentation. There are multiple positioning options to choose from.
Note: In order for the above prop to work properly, you must also send staticPosition={false} to your Datepicker kit instance.
If you are using the Datepicker within a Dialog, you cannot use the staticPosition/static_position prop.
Upon adding static={false} to the date picker, you will notice that the date picker detaches from the input field while scrolling. This is a known Flatpickr nuance. By adding the scrollContainer prop, you can tell the date picker which DOM container it should watch for scroll events. In this example, you can see that scrollContainer=".pb--page--content--main" is being passed in order to keep the date picker correctly positioned on page scroll.
Useage: scrollContainer: .validQuerySelectorHere
import React from 'react' import { Flex, FlexItem, DatePicker } from 'playbook-ui' const DatePickerPositions = (props) => ( <React.Fragment> <Flex> <FlexItem fixedSize="50%"> <DatePicker label="Datepicker (opens on the right)" pickerId="date-picker-positions1" position="auto right" scrollContainer=".pb--page--content--main" staticPosition={false} /> </FlexItem> </Flex> <Flex> <FlexItem fixedSize="50%"> <DatePicker label="Datepicker (opens on the left)" pickerId="date-picker-positions2" position="auto left" scrollContainer=".pb--page--content--main" staticPosition={false} /> </FlexItem> </Flex> <Flex> <FlexItem fixedSize="50%"> <DatePicker label="Datepicker (opens above on the left)" pickerId="date-picker-positions3" position="above left" scrollContainer=".pb--page--content--main" staticPosition={false} /> </FlexItem> </Flex> <Flex> <FlexItem fixedSize="50%"> <DatePicker label="Datepicker (opens below on the right)" pickerId="date-picker-positions4" position="below right" scrollContainer=".pb--page--content--main" staticPosition={false} /> </FlexItem> </Flex> </React.Fragment> ) export default DatePickerPositions
import React, { useRef, useEffect, useState } from 'react' import { Card, Flex, FlexItem, DatePicker } from 'playbook-ui' const DatePickerPositionsElement = (props) => { const cardRefTop = useRef(null), cardRefBtm = useRef(null) const [cardTop, setCardTop] = useState() const [cardBtm, setCardBtm] = useState() useEffect(() => { setCardTop(cardRefTop.current) setCardBtm(cardRefBtm.current) }, [cardTop, cardBtm]) return ( <React.Fragment> <div ref={cardRefTop}> <Card marginBottom="md" > {'👋 Datepicker will position from here based on ID.'} </Card> </div> <Flex> <FlexItem fixedSize="50%"> <DatePicker label="Datepicker (opens on the right)" pickerId="date-picker-position-element" position="auto right" positionElement={cardTop} scrollContainer=".pb--page--content--main" staticPosition={false} /> </FlexItem> </Flex> <div ref={cardRefBtm}> <Card marginBottom="md" > {'👋 Datepicker will position from here based on class name.'} </Card> </div> <Flex> <FlexItem fixedSize="50%"> <DatePicker label="Datepicker (opens on the right)" pickerId="date-picker-position-element2" position="auto right" positionElement={cardBtm} scrollContainer=".pb--page--content--main" staticPosition={false} /> </FlexItem> </Flex> </React.Fragment> ) } export default DatePickerPositionsElement
The requiredIndicator/required_indicator prop displays a red asterisk (*) next to the label to visually indicate that the field is required. This is purely visual and does not enforce validation—you can pair it with HTML required, client-side validation, or server-side validation as needed.
This kit's options prop requires an array of objects, each of which will be used as the selectable options within the dropdown. Each option object can support any number of key-value pairs, but each must contain label and value.
import React from 'react' import { Dropdown } from 'playbook-ui' const DropdownDefault = (props) => { const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" } ]; return ( <div> <Dropdown options={options} /> </div> ) } export default DropdownDefault
The autocomplete prop can be used to add autocomplete or typeahead functionality to the Dropdown's default Trigger. This prop is set to 'false' by default.
import React from 'react' import { Dropdown } from 'playbook-ui' const DropdownWithAutocomplete = (props) => { const options = [ { label: "United States", value: "unitedStates", areaCode: "+1", icon: "🇺🇸", id: "us" }, { label: "United Kingdom", value: "unitedKingdom", areaCode: "+44", icon: "🇬🇧", id: "gb" }, { label: "Pakistan", value: "pakistan", areaCode: "+92", icon: "🇵🇰", id: "pk" } ] return ( <div> <Dropdown autocomplete options={options} /> </div> ) } export default DropdownWithAutocomplete
multiSelect is a boolean prop that if set to true will allow for multiple options to be selected from the Dropdown.
multiSelect is set to false by default.
import React from 'react' import { Dropdown } from 'playbook-ui' const DropdownMultiSelect = (props) => { const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "United Kingdom", value: "unitedKingdom", id: "gb" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" }, { label: "India", value: "india", id: "in" }, { label: "Australia", value: "australia", id: "au" }, { label: "New Zealand", value: "new Zealand", id: "nz" }, { label: "Italy", value: "italy", id: "it" }, { label: "Spain", value: "spain", id: "es" } ]; return ( <div> <Dropdown multiSelect options={options} /> </div> ) } export default DropdownMultiSelect
multiSelect can also be used with the autocomplete functionality.
import React from 'react' import { Dropdown } from 'playbook-ui' const DropdownMultiSelectWithAutocomplete = (props) => { const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "United Kingdom", value: "unitedKingdom", id: "gb" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" }, { label: "India", value: "india", id: "in" }, { label: "Australia", value: "australia", id: "au" }, { label: "New Zealand", value: "new Zealand", id: "nz" }, { label: "Italy", value: "italy", id: "it" }, { label: "Spain", value: "spain", id: "es" } ]; return ( <div> <Dropdown autocomplete multiSelect options={options} /> </div> ) } export default DropdownMultiSelectWithAutocomplete
By default, the multiSelect prop will render selected options as the default FormPill. FormPillProps however can be used to customize these Pills with any props that exist for the FormPill.
This prop must be an object that contains valid FormPill props. For a full list of FormPill props, see here.
import React from 'react' import { Dropdown } from 'playbook-ui' const DropdownMultiSelectDisplay = (props) => { const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "United Kingdom", value: "unitedKingdom", id: "gb" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" }, { label: "India", value: "india", id: "in" }, { label: "Australia", value: "australia", id: "au" }, { label: "New Zealand", value: "new Zealand", id: "nz" }, { label: "Italy", value: "italy", id: "it" }, { label: "Spain", value: "spain", id: "es" } ]; return ( <div> <Dropdown formPillProps={{size:"small", color:"neutral"}} multiSelect options={options} /> </div> ) } export default DropdownMultiSelectDisplay
For the subtle variant, it is recommended that you set the Separators prop to false to remove the separator lines between the options for a cleaner look.
import React from 'react' import { Dropdown } from 'playbook-ui' const DropdownSubtleVariant = (props) => { const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" } ]; return ( <> <Dropdown options={options} separators={false} variant="subtle" /> </> ) } export default DropdownSubtleVariant
The dropdown is built using all of the following subcomponents:
Dropdown.Trigger is the UI component that users interact with to toggle the dropdown.
Dropdown.Container is the floating container that wraps the list of dropdown options.
Dropdown.Option renders options that are passed to the container.
Each of these subcomponents can be altered using global props and/or their respective props. See doc examples below for more information on each.
import React from 'react' import { Dropdown } from 'playbook-ui' const DropdownSubcomponentStructure = (props) => { const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" } ]; return ( <div> <Dropdown options={options} > <Dropdown.Trigger/> <Dropdown.Container> {options.map((option) => ( <Dropdown.Option key={option.id} option={option} /> ))} </Dropdown.Container> </Dropdown> </div> ) } export default DropdownSubcomponentStructure
autocomplete prop can also be used in conjunction with the subcomponent structure.
import React from 'react' import { Dropdown, Badge, Flex, FlexItem, User } from 'playbook-ui' const DropdownWithAutocompleteWithSubcomponents = (props) => { const options = [ { label: "Jasper Furniss", value: "jasperFurniss", territory: "PHL", title: "Lead UX Engineer", id: "jasper-furniss", status: "Offline" }, { label: "Ramon Ruiz", value: "ramonRuiz", territory: "PHL", title: "Senior UX Designer", id: "ramon-ruiz", status: "Away" }, { label: "Carlos Lima", value: "carlosLima", territory: "PHL", title: "Nitro Developer", id: "carlos-lima", status: "Online" }, { label: "Courtney Long", value: "courtneyLong", territory: "PHL", title: "Lead UX Designer", id: "courtney-long", status: "Online" } ]; return ( <div> <Dropdown autocomplete options={options} > {options.map((option) => ( <Dropdown.Option key={option.id} option={option} > <Flex align="center" justify="between" > <FlexItem> <User align="left" avatar name={option.label} orientation="horizontal" territory={option.territory} title={option.title} /> </FlexItem> <FlexItem> <Badge dark rounded text={option.status} variant={`${ option.status === "Offline" ? "neutral" : option.status === "Online" ? "success" : "warning" }`} /> </FlexItem> </Flex> </Dropdown.Option> ))} </Dropdown> </div> ) } export default DropdownWithAutocompleteWithSubcomponents
The top-level Dropdown component optionally accepts any string through a label prop to produce a label above your trigger element.
Add an id to wire the label to the trigger so that clicking the label will move focus directly to the input, and open the drop-down.
import React from 'react' import { Dropdown } from 'playbook-ui' const DropdownDefault = (props) => { const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" } ]; return ( <div> <Dropdown id="select_a_country" label="Select a Country" options={options} > {options.map((option) => ( <Dropdown.Option key={option.id} option={option} /> ))} </Dropdown> </div> ) } export default DropdownDefault
Dropdown.Option subcomponent accepts any child components to customize the options' contents and display. By default, options are Body kit text that is set by the label value from the option object.
import React from 'react' import { Dropdown, FlexItem, Icon, Body, Flex } from 'playbook-ui' const DropdownWithCustomOptions = (props) => { const options = [ { label: "United States", value: "unitedStates", areaCode: "+1", icon: "🇺🇸", id: "United-states" }, { label: "Canada", value: "canada", areaCode: "+1", icon: "🇨🇦", id: "canada" }, { label: "Pakistan", value: "pakistan", areaCode: "+92", icon: "🇵🇰", id: "pakistan" } ]; return ( <div> <Dropdown options={options} > {options.map((option) => ( <Dropdown.Option key={option.id} option={option} > <Flex align="center" justify="between" > <FlexItem> <Flex> <Icon icon={option.icon} paddingRight="xs" /> <Body text={option.label} /> </Flex> </FlexItem> <FlexItem> <Body color="light" text={option.areaCode} /> </FlexItem> </Flex> </Dropdown.Option> ))} </Dropdown> </div> ) } export default DropdownWithCustomOptions
import React from 'react' import { Dropdown, Body, Flex, FlexItem, Icon } from 'playbook-ui' const DropdownMultiSelectWithCustomOptions = (props) => { const options = [ { label: "United States", value: "unitedStates", areaCode: "+1", icon: "🇺🇸", id: "United-states" }, { label: "Canada", value: "canada", areaCode: "+1", icon: "🇨🇦", id: "canada" }, { label: "Pakistan", value: "pakistan", areaCode: "+92", icon: "🇵🇰", id: "pakistan" }, { label: "India", value: "india", areaCode: "+91", icon: "🇮🇳", id: "india" }, { label: "Australia", value: "australia", areaCode: "+61", icon: "🇦🇺", id: "australia" }, { label: "New Zealand", value: "newZealand", areaCode: "+64", icon: "🇳🇿", id: "new-zealand" }, { label: "Italy", value: "italy", areaCode: "+39", icon: "🇮🇹", id: "italy" }, { label: "Spain", value: "spain", areaCode: "+34", icon: "🇪🇸", id: "spain" } ]; return ( <div> <Dropdown multiSelect options={options} > {options.map((option) => ( <Dropdown.Option key={option.id} option={option} > <Flex align="center" justify="between" > <FlexItem> <Flex> <Icon icon={option.icon} paddingRight="xs" /> <Body text={option.label} /> </Flex> </FlexItem> <FlexItem> <Body color="light" text={option.areaCode} /> </FlexItem> </Flex> </Dropdown.Option> ))} </Dropdown> </div> ) } export default DropdownMultiSelectWithCustomOptions
Optionally utilize customDisplay on the Dropdown.Trigger subcomponent to customize its content after an option is selected. Pass in any combination of kits to create a custom display. When a user clicks on an option, the kits passed into customDisplay will display as the selected option.
The placeholder prop can also be used to customize the placeholder text for the default Dropdown.Trigger.
The onSelect prop returns the selected option as an object to be utilized by the dev. In this example we are using the onSelect to set a state with the selected option and using it to customize the customDisplay.
import React, { useState } from 'react' import { Dropdown, Badge, Flex, FlexItem, Avatar, User, Body } from 'playbook-ui' const DropdownWithCustomDisplay = (props) => { const [selectedOption, setSelectedOption] = useState(); const options = [ { label: "Jasper Furniss", value: "jasperFurniss", territory: "PHL", title: "Lead UX Engineer", id: "jasper-furniss", status: "Offline" }, { label: "Ramon Ruiz", value: "ramonRuiz", territory: "PHL", title: "Senior UX Designer", id: "ramon-ruiz", status: "Away" }, { label: "Carlos Lima", value: "carlosLima", territory: "PHL", title: "Nitro Developer", id: "carlos-lima", status: "Online" }, { label: "Courtney Long", value: "courtneyLong", territory: "PHL", title: "Lead UX Designer", id: "courtney-long", status: "Online" } ]; const CustomDisplay = () => { return ( <> { selectedOption && ( <Flex align="center"> <Avatar name={selectedOption.label} size="xs" /> <Body marginX="xs" text={selectedOption.label} /> <Badge text={selectedOption.status} variant={selectedOption.status == "Offline" ? "neutral" : selectedOption.status == "Online" ? "success" : "warning"} /> </Flex> ) } </> ) }; return ( <div> <Dropdown onSelect={(selectedItem) => setSelectedOption(selectedItem)} options={options} > <Dropdown.Trigger customDisplay={<CustomDisplay/>} placeholder="Select a User" /> {options.map((option) => ( <Dropdown.Option key={option.id} option={option} > <Flex align="center" justify="between" > <FlexItem> <User align="left" avatar name={option.label} orientation="horizontal" territory={option.territory} title={option.title} /> </FlexItem> <FlexItem> <Badge dark rounded text={option.status} variant={`${ option.status === "Offline" ? "neutral" : option.status === "Online" ? "success" : "warning" }`} /> </FlexItem> </Flex> </Dropdown.Option> ))} </Dropdown> </div> ) } export default DropdownWithCustomDisplay
Optionally replace the default trigger's select element by passing child components directly to the Dropdown.Trigger.
import React, { useState } from 'react' import { Dropdown, FlexItem, Icon, Body, Flex, IconCircle } from 'playbook-ui' const DropdownWithCustomTrigger = (props) => { const [selectedOption, setSelectedOption] = useState(); const options = [ { label: "United States", value: "unitedStates", areaCode: "+1", icon: "🇺🇸", id: "United-states" }, { label: "Canada", value: "canada", areaCode: "+1", icon: "🇨🇦", id: "canada" }, { label: "Pakistan", value: "pakistan", areaCode: "+92", icon: "🇵🇰", id: "pakistan" } ]; return ( <div> <Dropdown onSelect={(selectedItem) => setSelectedOption(selectedItem)} options={options} > <Dropdown.Trigger> <div key={selectedOption ? selectedOption.icon : "flag"}> <IconCircle cursor="pointer" icon={selectedOption ? selectedOption.icon : "flag"} variant="royal" /> </div> </Dropdown.Trigger> <Dropdown.Container maxWidth="xs"> {options.map((option) => ( <Dropdown.Option key={option.id} option={option} > <Flex align="center" justify="between" > <FlexItem> <Flex> <Icon icon={option.icon} paddingRight="xs" /> <Body text={option.label} /> </Flex> </FlexItem> <FlexItem> <Body color="light" text={option.areaCode} /> </FlexItem> </Flex> </Dropdown.Option> ))} </Dropdown.Container> </Dropdown> </div> ) } export default DropdownWithCustomTrigger
The optional searchbar boolean prop can also be used on the Dropdown.Container to render a searchbar with typeahead functionality within the dropdown itself. This is especially useful when a custom trigger is being used.
searchbar is set to false by default.
import React, { useState } from 'react' import { Dropdown, IconCircle } from 'playbook-ui' const DropdownWithSearch = (props) => { const [selectedOption, setSelectedOption] = useState(); const options = [ { label: "United States", value: "unitedStates", icon: "🇺🇸", id: "United-states" }, { label: "United Kingdom", value: "unitedKingdom", icon: "🇬🇧", id: "united-kingdom" }, { label: "Pakistan", value: "pakistan", icon: "🇵🇰", id: "pakistan" } ]; return ( <div> <Dropdown onSelect={(selectedItem) => setSelectedOption(selectedItem)} options={options} > <Dropdown.Trigger> <div key={selectedOption ? selectedOption.icon : "flag"}> <IconCircle cursor="pointer" icon={selectedOption ? selectedOption.icon : "flag"} variant="royal" /> </div> </Dropdown.Trigger> <Dropdown.Container maxWidth="xs" searchbar > {options.map((option) => ( <Dropdown.Option key={option.id} option={option} /> ))} </Dropdown.Container> </Dropdown> </div> ) } export default DropdownWithSearch
By default, dropdown option paddingX is set to sm and paddingY is set to xs, but this padding can be overridden using our global padding props. In this example we are setting the option padding to sm all around.
import React from 'react' import { Dropdown } from 'playbook-ui' const DropdownWithCustomPadding = (props) => { const options = [ { label: "United States", value: "unitedStates", areaCode: "+1", icon: "🇺🇸", id: "United-states" }, { label: "Canada", value: "canada", areaCode: "+1", icon: "🇨🇦", id: "canada" }, { label: "Pakistan", value: "pakistan", areaCode: "+92", icon: "🇵🇰", id: "pakistan" } ]; return ( <div> <Dropdown options={options} > {options.map((option) => ( <Dropdown.Option key={option.id} option={option} padding="sm" /> ))} </Dropdown> </div> ) } export default DropdownWithCustomPadding
The activeStyle prop can be used to customize the appearance of the dropdown selection indicator. It accepts an object with the following keys: backgroundColor sets the background color of the selected item (and its hover state); fontColor sets the font color of the selected item.
backgroundColor Type: String | Values: bg_light | white | Default: (no selection) is primary
fontColor Type: String | Values: primary | all Playbook Text Colors | Default: (no selection) is white
import React from 'react' import { Dropdown } from 'playbook-ui' const DropdownCustomActiveStyleOptions = (props) => { const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" } ]; return ( <div> <Dropdown activeStyle={{ backgroundColor: "bg_light", fontColor: "primary", }} label="Background Color: bg_light; Font Color: primary" marginBottom="sm" options={options} > <Dropdown.Trigger/> <Dropdown.Container> {options.map((option) => ( <Dropdown.Option key={option.id} option={option} /> ))} </Dropdown.Container> </Dropdown> <Dropdown activeStyle={{ backgroundColor: "white", fontColor: "primary", }} label="Background Color: white; Font Color: primary" marginBottom="sm" options={options} /> <Dropdown activeStyle={{ backgroundColor: "bg_light", fontColor: "text_lt_default", }} autocomplete label="Background Color: bg_light; Font Color: text_lt_default" marginBottom="sm" options={options} /> <Dropdown activeStyle={{ fontColor: "text_lt_lighter", }} label="Font Color: text_lt_lighter" marginBottom="sm" options={options} > <Dropdown.Trigger/> <Dropdown.Container> {options.map((option) => ( <Dropdown.Option key={option.id} option={option} /> ))} </Dropdown.Container> </Dropdown> </div> ) } export default DropdownCustomActiveStyleOptions
Use the Dropdown.Option subcomponent structure to include custom layouts inside dropdown menus. Icons can be placed alongside the Body label text.
import React from 'react' import { Dropdown, Body, Flex, Icon } from 'playbook-ui' const DropdownCustomIconOptions = (props) => { const options = [ { label: "Item 1", value: "item-1", id: "1" }, { label: "Item 2", value: "item-2", id: "2" }, { label: "Item 3", value: "item-3", id: "3" }, ] return ( <div> <Dropdown label="Multiple Icons" options={options} > {options.map((option) => ( <Dropdown.Option key={option.id} option={option} > <Flex align="center" justify="between" > <Flex align="center"> <Icon icon="calendar" paddingRight="xs" /> <Body color="default" text={option.label} /> </Flex> <Icon icon="check" /> </Flex> </Dropdown.Option> ))} </Dropdown> <Dropdown label="Icon on Left" options={options} paddingY="md" > {options.map((option) => ( <Dropdown.Option key={option.id} option={option} > <Flex align="center"> <Icon icon="calendar" paddingRight="xs" /> <Body color="default" text={option.label} /> </Flex> </Dropdown.Option> ))} </Dropdown> <Dropdown label="Icon on Right" options={options} > {options.map((option) => ( <Dropdown.Option key={option.id} option={option} > <Flex align="center" justify="between" > <Flex align="center"> <Body color="default" text={option.label} /> </Flex> <Icon icon="check" /> </Flex> </Dropdown.Option> ))} </Dropdown> </div> ) } export default DropdownCustomIconOptions
Radio inputs can be used inside Dropdown.Option for a custom layout that mimics form-like selection within a dropdown. Use the activeStyle backgroundColor and fontColor props to create contrast between the Radio selection indicator and the Dropdown selection background indicator.
import React, { useState } from 'react' import { Dropdown, Body, Flex, Radio } from 'playbook-ui' const DropdownCustomRadioOptions = (props) => { const [selectedValue, setSelectedValue] = useState(null) const options = [ { label: "Item 1", value: "item-1", id: "1" }, { label: "Item 2", value: "item-2", id: "2" }, { label: "Item 3", value: "item-3", id: "3" }, ] return ( <div> <Dropdown activeStyle={{ backgroundColor: "bg_light", fontColor: "text_lt_default" }} label="Select Item" onSelect={(selectedItem) => setSelectedValue(selectedItem?.value)} options={options} > {options.map((option) => { return ( <Dropdown.Option key={option.id} option={option} > <Flex align="center"> <Radio checked={selectedValue === option.value} name="dropdown_radio" value={option.value} /> <Body text={option.label} /> </Flex> </Dropdown.Option> ) })} </Dropdown> </div> ) } export default DropdownCustomRadioOptions
import React, { useState } from 'react' import { Dropdown, Icon } from 'playbook-ui' const DropdownError = (props) => { const [selectedOption, setSelectedOption] = useState() const error = selectedOption?.value ? null : (<> <Icon icon="warning" /> Please make a valid selection </>) const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" } ]; return ( <> <Dropdown error={error} onSelect={(selectedItem) => setSelectedOption(selectedItem)} options={options} /> </> ) } export default DropdownError
import React from 'react' import { Dropdown } from 'playbook-ui' const DropdownDefaultValue = (props) => { const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" } ]; return ( <> <Dropdown defaultValue={options[2]} options={options} /> </> ) } export default DropdownDefaultValue
import React from "react"; import { Dropdown } from 'playbook-ui' const DropdownMultiSelectWithDefault = (props) => { const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "United Kingdom", value: "unitedKingdom", id: "gb" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" }, { label: "India", value: "india", id: "in" }, { label: "Australia", value: "australia", id: "au" }, { label: "New Zealand", value: "new Zealand", id: "nz" }, { label: "Italy", value: "italy", id: "it" }, { label: "Spain", value: "spain", id: "es" } ]; const defaultSelectedOptions = [ { label: "United States", value: "unitedStates", }, { label: "Italy", value: "italy", }, ]; return ( <div> <Dropdown defaultValue={defaultSelectedOptions} multiSelect options={options} /> </div> ); }; export default DropdownMultiSelectWithDefault;
The blankSelection prop adds a blank option at the top of the dropdown options list. This allows users to explicitly clear their selection by choosing the blank option.
The blank selection option appears as the first item in the dropdown and has an empty value (id: "", value: ""). When selected, it effectively clears the dropdown selection.
import React from 'react' import { Dropdown } from 'playbook-ui' const DropdownBlankSelection = (props) => { const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" } ]; return ( <> <Dropdown blankSelection="Select one..." options={options} /> </> ) } export default DropdownBlankSelection
The placeholder prop allows you to customize the placeholder text that appears when no option is selected in the dropdown.
The placeholder prop works with all dropdown variants (default, subtle, and quickpick). When no option is selected, the placeholder text is displayed. When an option is selected, the placeholder is replaced by the selected option's label. The default placeholder text is "Select..." if no placeholder is provided.
import React from 'react' import { Dropdown } from 'playbook-ui' const DropdownWithPlaceholder = (props) => { const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" } ]; return ( <Dropdown options={options} placeholder="Choose a country" /> ) } export default DropdownWithPlaceholder
To use an external control (like a reset button) to clear Dropdown selection, you can make use of the useRef hook. You must pass a ref to the Dropdown component and use that ref within the onClick for the external control in the way shown in the code snippet below.
import React, { useRef } from 'react' import { Button, Dropdown } from 'playbook-ui' const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" } ] const DropdownClearSelection = (props) => { const dropdownRef = useRef(null) const handleReset = () => { if (dropdownRef.current) { dropdownRef.current.clearSelected() } } return ( <> <Dropdown defaultValue={options[2]} options={options} ref={dropdownRef} /> <Button marginTop="md" onClick={handleReset} text="Reset" /> </> ) } export default DropdownClearSelection
The clearable prop controls whether the clear (X) button appears in the dropdown. When set to false, the clear button is hidden.
This is useful in two scenarios:
import React, { useRef } from 'react' import { Button, Dropdown } from 'playbook-ui' const DropdownWithClearable = (props) => { const dropdownRef = useRef(null) const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" } ] const handleReset = () => { if (dropdownRef.current) { dropdownRef.current.clearSelected() } } return ( <> <Dropdown clearable={false} label="Quick Pick" onSelect={() => {}} ref={dropdownRef} variant="quickpick" /> <Button marginY="md" onClick={handleReset} text="Reset" /> <Dropdown clearable={false} defaultValue={options[options.length - 1]} label="Default" marginBottom="md" options={options} variant="default" /> <Dropdown clearable={false} defaultValue={options[1]} label="Subtle" options={options} separators={false} variant="subtle" /> </> ) } export default DropdownWithClearable
The constrainHeight prop limits the dropdown container height to 18em and enables vertical scrolling when the content exceeds this height. This prevents long dropdown lists from rendering off-screen.
When constrainHeight is true, the dropdown will:
This is particularly useful for dropdowns with many options, such as long lists or quickpick variants with many date range options.
import React from 'react' import { Dropdown } from 'playbook-ui' const DropdownWithConstrainHeight = (props) => { // Create a long list of options to demonstrate height constraint const options = Array.from({ length: 30 }, (_, i) => ({ label: `Option ${i + 1}`, value: `option_${i + 1}`, id: `opt_${i + 1}` })) return ( <> <Dropdown data={{ testid: "dropdown-no-constrain" }} label="Without Constrain Height (Default)" marginBottom="md" options={options} /> <Dropdown constrainHeight data={{ testid: "dropdown-constrain" }} label="With Constrain Height" options={options} /> </> ) } export default DropdownWithConstrainHeight
import React from 'react' import { Dropdown } from 'playbook-ui' const DropdownSeparatorsHidden = (props) => { const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" } ]; return ( <div> <Dropdown options={options} separators={false} /> </div> ) } export default DropdownSeparatorsHidden
The useDropdown hook can also be used to toggle the dropdown open and closed using an external control. To do so, you must manage state with the custom hook, pass the dropdown:'pb-dropdown-trigger' data attribute to the external control and use the isClosed prop as shown.
import React from 'react' import { Dropdown, useDropdown, Button } from 'playbook-ui' const DropdownWithExternalControl = (props) => { const [isDropDownClosed, setIsDropdownClosed] = useDropdown(true); const options = [ { label: "United States", value: "unitedStates", areaCode: "+1", icon: "🇺🇸", id: "United-states" }, { label: "Canada", value: "canada", areaCode: "+1", icon: "🇨🇦", id: "canada" }, { label: "Pakistan", value: "pakistan", areaCode: "+92", icon: "🇵🇰", id: "pakistan" } ]; return ( <div> <Button data={{dropdown:'pb-dropdown-trigger'}} marginBottom='sm' onClick={() => setIsDropdownClosed(!isDropDownClosed)} padding="none" tabIndex={0} variant="link" > {isDropDownClosed ? "Open Dropdown" : "Close Dropdown"} </Button> <Dropdown isClosed={isDropDownClosed} options={options} > {options.map((option) => ( <Dropdown.Option key={option.id} option={option} /> ))} </Dropdown> </div> ) } export default DropdownWithExternalControl
The closeOnClick prop allows you to control when the Dropdown closes in response to click interactions. The value any reflects the default behavior, where the dropdown will close after any click. Set it to outside to ensure interactive elements as dropdown options are able to be interacted with or modified. Set it to inside for a dropdown that only closes when the input or dropdown menu is clicked.
import React from 'react' import { Dropdown, Caption } from 'playbook-ui' const DropdownClosingOptions = (props) => { const options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Pakistan", value: "pakistan", id: "pk" } ]; return ( <> <Caption marginBottom="xs" text="Any" /> <Dropdown closeOnClick='any' options={options} /> <br /> <Caption marginBottom="xs" text="Outside" /> <Dropdown closeOnClick='outside' options={options} /> <br /> <Caption marginBottom="xs" text="Inside" /> <Dropdown closeOnClick='inside' options={options} /> </> ) } export default DropdownClosingOptions
The QuickPick variant provides predefined date based options when variant="quickpick" is used.
Open the Dropdown above to see the default options.
The optional rangeEndsToday prop can be used with the quickpick variant to set end date on all ranges that start with 'this' to today's date. For instance, by default 'This Year' will set end day to 12/31/(current year), but if rangeEndsToday prop is used, end date on that range will be today's date.
import React from 'react' import { Dropdown } from 'playbook-ui' const DropdownQuickpickRangeEnd = (props) => { return ( <div> <Dropdown label="Date Range" onSelect={(selectedItem) => console.log(selectedItem)} rangeEndsToday variant="quickpick" /> </div> ) } export default DropdownQuickpickRangeEnd
To set a default value for the Dropdown, you can use the label of the range you want set as default, for example "This Year", "Today", etc.
The customQuickPickDates prop allows for defining custom quick pick date options for the dropdown. The prop accepts an object with two properties: dates and override.
The dates property accepts an array of objects. Each object has label and value properties. The label is what will be displayed in the dropdown menu. The value property defines the date range that will be selected, and can be:
["06/01/2022", "06/07/2022"])timePeriod and amount properties for dynamic date calculations:
timePeriod property accepts "days", "weeks", "months", "quarters", or "years", representing past time periods calculated from today.amount property accepts any number.The override property is a boolean that controls whether custom dates replace or append to the default quick pick options. Default is true (replaces defaults). Set to false to append your custom dates to the default quick pick options.
import React from "react" import { Dropdown } from 'playbook-ui' const DropdownQuickpickCustom = (props) => ( <div> <Dropdown customQuickPickDates={{ dates: [ // Allow Playbook to handle the logic... { label: "Last 15 months", value: { timePeriod: "months", amount: 15, }, }, // Or, be explicit with an exact date range for more control... { label: "First Week of June 2022", value: ["06/01/2022", "06/07/2022"], }, ], }} label="Date Range" marginBottom="sm" onSelect={(selectedItem) => console.log(selectedItem)} variant="quickpick" /> <Dropdown customQuickPickDates={{ dates: [ { label: "Last 15 months", value: { timePeriod: "months", amount: 15, }, }, { label: "First Week of June 2022", value: ["06/01/2022", "06/07/2022"], }, ], override: false, }} label="Date Range - Append to Defaults" onSelect={(selectedItem) => console.log(selectedItem)} variant="quickpick" /> </div> ) export default DropdownQuickpickCustom
You can link a Dropdown (quickpick variant) to standard DatePickers using the following props:
For the Dropdown:
controlsStartId: ID of the DatePicker that should receive the start date.
controlsEndId: ID of the DatePicker that should receive the end date.
When a quickpick option like “This Year” is selected, it automatically populates the linked start and end inputs.
For the Start/End DatePickers:
syncStartWith: ID of the quickpick this start date is synced to.
syncEndWith: ID of the quickpick this end date is synced to.
When a user manually edits the start or end date, it clears the selected quickpick to prevent conflicting values.
import React from "react"; import { Dropdown, DatePicker } from 'playbook-ui' const DropdownQuickpickWithDatePickers = (props) => { return ( <> <Dropdown controlsEndId="end-date-picker" controlsStartId="start-date-picker" id="dropdown-quickpick" label="Range" marginBottom="sm" placeholder="Select a Date Range" variant="quickpick" /> <DatePicker label="Start Date" pickerId="start-date-picker" placeholder="Select a Start Date" syncStartWith="dropdown-quickpick" /> <DatePicker label="End Date" pickerId="end-date-picker" placeholder="Select an End Date" syncEndWith="dropdown-quickpick" /> </> ); }; export default DropdownQuickpickWithDatePickers;
The requiredIndicator/required_indicator prop displays a red asterisk (*) next to the label, visually indicating that the field is required. This is purely visual and does not enforce validation.
You can use requiredIndicator/required_indicator with any validation approach: HTML5 validation via the required prop, client-side validation, or backend validation. For this reason, it works independently and doesn't need to be paired with the required prop.
import React from "react"; import { Dropdown } from 'playbook-ui' const DropdownRequiredIndicator = (props) => { const options = [ { label: "United States", value: "unitedStates", id: "us", }, { label: "Canada", value: "canada", id: "ca", }, { label: "Pakistan", value: "pakistan", id: "pk", }, ]; return ( <div> <Dropdown label="Select a Country" options={options} requiredIndicator > {options.map((option) => ( <Dropdown.Option key={option.id} option={option} /> ))} </Dropdown> </div> ); }; export default DropdownRequiredIndicator;
The MultiLevelSelect kit renders a multi leveled select dropdown based on data from the user. treeData is a required prop that is expected to contain the data in the form of an array of objects. See code snippet for an example data array.
For the React version of the kit, the onSelect prop returns an array of objects. This array contains all checked items irrespective of whether it is a parent, child or grandchild. Open the console on this example and check and uncheck checkboxes to see this is action!
For the Rails version of the kit, there is no onselect. The form submits as a array of strings, following the typical rails pattern of utilizing hidden inputs. The strings are the values of the selected items' ids. For example, ["103", "106", "107"].
import React from "react"; import { MultiLevelSelect } from 'playbook-ui' const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", expanded: true, children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1", }, { label: "Business Affairs", value: "businessAffairs", id: "business1", children: [ { label: "Initiatives", value: "initiatives", id: "initiative1", }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1", }, ], }, { label: "People Experience", value: "peopleExperience", id: "experience1", }, ], }, { label: "Contact Center", value: "contactCenter", id: "contact1", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1", }, { label: "Customer Service", value: "customerService", id: "customer1", }, { label: "Energy", value: "energy", id: "energy1", }, ], }, ], }, ]; const MultiLevelSelectDefault = (props) => { return ( <div> <MultiLevelSelect id='multiselect-default' onSelect={(selectedNodes) => console.log( "Selected Items", selectedNodes ) } treeData={treeData} /> </div> ) }; export default MultiLevelSelectDefault;
You can pass react-hook-form props to the MultiLevelSelect kit. Check your console to see the full data selected from this example.
import React from "react" import { MultiLevelSelect } from 'playbook-ui' import { useForm } from "react-hook-form" const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", expanded: true, children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1", }, { label: "Business Affairs", value: "businessAffairs", id: "business1", children: [ { label: "Initiatives", value: "initiatives", id: "initiative1", }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1", }, ], }, { label: "People Experience", value: "peopleExperience", id: "experience1", }, ], }, { label: "Contact Center", value: "contactCenter", id: "contact1", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1", }, { label: "Customer Service", value: "customerService", id: "customer1", }, { label: "Energy", value: "energy", id: "energy1", }, ], }, ], }, ] const MultiLevelSelectReactHook = (props) => { const { register, watch } = useForm() const selectedItems = watch("departments") selectedItems && console.log("Selected Items", selectedItems) return ( <div> <MultiLevelSelect id="multiselect-default" marginBottom="md" treeData={treeData} {...register("departments")} /> </div> ) } export default MultiLevelSelectReactHook
Optionally enable the single variant to replace checkboxes with radios so the input accepts and returns only a single selection.
import React from "react"; import { MultiLevelSelect } from 'playbook-ui' const treeData = [ { label: "HQ", value: "hQ", id: "hq", }, { label: "Philadelphia", value: "philadelphia", id: "phl", children: [ { label: "Marketing & Sales PHL", value: "marketingAndSalesPhl", id: "marketingPHL", }, { label: "Installation Office PHL", value: "installationOfficePhl", id: "installationPHL", }, { label: "Warehouse PHL", value: "warehousePhl", id: "warehousePHL", }, ] }, { label: "New Jersey", value: "newJersey", id: "nj", children: [ { label: "New Jersey", value: "newJersey", id: "nj1", children: [ { label: "Marketing & Sales NJ", value: "marketingAndSalesNj", id: "marketingNJ", }, { label: "Installation Office NJ", value: "installationOfficeNj", id: "installationNJ", }, { label: "Warehouse NJ", value: "warehouseNj", id: "warehouseNJ", }, ], }, { label: "Princeton", value: "princeton", id: "princeton", children: [ { label: "Marketing & Sales Princeton", value: "marketingAndSalesPrinceton", id: "marketingPR", }, { label: "Installation Office Princeton", value: "installationOfficePrinceton", id: "installationPR", }, { label: "Warehouse Princeton", value: "warehousePrinceton", id: "warehousePR", }, ] }, ] }, { label: "Maryland", value: "maryland", id: "MD", children: [ { label: "Marketing & Sales MD", value: "marketingAndSalesMd", id: "marketingMD", }, { label: "Installation Office MD", value: "installationOfficeMd", id: "installationMD", }, { label: "Warehouse MD", value: "warehouseMd", id: "warehouseMD", }, ] }, { label: "Connecticut", value: "connecticut", id: "CT", children: [ { label: "Marketing & Sales CT", value: "marketingAndSalesCt", id: "marketingCT", }, { label: "Installation Office CT", value: "installationOfficeCt", id: "installationCT", }, { label: "Warehouse CT", value: "warehouseCt", id: "warehouseCT", }, ] }, ]; const MultiLevelSelectSingle = (props) => { return ( <div> <MultiLevelSelect id="multiselect-single" inputName="Power" onSelect={(selectedNode) => console.log("Selected Node", selectedNode)} treeData={treeData} variant="single" /> </div> ) }; export default MultiLevelSelectSingle;
Dynamically control your selectable options by passing hideRadio: true to any node within your tree data to omit that node's radio selector. In this example we've hidden all radios except ultimate children (nodes without descendants).
import React from "react"; import { MultiLevelSelect } from 'playbook-ui' const treeData = [ { label: "HQ", value: "hQ", id: "hq1", }, { label: "Philadelphia", value: "philadelphia", id: "phl1", hideRadio: true, children: [ { label: "Marketing & Sales PHL", value: "marketingAndSalesPhl", id: "marketingPHL1", }, { label: "Installation Office PHL", value: "installationOfficePhl", id: "installationPHL1", }, { label: "Warehouse PHL", value: "warehousePhl", id: "warehousePHL1", }, ] }, { label: "New Jersey", value: "newJersey", id: "nj2", hideRadio: true, children: [ { label: "New Jersey", value: "newJersey", id: "nj3", hideRadio: true, children: [ { label: "Marketing & Sales NJ", value: "marketingAndSalesNj", id: "marketingNJ1", }, { label: "Installation Office NJ", value: "installationOfficeNj", id: "installationNJ1", }, { label: "Warehouse NJ", value: "warehouseNj", id: "warehouseNJ1", }, ], }, { label: "Princeton", value: "princeton", id: "princeton1", hideRadio: true, children: [ { label: "Marketing & Sales Princeton", value: "marketingAndSalesPrinceton", id: "marketingPR1", }, { label: "Installation Office Princeton", value: "installationOfficePrinceton", id: "installationPR1", }, { label: "Warehouse Princeton", value: "warehousePrinceton", id: "warehousePR1", }, ] }, ] }, { label: "Maryland", value: "maryland", id: "MD1", hideRadio: true, children: [ { label: "Marketing & Sales MD", value: "marketingAndSalesMd", id: "marketingMD1", }, { label: "Installation Office MD", value: "installationOfficeMd", id: "installationMD1", }, { label: "Warehouse MD", value: "warehouseMd", id: "warehouseMD1", }, ] }, { label: "Connecticut", value: "connecticut", id: "CT1", hideRadio: true, children: [ { label: "Marketing & Sales CT", value: "marketingAndSalesCt", id: "marketingCT1", }, { label: "Installation Office CT", value: "installationOfficeCt", id: "installationCT1", }, { label: "Warehouse CT", value: "warehouseCt", id: "warehouseCT1", }, ] }, ]; const MultiLevelSelectSingleChildrenOnly = (props) => { return ( <div> <MultiLevelSelect id="multiselect-single-children-only" inputName="PowerChildren" onSelect={(selectedNode) => console.log("Selected Node", selectedNode)} treeData={treeData} variant="single" /> </div> ) }; export default MultiLevelSelectSingleChildrenOnly;
The returnAllSelected or return_all_selected prop can be used when users want data on all checked nodes from the dropdown, irrespective of whether it is a parent or child node.
NOTE: This variant also does not automatically uncheck the parent when any of the child nodes are unchecked. returnAllSelected is set to false by default.
NOTE: For larger trees that may return many pill selections, you can optionally set input_display: "none"(for Rails) or inputDisplay = "none"(for React) to hide all pills within the input.
import React from "react"; import { MultiLevelSelect } from 'playbook-ui' const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1", }, { label: "Business Affairs", value: "businessAffairs", id: "business1", children: [ { label: "Initiatives", value: "initiatives", id: "initiative1", }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1", }, ], }, { label: "People Experience", value: "peopleExperience", id: "experience1", }, ], }, { label: "Contact Center", value: "contactCenter", id: "contact1", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1", }, { label: "Customer Service", value: "customerService", id: "customer1", }, { label: "Energy", value: "energy", id: "energy1", }, ], }, ], }, ]; const MultiLevelSelectReturnAllSelected = (props) => { return ( <div> <MultiLevelSelect id="multi-level-select-return-all-selected" onSelect={(selectedNodes) => console.log("Selected Items with Return All Selected Data", selectedNodes) } returnAllSelected treeData={treeData} /> </div> ); }; export default MultiLevelSelectReturnAllSelected;
Use the inputDisplay/input_display prop to optionally display only the count in the display as opposed to multiple pills. This prop is set to 'pills' by default.
NOTE: inputDisplay/input_display is particularly useful for larger trees that may return many pill selections, helping to keep the input field clean and compact. This prop should not be used with the Single Select variant.
import React from "react"; import { MultiLevelSelect } from 'playbook-ui' const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", expanded: true, children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1", }, { label: "Business Affairs", value: "businessAffairs", id: "business1", children: [ { label: "Initiatives", value: "initiatives", id: "initiative1", }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1", }, ], }, { label: "People Experience", value: "peopleExperience", id: "experience1", }, ], }, { label: "Contact Center", value: "contactCenter", id: "contact1", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1", }, { label: "Customer Service", value: "customerService", id: "customer1", }, { label: "Energy", value: "energy", id: "energy1", }, ], }, ], }, ]; const MultiLevelSelectInputDisplay = (props) => { return ( <MultiLevelSelect id="multi-level-select-input-display-none" inputDisplay="none" onSelect={(selectedNodes) => console.log("Selected Items", selectedNodes) } returnAllSelected treeData={treeData} /> ); }; export default MultiLevelSelectInputDisplay;
selected_ids is an optional prop that accepts an array of ids and controls the selected state of the tree nodes that match the values passed. When used within react-hook-form, this prop can be used to manage the selected state of any ids passed to it.
Items that include checked:true on the treeData itself will also be selected on page load, even without being passed to selectedIds.
When an item is marked as checked on page load by any means, the dropdown will expand to show the checked items for easier accessibility.
When using selectedIds and variant="single" together (see single select doc examples), the selectedIds array should contain only one id, because only one item can be selected and displayed at a time. If the selectedIds array has multiple ids in it, the first id in the array will be the treeData node checked upon page load.
import React from "react"; import { MultiLevelSelect } from 'playbook-ui' const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1", }, { label: "Business Affairs", value: "businessAffairs", id: "business1", children: [ { label: "Initiatives", value: "initiatives", id: "initiative1", }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1", }, ], }, { label: "People Experience", value: "peopleExperience", id: "experience1", }, ], }, { label: "Contact Center", value: "contactCenter", id: "contact1", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1", }, { label: "Customer Service", value: "customerService", id: "customer1", }, { label: "Energy", value: "energy", id: "energy1", }, ], }, ], }, ]; const MultiLevelSelectSelectedIdsReact = (props) => { return ( <div> <MultiLevelSelect id="multi-level-select-selected_ids" onSelect={(selectedNodes) => console.log("Selected Items with Return All Selected Data", selectedNodes) } returnAllSelected selectedIds={["energy1", "talent1"]} treeData={treeData} /> </div> ); }; export default MultiLevelSelectSelectedIdsReact;
Change the form pill color by passing the optional pillColor prop. Product, Data, and Status colors are available options. Check them out here in the Form Pill colors example.
import React from "react"; import { MultiLevelSelect } from 'playbook-ui' const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", expanded: true, children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1", }, { label: "Business Affairs", value: "businessAffairs", id: "business1", children: [ { label: "Initiatives", value: "initiatives", id: "initiative1", }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1", }, ], }, { label: "People Experience", value: "peopleExperience", id: "experience1", }, ], }, { label: "Contact Center", value: "contactCenter", id: "contact1", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1", }, { label: "Customer Service", value: "customerService", id: "customer1", }, { label: "Energy", value: "energy", id: "energy1", }, ], }, ], }, ]; const MultiLevelSelectColor = (props) => { return ( <div> <MultiLevelSelect id='multiselect-color' onSelect={(selectedNodes) => console.log( "Selected Items", selectedNodes ) } pillColor="neutral" treeData={treeData} /> </div> ) }; export default MultiLevelSelectColor;
The MultiLevelSelect also provides a subcomponent structure which can be used to render children to the right of the Checkboxes and their labels. As seen in the code snippet below, these children have access to the current item being iterated over which can be used for conditional rendering.
import React from "react"; import { MultiLevelSelect, Badge } from 'playbook-ui' const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", expanded: true, status: "active", children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1", }, { label: "Business Affairs", value: "businessAffairs", id: "business1", status: "active", variant: "primary", children: [ { label: "Initiatives", value: "initiatives", id: "initiative1", }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1", status: "Inactive", }, ], }, { label: "People Experience", value: "peopleExperience", id: "experience1", }, ], }, { label: "Contact Center", value: "contactCenter", id: "contact1", status: "Inactive", variant: "error", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1", }, { label: "Customer Service", value: "customerService", id: "customer1", }, { label: "Energy", value: "energy", id: "energy1", }, ], }, ], }, ]; const MultiLevelSelectWithChildren = (props) => { return ( <div> <MultiLevelSelect id="multiselect-with-children" onSelect={(selectedNodes) => console.log("Selected Items", selectedNodes) } treeData={treeData} > <MultiLevelSelect.Options> {(item) => ( <Badge marginLeft="sm" text={item.status} variant={item.status === "active" ? "success" : "warning"} /> )} </MultiLevelSelect.Options> </MultiLevelSelect> </div> ); }; export default MultiLevelSelectWithChildren;
The MultiLevelSelect subcomponent structure is also available in the 'Single Select' variant. In this variant, the children will be rendered to the right of the Radios and their labels.
import React from "react"; import { MultiLevelSelect, Badge } from 'playbook-ui' const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", expanded: true, status: "active", children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1", }, { label: "Business Affairs", value: "businessAffairs", id: "business1", status: "active", variant: "primary", children: [ { label: "Initiatives", value: "initiatives", id: "initiative1", }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1", status: "Inactive", }, ], }, { label: "People Experience", value: "peopleExperience", id: "experience1", }, ], }, { label: "Contact Center", value: "contactCenter", id: "contact1", status: "Inactive", variant: "error", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1", }, { label: "Customer Service", value: "customerService", id: "customer1", }, { label: "Energy", value: "energy", id: "energy1", }, ], }, ], }, ]; const MultiLevelSelectWithChildrenWithRadios = (props) => { return ( <div> <MultiLevelSelect id="multiselect-with-children" onSelect={(selectedNodes) => console.log("Selected Items", selectedNodes) } treeData={treeData} variant="single" > <MultiLevelSelect.Options> {(item) => ( <Badge marginLeft="sm" text={item.status} variant={item.status === "active" ? "success" : "warning"} /> )} </MultiLevelSelect.Options> </MultiLevelSelect> </div> ); }; export default MultiLevelSelectWithChildrenWithRadios;
The MultiLevelSelect component optionally accepts a label prop to produce a label above the input.
Add an id to wire the label to the input so that clicking the label will move focus directly to the input, and open the drop-down.
import React from "react"; import { MultiLevelSelect } from 'playbook-ui' const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", expanded: true, children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1", }, { label: "Business Affairs", value: "businessAffairs", id: "business1", children: [ { label: "Initiatives", value: "initiatives", id: "initiative1", }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1", }, ], }, { label: "People Experience", value: "peopleExperience", id: "experience1", }, ], }, { label: "Contact Center", value: "contactCenter", id: "contact1", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1", }, { label: "Customer Service", value: "customerService", id: "customer1", }, { label: "Energy", value: "energy", id: "energy1", }, ], }, ], }, ]; const MultiLevelSelectDefault = (props) => { return ( <div> <MultiLevelSelect id="select_a_department" label="Select a Department" onSelect={(selectedNodes) => console.log("Selected Items", selectedNodes) } treeData={treeData} /> </div> ) }; export default MultiLevelSelectDefault;
import React, { useState, useEffect } from "react"; import { MultiLevelSelect } from 'playbook-ui' const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", expanded: true, children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1", }, { label: "Business Affairs", value: "businessAffairs", id: "business1", children: [ { label: "Initiatives", value: "initiatives", id: "initiative1", }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1", }, ], }, { label: "People Experience", value: "peopleExperience", id: "experience1", }, ], }, { label: "Contact Center", value: "contactCenter", id: "contact1", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1", }, { label: "Customer Service", value: "customerService", id: "customer1", }, { label: "Energy", value: "energy", id: "energy1", }, ], }, ], }, ]; const MultiLevelSelectError = (props) => { const [selectedItems, setSelectedItems] = useState([]); const [errorState, setErrorState] = useState("Please make a valid selection"); useEffect(() => { if (selectedItems.length === 0) { setErrorState("Please make a valid selection"); } else { setErrorState(null); } }, [selectedItems]); return ( <div> <MultiLevelSelect error={errorState} id="multiselect-error" onSelect={(selectedNodes) => setSelectedItems(selectedNodes)} treeData={treeData} /> </div> ); }; export default MultiLevelSelectError;
import React from "react"; import { MultiLevelSelect } from 'playbook-ui' const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", expanded: true, children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1", }, { label: "Business Affairs", value: "businessAffairs", id: "business1", children: [ { label: "Initiatives", value: "initiatives", id: "initiative1", }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1", }, ], }, { label: "People Experience", value: "peopleExperience", id: "experience1", }, ], }, { label: "Contact Center", value: "contactCenter", id: "contact1", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1", }, { label: "Customer Service", value: "customerService", id: "customer1", }, { label: "Energy", value: "energy", id: "energy1", }, ], }, ], }, ]; const MultiLevelSelectDisabled = (props) => { return ( <> <MultiLevelSelect disabled id='multiselect-default' onSelect={(selectedNodes) => console.log( "Selected Items", selectedNodes ) } treeData={treeData} /> </> ) }; export default MultiLevelSelectDisabled
To disable individual items in the treeData, include disabled:true within the object on the treeData that you want disabled. See the code snippet below for an example of how to do this.
If a parent is selected, the parent will be returned in the selected items list, even if it has disabled children.
import React from "react"; import { MultiLevelSelect } from 'playbook-ui' const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", expanded: true, children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1", disabled: true, }, { label: "Business Affairs", value: "businessAffairs", id: "business1", children: [ { label: "Initiatives", value: "initiatives", id: "initiative1", disabled: true, }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1", }, ], }, { label: "People Experience", value: "peopleExperience", id: "experience1", }, ], }, { label: "Contact Center", value: "contactCenter", id: "contact1", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1", }, { label: "Customer Service", value: "customerService", id: "customer1", disabled: true, }, { label: "Energy", value: "energy", id: "energy1", }, ], }, ], }, ]; const MultiLevelSelectDisabledOptionsDefault = (props) => { return ( <div> <MultiLevelSelect id='multiselect-disabled-options-default' onSelect={(selectedNodes) => console.log( "Selected Items", selectedNodes ) } treeData={treeData} /> </div> ) }; export default MultiLevelSelectDisabledOptionsDefault;
Individual items can also be disabled by including the disabled:true within the object on the treeData for the returnAllSelected/return_all_selected variant. As noted above, this variant will return data on all checked nodes from the dropdown, irrespective of whether it is a parent or child node.
import React from "react"; import { MultiLevelSelect } from 'playbook-ui' const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", expanded: true, children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1", disabled: true, }, { label: "Business Affairs", value: "businessAffairs", id: "business1", children: [ { label: "Initiatives", value: "initiatives", id: "initiative1", disabled: true, }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1", }, ], }, { label: "People Experience", value: "peopleExperience", id: "experience1", }, ], }, { label: "Contact Center", value: "contactCenter", id: "contact1", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1", }, { label: "Customer Service", value: "customerService", id: "customer1", disabled: true, }, { label: "Energy", value: "energy", id: "energy1", }, ], }, ], }, ]; const MultiLevelSelectDisabledOptions = (props) => { return ( <div> <MultiLevelSelect id='multiselect-disabled-options' onSelect={(selectedNodes) => console.log( "Selected Items", selectedNodes ) } returnAllSelected treeData={treeData} /> </div> ) }; export default MultiLevelSelectDisabledOptions;
For the default variant, disabling the parent item will automatically disable it's children as well.
If you want to be able to disable a parent WITHOUT disabling it's children, use the returnAllSelected/return_all_selected variant.
import React from "react"; import { MultiLevelSelect } from 'playbook-ui' const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", expanded: true, children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1", }, { label: "Business Affairs", value: "businessAffairs", id: "business1", expanded: true, disabled: true, children: [ { label: "Initiatives", value: "initiatives", id: "initiative1", }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1", }, ], }, { label: "People Experience", value: "peopleExperience", id: "experience1", }, ], }, { label: "Contact Center", value: "contactCenter", id: "contact1", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1", }, { label: "Customer Service", value: "customerService", id: "customer1", }, { label: "Energy", value: "energy", id: "energy1", }, ], }, ], }, ]; const MultiLevelSelectDisabledOptionsParentDefault = (props) => { return ( <div> <MultiLevelSelect id='multiselect-disabled-options-parent-default' onSelect={(selectedNodes) => console.log( "Selected Items", selectedNodes ) } treeData={treeData} /> </div> ) }; export default MultiLevelSelectDisabledOptionsParentDefault;
For the returnAllSelected/return_all_selected variant, disabling the parent item will NOT automatically disable it's children since this version allows you to select a parent even if all children are unselected.
You can manually pass disabled:true to any and all children of a disabled parent if you want to do so.
import React from "react"; import { MultiLevelSelect } from 'playbook-ui' const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", expanded: true, children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1", }, { label: "Business Affairs", value: "businessAffairs", id: "business1", expanded: true, disabled: true, children: [ { label: "Initiatives", value: "initiatives", id: "initiative1", }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1", }, ], }, { label: "People Experience", value: "peopleExperience", id: "experience1", }, ], }, { label: "Contact Center", value: "contactCenter", id: "contact1", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1", }, { label: "Customer Service", value: "customerService", id: "customer1", }, { label: "Energy", value: "energy", id: "energy1", }, ], }, ], }, ]; const MultiLevelSelectDisabledOptionsParent = (props) => { return ( <div> <MultiLevelSelect id='multiselect-disabled-options-parent' onSelect={(selectedNodes) => console.log( "Selected Items", selectedNodes ) } returnAllSelected treeData={treeData} /> </div> ) }; export default MultiLevelSelectDisabledOptionsParent;
Individual items can be disabled by including disabled: true within the object on the treeData for the single variant. Disabled options are visibly disabled in the dropdown UI and cannot be selected via mouse click or keyboard navigation. When a parent node is disabled, all of its children are automatically disabled as well.
import React from "react"; import { MultiLevelSelect } from 'playbook-ui' const treeData = [ { label: "HQ", value: "hQ", id: "hq2", }, { label: "Philadelphia", value: "philadelphia", id: "phl2", disabled: true, children: [ { label: "Marketing & Sales PHL", value: "marketingAndSalesPhl", id: "marketingPHL2", }, { label: "Installation Office PHL", value: "installationOfficePhl", id: "installationPHL2", }, { label: "Warehouse PHL", value: "warehousePhl", id: "warehousePHL2", }, ] }, { label: "New Jersey", value: "newJersey", id: "nj2", children: [ { label: "New Jersey", value: "newJersey", id: "nj12", children: [ { label: "Marketing & Sales NJ", value: "marketingAndSalesNj", id: "marketingNJ2", disabled: true, }, { label: "Installation Office NJ", value: "installationOfficeNj", id: "installationNJ2", }, { label: "Warehouse NJ", value: "warehouseNj", id: "warehouseNJ2", }, ], }, { label: "Princeton", value: "princeton", id: "princeton2", children: [ { label: "Marketing & Sales Princeton", value: "marketingAndSalesPrinceton", id: "marketingPR2", }, { label: "Installation Office Princeton", value: "installationOfficePrinceton", id: "installationPR2", disabled: true, }, { label: "Warehouse Princeton", value: "warehousePrinceton", id: "warehousePR2", }, ] }, ] }, { label: "Maryland", value: "maryland", id: "MD2", children: [ { label: "Marketing & Sales MD", value: "marketingAndSalesMd", id: "marketingMD2", }, { label: "Installation Office MD", value: "installationOfficeMd", id: "installationMD2", }, { label: "Warehouse MD", value: "warehouseMd", id: "warehouseMD2", }, ] }, { label: "Connecticut", value: "connecticut", id: "CT2", children: [ { label: "Marketing & Sales CT", value: "marketingAndSalesCt", id: "marketingCT2", }, { label: "Installation Office CT", value: "installationOfficeCt", id: "installationCT2", }, { label: "Warehouse CT", value: "warehouseCt", id: "warehouseCT2", }, ] }, ]; const MultiLevelSelectSingleDisabled = (props) => { return ( <div> <MultiLevelSelect id="multiselect-single-disabled" inputName="Power" onSelect={(selectedNode) => console.log("Selected Node", selectedNode)} treeData={treeData} variant="single" /> </div> ) }; export default MultiLevelSelectSingleDisabled;
The requiredIndicator/required_indicator prop displays a red asterisk (*) next to the label, visually indicating that the field is required. This is purely visual and does not enforce validation.
You can use requiredIndicator/required_indicator with any validation approach: HTML5 validation via the required prop, client-side validation, or backend validation. For this reason, it works independently and doesn't need to be paired with the required prop.
import React from "react" import { MultiLevelSelect } from 'playbook-ui' const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", expanded: true, children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1" }, { label: "Business Affairs", value: "businessAffairs", id: "business1", children: [ { label: "Initiatives", value: "initiatives", id: "initiative1" }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1" } ] }, { label: "People Experience", value: "peopleExperience", id: "experience1" } ] }, { label: "Contact Center", value: "contactCenter", id: "contact1", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1" }, { label: "Customer Service", value: "customerService", id: "customer1" }, { label: "Energy", value: "energy", id: "energy1" } ] } ] } ] const MultiLevelSelectRequiredIndicator = (props) => { return ( <div> <MultiLevelSelect id="select_a_department" label="Select a Department" onSelect={(selectedNodes) => console.log("Selected Items", selectedNodes)} requiredIndicator treeData={treeData} /> </div> ) } export default MultiLevelSelectRequiredIndicator
When a parent resets a Multi Level Select (e.g., “Default” or “Clear”), the kit needs a key that changes with the selection because React uses the key to determine component identity and whether to preserve internal state. If the key doesn’t change, React reuses the existing instance and may keep showing the old selection instead of resetting to the new one.
import React, { useState } from "react"; import { MultiLevelSelect, Button } from 'playbook-ui' ; const treeData = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "100", expanded: true, children: [ { label: "People", value: "people", id: "101", expanded: true, children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "102", }, { label: "Business Affairs", value: "businessAffairs", id: "103", children: [ { label: "Initiatives", value: "initiatives", id: "104", }, { label: "Learning & Development", value: "learningAndDevelopment", id: "105", }, ], }, { label: "People Experience", value: "peopleExperience", id: "106", }, ], }, { label: "Contact Center", value: "contactCenter", id: "107", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "108", }, { label: "Customer Service", value: "customerService", id: "109", }, { label: "Energy", value: "energy", id: "110", }, ], }, ], }, ]; const MultiLevelSelectReactResetKey = (props) => { const [resetKey, setResetKey] = useState(0); const handleReset = () => { setResetKey((k) => k + 1); }; return ( <> <MultiLevelSelect id="multi-level-select-reset-example" key={`multi-level-select-reset-${resetKey}`} name="my_array" returnAllSelected treeData={treeData} /> <Button id="multilevelselect-reset-button" marginTop="lg" onClick={handleReset} text="Reset" /> </> ); }; export default MultiLevelSelectReactResetKey;
Use the placeholder prop to customize the initial text shown in the input when nothing is selected. The default is Start typing....
import React from "react"; import { MultiLevelSelect } from 'playbook-ui' const treeTemplate = [ { label: "Power Home Remodeling", value: "powerHomeRemodeling", id: "powerhome1", expanded: true, children: [ { label: "People", value: "people", id: "people1", expanded: true, children: [ { label: "Talent Acquisition", value: "talentAcquisition", id: "talent1", }, { label: "Business Affairs", value: "businessAffairs", id: "business1", children: [ { label: "Initiatives", value: "initiatives", id: "initiative1", }, { label: "Learning & Development", value: "learningAndDevelopment", id: "development1", }, ], }, { label: "People Experience", value: "peopleExperience", id: "experience1", }, ], }, { label: "Contact Center", value: "contactCenter", id: "contact1", children: [ { label: "Appointment Management", value: "appointmentManagement", id: "appointment1", }, { label: "Customer Service", value: "customerService", id: "customer1", }, { label: "Energy", value: "energy", id: "energy1", }, ], }, ], }, ]; function prefixTreeIds(nodes, prefix) { return nodes.map((node) => ({ ...node, id: `${prefix}${node.id}`, children: node.children && node.children.length > 0 ? prefixTreeIds(node.children, prefix) : node.children, })); } const treeDataMulti = prefixTreeIds(treeTemplate, "phm_"); const treeDataReturnAll = prefixTreeIds(treeTemplate, "phr_"); const treeDataSingle = prefixTreeIds(treeTemplate, "phs_"); const MultiLevelSelectPlaceholder = () => ( <> <MultiLevelSelect id="multi-level-select-placeholder-multi" label="Multi (default)" marginBottom="sm" name="placeholder_multi" onSelect={(selectedNodes) => console.log("Multi — default", selectedNodes) } placeholder="Search or choose options…" treeData={treeDataMulti} /> <MultiLevelSelect id="multi-level-select-placeholder-return-all" label="Multi (return all selected)" marginBottom="sm" name="placeholder_return_all" onSelect={(selectedNodes) => console.log("Multi — return all selected", selectedNodes) } placeholder="Departments..." returnAllSelected treeData={treeDataReturnAll} /> <MultiLevelSelect id="multi-level-select-placeholder-single" label="Single" name="placeholder_single" onSelect={(selectedNodes) => console.log("Single", selectedNodes) } placeholder="Select one option…" treeData={treeDataSingle} variant="single" /> </> ); export default MultiLevelSelectPlaceholder;
import React from 'react' import { Select } from 'playbook-ui' const SelectDefault = (props) => { const options = [ { value: '1', text: 'Burgers', }, { value: '2', text: 'Pizza', }, { value: '3', text: 'Tacos', }, ] return ( <div> <Select label="Favorite Food" name="food" options={options} /> </div> ) } export default SelectDefault
import React from 'react' import { Select } from 'playbook-ui' const SelectBlank = (props) => { const options = [ { value: 'USA' }, { value: 'Canada' }, { value: 'Brazil' }, { value: 'Philippines' }, ] return ( <div> <Select blankSelection="Select One..." label="Where do you live" name="location" options={options} /> </div> ) } export default SelectBlank
import React from 'react' import { Select } from 'playbook-ui' const SelectDisabledOptions = (props) => { const options = [ { value: '1', disabled: true, text: 'Espresso', }, { value: '2', text: 'Americano', }, { value: '3', disabled: true, text: 'Cappuccino', }, { value: '4', text: 'Mocha', }, { value: '5', text: 'Flat White', }, { value: '6', text: 'Latte', }, ] return ( <div> <Select label="Favorite Coffee" name="coffee" options={options} value="2" /> </div> ) } export default SelectDisabledOptions
import React from 'react' import { Select } from 'playbook-ui' const SelectDisabled = (props) => { const options = [ { value: 'Apple Pie' }, { value: 'Cookies' }, { value: 'Ice Cream' }, { value: 'Brownies' }, ] return ( <div> <Select disabled label="Favorite Dessert" name="dessert" options={options} /> </div> ) } export default SelectDisabled
import React from 'react' import { Select } from 'playbook-ui' const SelectRequired = (props) => { const options = [ { value: 'Left' }, { value: 'Right' }, { value: 'I go without laces' }, ] return ( <div> <Select blankSelection="Select One..." label="Which shoe do you tie first?" name="shoe" options={options} required /> </div> ) } export default SelectRequired
import React from 'react' import { Select } from 'playbook-ui' const SelectValueTextSame = (props) => { const options = [ { value: 'Football' }, { value: 'Baseball' }, { value: 'Basketball' }, { value: 'Hockey' }, ] return ( <div> <Select label="Favorite Sport" name="sports" options={options} /> </div> ) } export default SelectValueTextSame
import React from 'react' import { Select } from 'playbook-ui' const SelectCustomSelect = (props) => { return ( <div> <Select label="Favorite Holiday" > <select id="holiday" name="holiday" > <option value="1">{'Christmas'}</option> <option value="2">{'Thanksgiving'}</option> <option value="3">{'Halloween'}</option> <option value="4">{'Fourth of July'}</option> </select> </Select> </div> ) } export default SelectCustomSelect
To create a select with non-selectable subheaders, use a Custom Select component to render a native <select> containing <optgroup> elements. The optgroup HTML element groups related options under a non-selectable label in the dropdown.
import React from 'react' import { Select } from 'playbook-ui' const SelectCustomSelectSubheaders = (props) => { return ( <div> <Select label="Favorite Animal" > <select id="animal" name="animal" > <optgroup label="Mammal"> <option value="1">{'Cat'}</option> <option value="2">{'Dog'}</option> </optgroup> <optgroup label="Amphibian"> <option value="3">{'Frog'}</option> <option value="4">{'Salamander'}</option> </optgroup> </select> </Select> </div> ) } export default SelectCustomSelectSubheaders
Select w/ Error shows that an option must be selected or is invalid (i.e. when used in a form it signals a user to fix an error).
import React from 'react' import { Body, Select, Icon } from 'playbook-ui' const SelectError = (props) => { const options = [ { value: '1', text: 'Burgers', }, { value: '2', text: 'Pizza', }, { value: '3', text: 'Tacos', }, ] const error = (<> <Icon icon="warning" /> Please make a valid selection </>) return ( <div> <Select error={error} label="Favorite Food" name="food" options={options} value="2" /> <Body error={error} status="negative" /> </div> ) } export default SelectError
import React from 'react' import { Body, Select } from 'playbook-ui' const SelectInline = (props) => { const options = [ { value: '1', text: 'Burgers', }, { value: '2', text: 'Pizza', }, { value: '3', text: 'Tacos', }, ] return ( <div> <Select inline label="Favorite Food" name="food" options={options} /> <Body status="negative" /> </div> ) } export default SelectInline
import React from 'react' import { Body, Select } from 'playbook-ui' const SelectInlineShowArrow = (props) => { const options = [ { value: '1', text: 'Burgers', }, { value: '2', text: 'Pizza', }, { value: '3', text: 'Tacos', }, ] return ( <div> <Select inline label="Favorite Food" name="food" options={options} showArrow /> <Body status="negative" /> </div> ) } export default SelectInlineShowArrow
import React from 'react' import { Body, Select } from 'playbook-ui' const SelectInlineCompact = (props) => { const options = [ { value: '1', text: 'Burgers', }, { value: '2', text: 'Pizza', }, { value: '3', text: 'Tacos', }, ] return ( <div> <Select compact inline label="Favorite Food" name="food" options={options} /> <Body status="negative" /> </div> ) } export default SelectInlineCompact
The multiple prop enables multiple selections; however, for a better user experience, we recommend our Typeahead kit.
import React from 'react' import { Select } from 'playbook-ui' const SelectMultiple = (props) => { const options = [ { value: '1', text: 'Burgers', }, { value: '2', text: 'Pizza', }, { value: '3', text: 'Tacos', }, { value: '3', text: 'BBQ', }, { value: '3', text: 'Sushi', }, { value: '3', text: 'Chinese', }, { value: '3', text: 'Hot Dogs', }, ] return ( <div> <Select label="Favorite Food" multiple name="food" options={options} /> </div> ) } export default SelectMultiple
You can pass react-hook-form props to a select kit. You can use register which will make the value available for both the form validation and submission.
import React, { useState } from "react" import { Select, Body, Button } from 'playbook-ui'import { useForm } from "react-hook-form" const SelectReactHook = (props) => { const { register, handleSubmit, formState: { errors } } = useForm({ defaultValues: { food: '', }, }) const [submittedData, setSubmittedData] = useState({ food: '', }) const onSubmit = (data) => { setSubmittedData(data) } const options = [ { value: 1, text: 'Burgers', }, { value: 2, text: 'Pizza', }, { value: 3, text: 'Tacos', }, ] return ( <> <form onSubmit={handleSubmit(onSubmit)}> <Select {...register("food", { required: true })} error={errors.food ? "Please select a food." : null} label="Favorite Food" options={options} /> <br /> <Button htmlType="submit" marginTop="sm" text="Submit" /> </form> <Body padding="xs" text={`Food: ${submittedData.food}`} /> </> ) } export default SelectReactHook
Use the input_options / inputOptions prop to pass additional attributes directly to the underlying <select> element instead of the outer wrapper. This is useful for applying data attributes, custom IDs, or other HTML attributes that need to be on the select element itself.
import React from 'react' import { Select } from 'playbook-ui' const SelectInputOptions = (props) => { const options = [ { value: 'pizza', text: 'Pizza' }, { value: 'tacos', text: 'Tacos' }, { value: 'sushi', text: 'Sushi' }, ] return ( <> <Select inputOptions={{ 'aria-label': 'Select your favorite food', className: 'custom-select-class', id: 'favorite-food-select', }} label="Favorite Food" name="favorite_food" options={options} /> </> ) } export default SelectInputOptions
The requiredIndicator/required_indicator prop displays a red asterisk (*) next to the label, visually indicating that the field is required. This is purely visual and does not enforce validation.
You can use requiredIndicator/required_indicator with any validation approach: HTML5 validation via the required prop, client-side validation, or backend validation. For this reason, it works independently and doesn't need to be paired with the required prop.
import React from "react"; import { Select } from 'playbook-ui'; const SelectRequiredIndicator = () => { const options = [ { value: "1", text: "Popcorn", }, { value: "2", text: "Chips", }, { value: "3", text: "Twizzlers", }, ]; return ( <div> <Select label="Favorite Snack" name="food" options={options} requiredIndicator /> </div> ); }; export default SelectRequiredIndicator;
Default Selectable Cards are multi select by default.
import React, { useState } from 'react' import { SelectableCard } from 'playbook-ui' const SelectableCardDefault = (props) => { const [selectedWithIcon, setSelectedWithIcon] = useState(true) const [selectedNoIcon, setSelectedNoIcon] = useState(true) const [unselected, setUnselected] = useState(false) const [disabled, setDisabled] = useState(false) return ( <div className="pb--doc-demo-row"> <SelectableCard checked={selectedWithIcon} icon inputId="selectedWithIcon" name="selectedWithIcon" onChange={() => setSelectedWithIcon(!selectedWithIcon)} value="selectedWithIcon" > {'Selected, with icon'} </SelectableCard> <SelectableCard checked={selectedNoIcon} inputId="selectedWithoutIcon" name="selectedWithoutIcon" onChange={() => setSelectedNoIcon(!selectedNoIcon)} value="selectedWithoutIcon" > {'Selected, without icon'} </SelectableCard> <SelectableCard checked={unselected} inputId="unselected" name="unselected" onChange={() => setUnselected(!unselected)} value="unselected" > {'Unselected'} </SelectableCard> <SelectableCard checked={disabled} disabled inputId="disabled" name="disabled" onChange={() => setDisabled(!disabled)} value="disabled" > {'Disabled'} </SelectableCard> </div> ) } export default SelectableCardDefault
Single Select allows only one selectable card in the set to be selected.
import React, { useState } from 'react' import { SelectableCard } from 'playbook-ui' const SelectableCardSingleSelect = (props) => { const [selected, setSelected] = useState(null) const handleSelect = (event) => { setSelected(event.target.value) } return ( <div className="pb--doc-demo-row"> <SelectableCard checked={selected === 'male'} inputId="male1" multi={false} name="gender" onChange={handleSelect} value="male" > {'Male'} </SelectableCard> <SelectableCard checked={selected === 'female'} inputId="female1" multi={false} name="gender" onChange={handleSelect} value="female" > {'Female'} </SelectableCard> <SelectableCard checked={selected === 'other'} inputId="other1" multi={false} name="gender" onChange={handleSelect} value="other" > {'Other'} </SelectableCard> </div> ) } export default SelectableCardSingleSelect
Selectable Cards can pass text or block content.
import React, { useState } from 'react' import { SelectableCard, Body, Title } from 'playbook-ui' const SelectableCardBlock = (props) => { const [block, setBlock] = useState(true) const [tag, setTag] = useState(false) const handleSelect = (event) => { setBlock(event.target.checked) } const handleTag = (event) => { setTag(event.target.checked) } return ( <div className="pb--doc-demo-row"> <SelectableCard checked={block} inputId="block" name="block" onChange={handleSelect} value="block" > <Title size={4} text="Block" /> <Body tag="span" > {'This uses block'} </Body> </SelectableCard> <SelectableCard checked={tag} inputId="tag" name="tag" onChange={handleTag} text="This passes text through the tag" value="tag" /> </div> ) } export default SelectableCardBlock
Selectable Cards can pass images with optional text.
import React, { useState } from 'react' import { Body, Image, SelectableCard } from 'playbook-ui' const SelectableCardImage = (props) => { const [selectedImage, setSelectedImage] = useState(true) const [unselectedImage, setUnselectedImage] = useState(false) return ( <div className="pb--doc-demo-row"> <SelectableCard checked={selectedImage} icon inputId="selectableImage" name="selectableImage" onChange={() => setSelectedImage(!selectedImage)} value="selectableImage" > <Image rounded size="xl" url="https://unsplash.it/500/400/?image=634" /> <Body>{'Add text here'}</Body> </SelectableCard> <SelectableCard checked={unselectedImage} icon inputId="unselectedImage" name="unselectedImage" onChange={() => setUnselectedImage(!unselectedImage)} value="unselectedImage" > <Image rounded size="xl" url="https://unsplash.it/500/400/?image=634" /> </SelectableCard> </div> ) } export default SelectableCardImage
Selectable Cards can show an input indicating state.
import React, { useState } from 'react' import { Body, SelectableCard, Title } from 'playbook-ui' const SelectableCardInput = (props) => { const [state, setState] = useState({ firstCheckbox: true, secondCheckbox: true, thirdCheckbox: false, forthCheckbox: false, radioSelected: 'first', }) const handleSelect = (event) => { setState({ ...state, [event.target.name]: event.target.checked, }) } const handleRadioSelect = (event) => { setState({ ...state, radioSelected: event.target.value, }) } return ( <> <Title size={3} text="What programming languages do you know?" /> <br /> <SelectableCard checked={state.firstCheckbox} inputId="firstCheckbox" name="firstCheckbox" onChange={handleSelect} value="firstCheckbox" variant="displayInput" > <Body>{'Ruby'}</Body> </SelectableCard> <SelectableCard checked={state.secondCheckbox} inputId="secondCheckbox" name="secondCheckbox" onChange={handleSelect} value="secondCheckbox" variant="displayInput" > <Body>{'JavaScript'}</Body> </SelectableCard> <SelectableCard checked={state.thirdCheckbox} inputId="thirdCheckbox" name="thirdCheckbox" onChange={handleSelect} value="thirdCheckbox" variant="displayInput" > <Body>{'TypeScript'}</Body> </SelectableCard> <SelectableCard checked={state.fourthCheckbox} inputId="fourthCheckbox" name="fourthCheckbox" onChange={handleSelect} value="fourthCheckbox" variant="displayInput" > <Body>{'Swift'}</Body> </SelectableCard> <br /> <Title size={3} text="How likely are you to recommend Playbook to a friend?" /> <br /> <SelectableCard checked={state.radioSelected === 'first'} inputId="radio-1" multi={false} name="radio" onChange={handleRadioSelect} value="first" variant="displayInput" > <Body>{'5'}</Body> </SelectableCard> <SelectableCard checked={state.radioSelected === 'second'} inputId="radio-2" multi={false} name="radio" onChange={handleRadioSelect} value="second" variant="displayInput" > <Body> {'4'} </Body> </SelectableCard> <SelectableCard checked={state.radioSelected === 'third'} inputId="radio-3" multi={false} name="radio" onChange={handleRadioSelect} value="third" variant="displayInput" > <Body>{'3'}</Body> </SelectableCard> <SelectableCard checked={state.radioSelected === 'fourth'} inputId="radio-4" multi={false} name="radio" onChange={handleRadioSelect} value="fourth" variant="displayInput" > <Body>{'2'}</Body> </SelectableCard> <SelectableCard checked={state.radioSelected === 'fifth'} inputId="radio-5" multi={false} name="radio" onChange={handleRadioSelect} value="fifth" variant="displayInput" > <Body>{'1'}</Body> </SelectableCard> </> ) } export default SelectableCardInput
import React, { useState } from 'react' import { Body, SelectableCard, Title } from 'playbook-ui' const SelectableCardError = (props) => { const [football, setFootball] = useState(false) const [basketball, setBasketball] = useState(false) const [baseball, setBaseball] = useState(false) return ( <div> <Title size={3} text="What sports do you like?" /> <br /> <SelectableCard checked={football} error inputId="football" name="football" onChange={() => setFootball(!football)} value="football" variant="displayInput" > <Body>{'Football'}</Body> </SelectableCard> <SelectableCard checked={basketball} error inputId="basketball" name="basketball" onChange={() => setBasketball(!basketball)} value="basketball" variant="displayInput" > <Body>{'Basketball'}</Body> </SelectableCard> <SelectableCard checked={baseball} error inputId="baseball" name="baseball" onChange={() => setBaseball(!baseball)} value="baseball" variant="displayInput" > <Body>{'Baseball'}</Body> </SelectableCard> </div> ) } export default SelectableCardError
import React, { useState } from 'react' import { SelectableCardIcon } from 'playbook-ui' const SelectableCardIconDefault = (props) => { const [selected, setSelected] = useState(true) const [unselected, setUnselected] = useState(false) return ( <div className="pb--doc-demo-row"> <SelectableCardIcon bodyText="Export" checked={selected} icon="chart-line" inputId={1} onChange={() => setSelected(!selected)} titleText="Quarterly Report" /> <SelectableCardIcon bodyText="Export" checked={unselected} icon="chart-pie" inputId={2} onChange={() => setUnselected(!unselected)} titleText="Market Share" /> <SelectableCardIcon bodyText="Export" disabled icon="analytics" inputId={3} titleText="Comprehensive" /> </div> ) } export default SelectableCardIconDefault
import React, { useState } from 'react' import { SelectableCardIcon } from 'playbook-ui' const SelectableCardIconCheckmark = (props) => { const [selected, setSelected] = useState(true) const [unselected, setUnselected] = useState(false) return ( <div className="pb--doc-demo-row"> <SelectableCardIcon bodyText="Howdy Partner." checked={selected} checkmark icon="hat-cowboy" inputId={4} onChange={() => setSelected(!selected)} titleText="Cowboy" /> <SelectableCardIcon bodyText="Poof, you're a sandwich." checked={unselected} checkmark icon="hat-wizard" inputId={5} onChange={() => setUnselected(!unselected)} titleText="Wizard" /> <SelectableCardIcon bodyText="Where is the lamb sauce?" checkmark disabled icon="hat-chef" inputId={6} titleText="Chef" /> </div> ) } export default SelectableCardIconCheckmark
import React, { useState } from 'react' import { SelectableCardIcon } from 'playbook-ui' const SelectableCardIconSingleSelect = (props) => { const [selectedFormat, toggleFormat] = useState(null) return ( <div className="pb--doc-demo-row"> <SelectableCardIcon checked={selectedFormat === 'car'} icon="car" inputId={7} name="select" onChange={() => toggleFormat('car')} titleText="Car" value="car" /> <SelectableCardIcon checked={selectedFormat === 'bus'} icon="bus" inputId={8} name="select" onChange={() => toggleFormat('bus')} titleText="Bus" value="bus" /> <SelectableCardIcon checked={selectedFormat === 'subway'} icon="subway" inputId={9} name="select" onChange={() => toggleFormat('subway')} titleText="Subway" value="subway" /> </div> ) } export default SelectableCardIconSingleSelect
When using custom icons it is important to introduce a "clean" SVG. In order to ensure these custom icons perform as intended within your kit(s), ensure these things have been modified from the original SVG markup:
Attributes must be React compatible e.g. xmlns:xlink should be xmlnsXlink and so on. There should be no hyphenated attributes and no semi-colons!.
Fill colors with regards to g or path nodes, e.g. fill="black", should be replaced with currentColor ala fill="currentColor". Your mileage may vary depending on the complexity of your SVG.
Pay attention to your custom icon's dimensions and viewBox attribute. It is best to use a viewBox="0 0 512 512" starting point when designing instead of trying to retrofit the viewbox afterwards!
You must source your own SVG into component/view you are working on. This can easily be done in programmatic and maintainable ways.
So long as you have a valid React <SVG> node, you can send it as the customIcon prop and the kit will take care of the rest.
Some Rails applications use only webpack(er) which means using image_url will be successful over image_path in most cases especially development where Webpack Dev Server is serving assets over HTTP. Rails applications still using Asset Pipeline may use image_path or image_url. Of course, YMMV depending on any custom configurations in your Rails application.
import React from 'react' import { SelectableCardIcon } from 'playbook-ui' const svg = { newChat: ( <svg ariaHidden="true" focusable="false" role="img" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" > <path d="M448 0H64C28.7 0 0 28.7 0 64v288c0 35.3 28.7 64 64 64h96v84c0 7.1 5.8 12 12 12 2.4 0 4.9-.7 7.1-2.4L304 416h144c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64zm16 352c0 8.8-7.2 16-16 16H288l-12.8 9.6L208 428v-60H64c-8.8 0-16-7.2-16-16V64c0-8.8 7.2-16 16-16h384c8.8 0 16 7.2 16 16v288zM336 184h-56v-56c0-8.8-7.2-16-16-16h-16c-8.8 0-16 7.2-16 16v56h-56c-8.8 0-16 7.2-16 16v16c0 8.8 7.2 16 16 16h56v56c0 8.8 7.2 16 16 16h16c8.8 0 16-7.2 16-16v-56h56c8.8 0 16-7.2 16-16v-16c0-8.8-7.2-16-16-16z" fill="currentColor" /> </svg> ), } const SelectableCardIconCustom = (props) => { return ( <div className="pb--doc-demo-row"> <SelectableCardIcon bodyText="Talk to someone you love" checked customIcon={svg.newChat} inputId={1} titleText="New Chat" /> </div> ) } export default SelectableCardIconCustom
import React, { useState } from 'react' import { SelectableIcon } from 'playbook-ui' const SelectableIconDefault = (props) => { const [ checkSelected, toggleSelected ] = useState(true) const [ checkUnselected, toggleUnselected ] = useState(false) const [ checkDisabled, toggleDisabled ] = useState(false) return ( <div className="pb--doc-demo-row"> <SelectableIcon checked={checkSelected} icon="dollar-sign" inputId={10} onChange={() => toggleSelected(!checkSelected)} text="US Dollar" /> <SelectableIcon checked={checkUnselected} icon="euro-sign" inputId={11} onChange={() => toggleUnselected(!checkUnselected)} text="Euro" /> <SelectableIcon checked={checkDisabled} disabled icon="yen-sign" inputId={12} onChange={() => toggleDisabled(!checkDisabled)} text="Yen" /> </div> ) } export default SelectableIconDefault
import React, { useState } from 'react' import { SelectableIcon } from 'playbook-ui' const SelectableIconSingleSelect = (props) => { const [ selectedFormat, toggleFormat ] = useState(null) return ( <div className="pb--doc-demo-row"> <SelectableIcon checked={selectedFormat === 'Cassette'} icon="cassette-tape" inputId={13} multi={false} name="music-format" onChange={() => toggleFormat('Cassette')} text="Cassette" value="Cassette" /> <SelectableIcon checked={selectedFormat === 'CD'} icon="compact-disc" inputId={14} multi={false} name="music-format" onChange={() => toggleFormat('CD')} text="CD" value="CD" /> <SelectableIcon checked={selectedFormat === 'Vinyl'} icon="album-collection" inputId={15} multi={false} name="music-format" onChange={() => toggleFormat('Vinyl')} text="Vinyl" value="Vinyl" /> </div> ) } export default SelectableIconSingleSelect
import React from 'react' import { Radio } from 'playbook-ui' const RadioDefault = (props) => { const ref = React.createRef() return ( <div> <Radio label="Power" name="Group2" ref={ref} tabIndex={0} value="Power" /> <br /> <Radio defaultChecked={false} label="Nitro" name="Group2" value="Nitro" /> <br /> <Radio defaultChecked={false} label="Google" name="Group2" value="Google" /> </div> ) } export default RadioDefault
import React, { useState } from 'react' import { Radio } from 'playbook-ui' const RadioCustom = (props) => { const [choice, setChoice] = useState('power') const handleOnChange = ({ target }) => { setChoice(target.value) } return ( <div> <p> {'Your choice is: '} <code>{choice}</code> </p> <br /> <Radio className="my_custom_class" label="Custom Power" > <input checked={choice === 'power'} name="custom" onChange={handleOnChange} type="radio" value="power" /> </Radio> <br /> <Radio className="my_custom_class" label="Custom Nitro" > <input checked={choice === 'nitro'} name="custom" onChange={handleOnChange} type="radio" value="nitro" /> </Radio> <br /> <Radio className="my_custom_class" label="Custom Google" > <input checked={choice === 'google'} name="custom" onChange={handleOnChange} type="radio" value="google" /> </Radio> </div> ) } export default RadioCustom
Error shows that the radio option must be selected or is invalid (i.e. when used in a form it signals a user to fix an error).
import React from 'react' import { Flex, Radio } from 'playbook-ui' const RadioAlignment = (props) => { return ( <Flex> <Radio alignment="vertical" label="Power" marginRight="sm" name="Group2" tabIndex={0} value="Power" /> <br /> <Radio alignment="vertical" defaultChecked={false} label="Nitro" marginRight="sm" name="Group2" value="Nitro" /> <br /> <Radio alignment="vertical" defaultChecked={false} label="Google" name="Group2" value="Google" /> </Flex> ) } export default RadioAlignment
import React from 'react' import { Radio } from 'playbook-ui' const RadioDisabled = (props) => { const ref = React.createRef() return ( <div style={{ display: "flex", flexDirection: "column" }}> <Radio disabled label="Disabled unselected" marginBottom="xs" name="DisabledGroup" ref={ref} tabIndex={0} value="Disabled unselected" /> <Radio checked disabled label="Disabled selected" name="DisabledGroup" value="Disabled selected" /> </div> ) } export default RadioDisabled
Use the custom_children prop to enable the use of kits instead of text labels.
import React from 'react' import { Radio, Select, Typeahead, Title } from 'playbook-ui' const RadioChildren = (props) => { const options = [ { label: 'Orange', value: 'Orange' }, { label: 'Red', value: 'Red' }, { label: 'Green', value: 'Green' }, { label: 'Blue', value: 'Blue' }, ] return ( <div> <Radio customChildren label="Select" marginBottom="sm" name="Group1" tabIndex={0} value="Select" > <Select marginBottom="none" minWidth="xs" options={options} /> </Radio> <Radio customChildren label="Typeahead" marginBottom="sm" name="Group1" tabIndex={0} value="Typeahead" > <Typeahead marginBottom="none" minWidth="xs" options={options} /> </Radio> <Radio customChildren defaultChecked={false} label="Typography" name="Group1" value="Typography" > <Title text="Custom Typography" /> </Radio> </div> ) } export default RadioChildren
You can pass react hook props to the radio kit.
import React from "react" import { Radio, Body, Flex } from 'playbook-ui'import { useForm } from "react-hook-form" const RadioReactHook = () => { const { register, watch } = useForm({ defaultValues: { size: "Small", }, }) const selectedSize = watch("size", "Small") return ( <Flex orientation="row"> <Flex align="start" orientation="column" paddingRight="lg" > <Radio label="Small" marginBottom='sm' name="size" value="Small" {...register("size")} /> <br /> <Radio label="Medium" marginBottom='sm' name="size" value="Medium" {...register("size")} /> <br /> <Radio label="Large" marginBottom='sm' name="size" value="Large" {...register("size")} /> </Flex> <Flex align="start" orientation="column" > <Body text={`Selected Size: ${selectedSize}`} /> </Flex> </Flex> ) } export default RadioReactHook
You can pass react hook props to the checkbox kit.
import React, { useState } from "react" import { Button, Checkbox, Flex, Body } from 'playbook-ui'import { useForm } from "react-hook-form" const CheckboxReactHook = () => { const { register, handleSubmit } = useForm({ defaultValues: { Small: false, Medium: false, Large: false, }, }) const [submittedData, setSubmittedData] = useState({ Small: false, Medium: false, Large: false, }) const onSubmit = (data) => { setSubmittedData(data) } return ( <Flex orientation="row"> <Flex align="start" orientation="column" paddingRight="lg" > <form onSubmit={handleSubmit(onSubmit)}> <Checkbox padding="xs" text="Small" {...register("Small")} /> <br /> <Checkbox padding="xs" text="Medium" {...register("Medium")} /> <br /> <Checkbox padding="xs" text="Large" {...register("Large")} /> <br /> <Button htmlType="submit" marginTop="sm" text="submit" /> </form> </Flex> <Flex align="start" orientation="column" > <Body padding="xs" text={`Small: ${submittedData.Small ? "true" : "false"}`} /> <Body padding="xs" text={`Medium: ${submittedData.Medium ? "true" : "false"}`} /> <Body padding="xs" text={`Large: ${submittedData.Large ? "true" : "false"}`} /> </Flex> </Flex> ) } export default CheckboxReactHook
import React, { useState } from 'react' import { Checkbox } from 'playbook-ui' const CheckboxCustom = (props) => { const [checked, setChecked] = useState(false) const handleOnChange = () => { setChecked(!checked) } return ( <div> {`The checkbox is ${checked ? 'checked' : 'unchecked'}.`} <br /> <br /> <div> <Checkbox text="Toggle Me" > <input checked={checked} name="custom-name" onChange={handleOnChange} type="checkbox" value="custom-value" /> </Checkbox> </div> </div> ) } export default CheckboxCustom
import React, { useState } from 'react' import { Checkbox, Table } from 'playbook-ui' const CheckboxIndeterminate = (props) => { const [checkboxes, setCheckboxes] = useState([ { name: 'Coffee', checked: false }, { name: 'Ice Cream', checked: false }, { name: 'Chocolate', checked: true }, ]) const isAllChecked = !checkboxes.find((checkbox) => !checkbox.checked) const isNoneChecked = !checkboxes.find((checkbox) => checkbox.checked) const processCheckboxes = (checked) => checkboxes.slice(0).map((checkbox) => { checkbox.checked = checked return checkbox }) const onToggleAll = () => { setCheckboxes( isNoneChecked ? processCheckboxes(true) : processCheckboxes(false) ) } const updateCheckboxes = (checkbox, index) => { const newCheckboxes = checkboxes.slice(0) newCheckboxes[index].checked = !checkbox.checked setCheckboxes(newCheckboxes) } return ( <Table container={false} size="md" > <thead> <tr> <th> <Checkbox checked={isAllChecked} indeterminate={!isAllChecked && !isNoneChecked} name="checkbox-name" onChange={onToggleAll} text={isNoneChecked ? 'Check All' : 'Uncheck All'} value="check-box value" /> </th> </tr> </thead> <tbody> {checkboxes.map((checkbox, index) => ( <tr key={index}> <td> <Checkbox checked={checkbox.checked} name={checkbox.name} onChange={() => { updateCheckboxes(checkbox, index) }} text={checkbox.name} value="check-box value" /> </td> </tr> ))} </tbody> </Table> ) } export default CheckboxIndeterminate
import React from 'react' import { Checkbox } from 'playbook-ui' const CheckboxDisabled = (props) => { return ( <div style={{ display: "flex", flexDirection: "column" }}> <Checkbox disabled marginBottom="xs" name="default name" tabIndex={0} text="Disabled unchecked" value="default value" /> <Checkbox checked disabled name="checkbox-name" text="Disabled checked" value="check-box value" /> </div> ) } export default CheckboxDisabled
import React from 'react' import { SelectableList } from 'playbook-ui' const SelectableListDefault = (props) => { return ( <div> <SelectableList variant="checkbox"> <SelectableList.Item label="Mild" name="checkbox-name-1" value="1" /> <SelectableList.Item checked label="Medium" name="checkbox-name-2" value="2" /> <SelectableList.Item label="Hot" name="checkbox-name-3" value="3" /> </SelectableList> </div> ) } export default SelectableListDefault
import React from 'react' import { SelectableList } from 'playbook-ui' const SelectableListDefault = (props) => { return ( <div> <SelectableList variant="radio"> <SelectableList.Item label="Small" name="radio" value="1" /> <SelectableList.Item defaultChecked label="Medium" name="radio" value="2" /> <SelectableList.Item label="Large" name="radio" value="3" /> </SelectableList> </div> ) } export default SelectableListDefault
Use the Time Picker for time-only selection. For date and time selection, use the DatePicker with Time Selection Enabled instead.
Set time_format / timeFormat to 24hour to display the time selection dropdown in a 24-hour format.
The default_time / defaultTime prop sets a default time value and accepts both 12-hour and 24-hour formats.
import React from 'react' import { TimePicker } from 'playbook-ui' const TimePickerDefaultTime = (props) => ( <div> <TimePicker defaultTime="2:30 PM" id="time-picker-default-time-12hr" label="12-Hour Format (2:30 PM)" /> <TimePicker defaultTime="14:30" id="time-picker-default-time-24hr" label="24-Hour Format (14:30)" /> <TimePicker defaultTime="14:30" id="time-picker-default-time-24hr-format" label="24-Hour Format with timeFormat (14:30)" timeFormat="24hour" /> </div> ) export default TimePickerDefaultTime
Enable timezone display by passing show_timezone / showTimezone.
import React from 'react' import { TimePicker } from 'playbook-ui' const TimePickerTimezone = (props) => ( <div> <TimePicker id="time-picker-timezone" showTimezone /> <TimePicker id="time-picker-timezone-24hour" showTimezone timeFormat="24hour" /> </div> ) export default TimePickerTimezone
Use the min_time / minTime and max_time / maxTime props to restrict the selectable time range. This example demonstrates minimum-only, maximum-only, and combined ranges in both 12-hour and 24-hour formats.
import React from 'react' import { TimePicker } from 'playbook-ui' const TimePickerMinMaxTime = (props) => ( <div> <TimePicker id="time-picker-min-only" label="Minimum Time Only" minTime="09:00" /> <TimePicker id="time-picker-max-only" label="Maximum Time Only" maxTime="17:00" timeFormat="24hour" /> <TimePicker id="time-picker-min-max-12hr" label="Min & Max Time Range (12-hour)" maxTime="17:00" minTime="09:00" /> <TimePicker id="time-picker-min-max-24hr" label="Min & Max Time Range (24-hour)" maxTime="17:00" minTime="09:00" timeFormat="24hour" /> <TimePicker id="time-picker-pm-only" label="PM Only Range (AM disabled)" maxTime="17:00" minTime="13:00" /> <TimePicker id="time-picker-am-only" label="AM Only Range (PM disabled)" maxTime="11:30" minTime="06:00" /> </div> ) export default TimePickerMinMaxTime
import React from 'react' import { TimePicker } from 'playbook-ui' const TimePickerDisabled = (props) => ( <div> <TimePicker disabled id="time-picker-disabled" label="Disabled Time Picker" /> <TimePicker defaultTime="14:30" disabled id="time-picker-disabled-with-value" label="Disabled with Default Time" /> </div> ) export default TimePickerDisabled
The requiredIndicator/required_indicator prop displays a red asterisk (*) next to the label, visually indicating that the field is required. This is purely visual and does not enforce validation.
You can use requiredIndicator/required_indicator with any validation approach: HTML5 validation via the required prop, client-side validation, or backend validation. For this reason, it works independently and doesn't need to be paired with the required prop.
Demonstrates the onChange and onClose event handlers for the Time Picker.
import React, { useState } from 'react' import { TimePicker, Body, Flex } from 'playbook-ui' const TimePickerOnHandler = (props) => { const [selectedTime, setSelectedTime] = useState('') const [closedTime, setClosedTime] = useState('') const handleTimeChange = (time) => { setSelectedTime(time) } const handleTimeClose = (time) => { setClosedTime(time) } return ( <div> {(selectedTime || closedTime) && ( <Flex marginBottom="sm" orientation="column" > {selectedTime && ( <Body text={`onChange: ${selectedTime}`} /> )} {closedTime && ( <Body marginTop={selectedTime ? "xs" : "none"} text={`onClose: ${closedTime}`} /> )} </Flex> )} <TimePicker id="time-picker-on-handler" onChange={handleTimeChange} onClose={handleTimeClose} /> </div> ) } export default TimePickerOnHandler