Settings API
Overview
Fitbit developers can make their application configurable by users, by creating application settings.
Application settings are written using JSX.
A compiled settings.js file is registered into the Fitbit mobile application
during the application installation process.
General Tips
settingsKey will manage the settings storage and retrieval for you, but you
can still manage them yourself. The following are equivalent:
<ColorSelect
settingsKey="color"
/>
<ColorSelect
value={props.settings.color}
onChange={value => props.settingsStorage.setItem('color', value)}
/>
Components
The Settings API provides a number of predefined components.
Section
Creates an element which can be used as a container section for other elements.
Basic Usage
<Section
description={<Text> Description <Link source="/">here</Link></Text>}
title={<Text bold align="center">Demo Settings</Text>}>
<Text>
This is a very basic demo settings page to show off some of the current
capabilities of the Companion Settings library.
</Text>
</Section>
Properties
titletakes a string, the text that appears above the content block.descriptiontakes a string, the subtext that appears below the content block.
Link
Create a hyperlink to an anchor or URL.
Basic Usage
<Link source="...">InnerHTML</Link>
Properties
sourcetakes a string, the web address to link to.
Example Use Cases
External links, must be HTTP/HTTPS:
<Link source="https://www.google.com">Google</Link>
Tip: Use with the
<Text>element for additional formatting options.
Text
Create a paragraph of text. Supports rich formatting.
Basic Usage
<Text>Your Text Here</Text>
Properties
boldif present, the inner text will appear bold.italicif present, the inner text will appear italic.align:left | center | right, sets the horizontal alignment of text.
Example Use Cases
<Text align="right">This text will align to the right side</Text>
<Text italic>This text is italicized.</Text>
<Text align="center">This text will be centered and <Text bold>bold</Text></Text>
Tip: Text is intended to appear inside a
<Section>or<List>.
TextImageRow
Creates a row containing a label, sublabel, and optional icon image.
Basic Usage
<TextImageRow
label="Example"
sublabel="here it is"
/>
Properties
labeltakes a string, appears as the main text.sublabeltakes a string, appears as the gray subtext under the label.icontakes a string, URL for the icon image
Example Use Cases
<TextImageRow
label="San Francisco"
sublabel="CA"
icon="https://tinyurl.com/ybbmpxxq"
/>
Tip: Intended for use in a
<List>or<Select>.
Button
Creates a simple button, similar to the
Basic Usage
<Button
label="Button"
onClick={() => console.log("Clicked!")}
/>
Properties
labeltakes a string, the text that appears inside the buttonlistif present, the button will be styled to fit into a ListonClicka function that is called every time the button is clicked. Passes the SyntheticEvent(https://facebook.github.io/react/docs/events.html) as the first argument.
Example Use Cases
<Button
list
label="Clear Settings Storage"
onClick={() => props.settingsStorage.clear()}
/>
Toggle
Creates a simple toggle on/off button.
Basic Usage
<Toggle
settingsKey="toggle"
label="example"
/>
Properties
labeltakes a string, the text that appears to the left of the toggle.settingsKeytakes a string, the key associated with this setting.onChangea function that is called every time the toggle is changed. Passes the new value of the toggle as the first argument (the booleantruefor on,falsefor off).
Example Use Cases
<Toggle
settingsKey="toggle"
/>
<Toggle
settingsKey="toggle"
label={`Toggle Switch: ${settings.toggle === 'true' ? 'on' : 'off'}`}
/>
<Toggle
settingsKey="toggle"
label="Toggle Switch"
/>
{ JSON.parse(settings.toggle || 'false') && <Toggle settingsKey="hiddenToggle" /> }
Slider
Creates a range slider control.
Basic Usage
<Slider
label="Example"
settingsKey="slider"
min="0"
max="60"
/>
Properties
labeltakes a string, the text that appears above the slider.settingsKeytakes a string, the key associated with this setting.mintakes a string representation of a number, the minimum value for the slider.maxtakes a string representation of a number, the maximum value for the slider.steptakes a string representation of a number, the interval for slider values.onChangea function that is called every time the slider value is changed. Passes the new value of the toggle as the first argument (the string representation of the numerical value).
TextInput
Basic Usage
<TextInput
label="example"
settingsKey="text"
/>
Properties
titletakes a string, the text that appears above the section and in the navbar titlelabeltakes a string, the text that appears on the TextInput button as well above the text input boxplaceholdertakes a string, the text that appears inside the text input box when no value is present, defaults tolabelactiontakes a string, the text that appears in the save button if presenttypetakes a string, the type of input field, defaults to "text"disabledif present, the textInput is disabled and cannot be clicked onsettingsKeytakes a string, the key associated with this settingonChangea function that is called every time the text value is saved by the user. Takes the new value of the text as an argumentrenderItema function that takes in the value of one option and returns the JSX to render that item in a list. By default, thenamefield is wrapped in a<Text>component.onAutocompletea function that is called every time the text value is changed by the user. Takes the new value of the text as an argument and returns a list of autocomplete options to render. Each option is rendered usingrenderItemand must include anamefield.renderAutocompletea function that takes in one option and the input value and returns the JSX to render that item in a list. By default usesrenderItem.
Example use cases
<TextInput
label="Example"
title="Text Input"
settingsKey="textInput"
disabled={!(props.settings.toggleTextInput === "true")}
/>
<Toggle
label="Enable Text Input"
settingsKey="toggleTextInput"
/>
<TextInput
title="Add List Item"
label="Item Name"
placeholder="Type something"
action="Add Item"
onAutocomplete={(value) => {
const autoValues = [
{ name: "red", value: "1" },
{ name: "orange", value: "2" },
{ name: "yellow", value: "3" },
{ name: "green", value: "4" },
{ name: "blue", value: "5" },
{ name: "purple", value: "6" }];
return autoValues.filter((option) => option.name.startsWith(value));
}}
/>
Tip: This component is still being developed and will soon include support for autocomplete
ColorSelect
Basic Usage
<ColorSelect
settingsKey="color"
colors={[
{color: 'tomato'},
{color: 'sandybrown'},
{color: 'gold'},
{color: 'aquamarine'},
{color: 'deepskyblue'},
{color: 'plum'}
]}
/>
Properties
settingsKeytakes a string, the key associated with this setting.colorstakes an array of objects. Each object must have a field namedcolor, whose value is a valid string representation of a CSS color. For examples, see https://www.w3schools.com/cssref/css_colors_legal.asp. Each object can also include an optionalvaluefield, which is what will be stored in settings and passed toonSelection. Ifvalueis not defined, the value ofcolorwill be used by default.centeredif present, the color circles will be center aligned. Otherwise, they are left aligned.onSelectiona function that is called every time a color is selected. Passes the new value of the selected color as the first argument (the string representation of the value).
Example Use Cases
<ColorSelect
centered={true}
settingsKey="color"
colors={[
{color: 'tomato', value: '1'},
{color: 'sandybrown', value: '2'},
{color: 'gold', value: '3'},
{color: 'aquamarine', value: '4'},
{color: 'deepskyblue',value: '5'},
{color: 'plum', value: '6'},
{color: 'tomato', value: '7'},
{color: 'sandybrown', value: '12'},
{color: 'gold', value: '13'},
{color: 'aquamarine', value: '14'},
{color: 'deepskyblue',value: '15'}
]}
onSelection={(value) => console.log(value)}
/>
<ColorSelect
settingsKey="color"
colors={[
{color: 'tomato', value: {align: 'left', number: '1'}},
{color: 'sandybrown', value: {align: 'right', number: '2'}}
]}
/>
Tip: If you specify fewer than
6colors, the circles will stretch to fill the row
Select
Creates a selection picker.
Basic Usage
<Select
label={`Selection`}
settingsKey="selection"
options={[
{name:"One"},
{name:"Two"},
{name:"Three"}
]}
/>
Properties
titletakes a string, the text that appears above the List block.selectViewTitletakes a string, the text that appears as the title of the select view or modal.labeltakes a string, the text that appears on the select button.settingsKeytakes a string, the key associated with this setting.optionstakes an array of objects. Each object must have a field namedname, whose value is a string. Each object can also include an optionalvaluefield, which will be stored in settings along withname.multipleif present, the user can select multiple items from the list, toggling them on and off by selecting them.disabledif present, the select element will be disabled.renderItema function that takes in the value of one option and returns the JSX to render that item in a list. By default, thenamefield is wrapped in a<Text>component.onSelectiona function that is called every time an option is selected. Passes an object as an argument:{selected: Array, values: Array}, whereselectedis an array of indices that map to the selected options, andvaluesis an array of the values of those selected options.
Note that the selected option within a <Select> is recalled by the option's
index in the options array, not by the option's name or value. If you
update your application to rearrange or remove options within a <Select>,
you must manually migrate the corresponding settingsKey in your companion
code. Otherwise, existing users will see their selections changed or cleared
unexpectedly during the update. Alternatively, you may manually manage the
value of the <Select> via the onSelection event and selected property.
Example Use Cases
<Select
label={`Multi-Selection`}
multiple
settingsKey="multiselection"
options={[
{name:"One", value:"1"},
{name:"Two", value:"2"},
{name:"Three", value:"3"},
{name:"Four", value:"4"},
{name:"Five", value:"5"},
{name:"Six", value:"6"},
{name:"Seven", value:"7"},
{name:"Eight", value:"8"},
{name:"Nine", value:"9"},
{name:"Ten", value:"10"},
{name:"Eleven", value:"11"},
{name:"Twelve", value:"12"},
{name:"Thirteen", value:"13"},
{name:"Fourteen", value:"14"},
{name:"Fifteen", value:"15"}
]}
renderItem={
(option) =>
<TextImageRow
label={option.name}
sublabel="Sub-Label"
icon="https://tinyurl.com/ybbmpxxq"
/>
}
onSelection={(selection) => console.log(selection)}
/>
Tip: We recommend using
<TextImageRow>as the rendering function for renderItem when including icons or sublabels. For a simple text item, use<Text>.
Additive List
Creates a list which users can add items to by selecting from a list of options.
Basic Usage
Additive List with a Text Input:
<AdditiveList
settingsKey="additive"
/>
Additive List with a Select Input:
<AdditiveList
settingsKey="additive"
addAction={
<Select
label="Add Item"
options={[
{ name: 'Label1'},
{ name: 'Label2'},
{ name: 'Label3'},
{ name: 'Label4'},
{ name: 'Label5'}
]}
/>
}
/>
Properties
titletakes a string, the text that appears above the List block.descriptiontakes a string, the subtext that appears below the List block.settingsKeytakes a string, the key associated with this setting.minItemsthe minimum number of items allowed in the list.maxItemsthe maximum number of items allowed in the list.renderItema function that takes in the value of one option and returns the JSX to render that item in a list. By default, thenamefield is wrapped in a<Text>component.addActiona component that will be used to render the input style for this list. Should be a component that allows for input, such asSelectorTextInput.onListChangea function that is called every time the list is changed from adding, deleting or reordering. Passes an array as an argument containing all the items in the list in their current order
Example Use Cases
<AdditiveList
title="A list of TextImageRow"
settingsKey="select-list"
maxItems="5"
renderItem={
({ name, value }) =>
<TextImageRow
label={name}
sublabel={value.location}
icon={value.icon}
/>
}
addAction={
<Select
label="Add Item"
options={[
{ name: 'Label1', required: true, value: {location: 'Sub-Label', icon: 'https://tinyurl.com/ybbmpxxq'} },
{ name: 'Label2', value: {location: 'Sub-Label', icon: 'https://tinyurl.com/ybbmpxxq'} },
{ name: 'Label3', required: true, value: {location: 'Sub-Label', icon: 'https://tinyurl.com/ybbmpxxq'} },
{ name: 'Label4', value: {location: 'Sub-Label', icon: 'https://tinyurl.com/ybbmpxxq'} },
{ name: 'Label5', required: false, value: {location: 'Sub-Label', icon: 'https://tinyurl.com/ybbmpxxq'} }
]}
/>
}
/>
<AdditiveList
title="A list with Autocomplete"
settingsKey="autocomplete-list"
maxItems="5"
addAction={
<TextInput
title="Add List Item"
label="Item Name"
placeholder="Type something"
action="Add Item"
onAutocomplete={(value) => {
const autoValues = [
{ name: "red", value: "1" },
{ name: "orange", value: "2" },
{ name: "yellow", value: "3" },
{ name: "green", value: "4" },
{ name: "blue", value: "5" },
{ name: "purple", value: "6" }];
return autoValues.filter((option) => option.name.startsWith(value));
}}
/>
}
/>
OAuth Button
Creates a generic OAuth button that provides two stage authorization code flow by default.
Note: Most OAuth providers require you to specify the
redirect_urldomain or full path that you will be using with their service. We have provided a special URL to automatically handle the redirection. Please use:https://app-settings.fitbitdevelopercontent.com/simple-redirect.html
Basic Usage
<Oauth
settingsKey="oauth"
title="OAuth Login"
label="OAuth"
status="Login"
authorizeUrl="https://accounts.google.com/o/oauth2/v2/auth"
requestTokenUrl="https://www.googleapis.com/oauth2/v4/token"
clientId="11111"
clientSecret="asdfxxx"
scope="profile"
pkce
/>
Properties
titletakes a string, the text that appears above the List block.labeltakes a string, the text that appears on the left of the Button.statustakes a string, the text that appears on the right of the Button.descriptiontakes a string, the subtext that appears below the List block.settingsKeytakes a string, the key associated with this setting.authorizeUrltakes a string, the user authorization grant url.requestTokenUrltakes a string, the request token url.clientIdtakes a string, the clientId specified on your OAuth provider account.clientSecrettakes a string, the clientSecret specified on your OAuth prvoder account.scopetakes a string, the scopes that are being requested.pkcetakes a boolean, enables Proof Key for Code Exchange for OAuth providers that support PKCE.onAccessTokena function that receives the accessToken and anything the OAuth provides with it like refresh token and expiration.
Example Use Cases
<Oauth
settingsKey="oauth"
title="Fitbit Login"
label="Fitbit"
status="Login"
authorizeUrl="https://www.fitbit.com/oauth2/authorize"
requestTokenUrl="https://api.fitbit.com/oauth2/token"
clientId="11111"
clientSecret="asdfxxx"
scope="profile"
onAccessToken={async (data) => {
console.log(data);
}}
/>
Strava Login Button
Creates a Strava login button that takes in Strava OAuth options and allows the user to log in.
Note: For Strava API Application registration you need to set the domain that is used redirect to after a user authenticates at Strava. That domain currently should be:
fitbitdevelopercontent.comand is likely to change in the future when we provide a more robust redirect OAuth service.
Basic Usage
<StravaLogin
title="Strava Login"
settingsKey="strava"
clientId="11111"
clientSecret="asdfxxx"
/>
Properties
titletakes a string, the text that appears above the List block.descriptiontakes a string, the subtext that appears below the List block.settingsKeytakes a string, the key associated with this setting.clientIdtakes a string, the clientId specified on your Strava account.clientSecrettakes a string, the clientSecret specified on your Strava account.onAccessTokena function that receives the accessToken and Strava userInfo when the auth flow returns with a valid code. It will only run once after coming back from the auth flow.
Example Use Cases
<StravaLogin
title="Strava Login"
settingsKey="strava"
clientId="11111"
clientSecret="asdfxxx"
onAccessToken={async (accessToken, userInfo) => {
const profile = await getProfile(accessToken);
settingsStorage.setItem('user', JSON.stringify(profile));
}}
/>
Image Picker
Creates a component that facilitates the user picking a photo from their phone to be used within your application. Once an image is picked, it will be either stored and/or passed to your handler function as a base64 encoded string.
Basic Usage
<ImagePicker
title="Image Picker"
description="Pick an image to use in this app"
label="Pick an Image"
sublabel="Settings image picker"
settingsKey="image"
imageWidth="300"
imageHeight="300"
/>
Properties
titletakes a string, the text that appears above the List block.descriptiontakes a string, the subtext that appears below the List block.labeltakes a string, the text that appears as the main action the Button.sublabeltakes a string, the text that appears under the label on the Button.pickerTitletakes a string, the title of the image picker page.pickerImageTitletakes a string, the title above the already picked image.pickerLabeltakes a string, the text that appears as the main action on the picker page.settingsKeytakes a string, the key associated with this setting. Note: If you provide asettingsKeythe image data will be stored and available under the key name you provide as JSON serialized as a string. Stored as a JSON serialized string with the following properties:imageUri- base64 data URIimageSize.width- definedimageWidthimageSize.height- definedimageHeightimageWidthtakes a string or integer, set to348by default, the desired width of the picked image.imageHeighttakes a string, set to250by default, the desired height of the picked image.showIcontakes a boolean, set totrueby default, if set tofalseit will not show the picked image as an icon next to the button.disabledtakes a boolean, disable the button.onImagePickedtakes a function, when an image is picked the image data is passed to the definedonImagePickedhandler. Passes an object with the following properties:imageUri- base64 data URIimage.imageString- base64 string image dataimage.type- image mime-typeimageSize.width- definedimageWidthimageSize.height- definedimageHeight
Example Use Cases
<ImagePicker
title="Image Picker"
description="Pick an image to use in this app"
label="Pick an Image"
sublabel="Settings image picker"
imageWidth="300"
imageHeight="300"
onImagePicked={({ image, imageSize }) => doSomethingWithImage(image, imageSize)}
/>