Skip to content

Commit

Permalink
ComboBox README (#237)
Browse files Browse the repository at this point in the history
  • Loading branch information
bitpshr authored Jun 15, 2017
1 parent 4501311 commit 28aa1eb
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 5 deletions.
167 changes: 166 additions & 1 deletion src/combobox/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,166 @@
# ComboBox widget
# @dojo/widgets/combobox/ComboBox widget

Dojo 2's `ComboBox` widget provides a form control that allows users to either enter a value manually or to select a value from a list of results.

## Features

- Compatible with any underlying data provider, data format, or store
- Custom components can be used for the list of results and each individual result
- Completely keyboard accessible

![Image of basic combobox](http://placekitten.com/450/300)

### Keyboard Usage

`ComboBox` supports standard keyboard navigation for data entry, toggling the results menu, and navigating to/selecting a given result.

**Input Events**:

- Escape key: hides the results menu if it is open
- Down Arrow: if the results menu is closed, pressing the down arrow opens the menu. If the menu is already open, then pressing the down arrow highlights the next option. If the last last option is highlighted, then the first option is highlighted and scrolled into view
- Up Arrow: if the results menu is open, pressing the up arrow highlights the previous result. If the first result is currently highlighted, then the last option is highlighted and scrolled into view
- Enter Key: if the results menu is open, pressing the enter key selects the highlighted option and sets its value as the input value

**Arrow Button Events**

- Enter Key: opens the results menu
- Space Key: opens the results menu

**Clear Button Events**

- Enter Key: clears the input value
- Space Key: clears the input value

### Accessibility Features

Beyond complete keyboard accessibility, `ComboBox` ensures that all appropriate ARIA attributes are included. To guarantee an excellent experience for all users, however, the following should be included with every `ComboBox`:

- `inputProperties.describedBy`: the ID of an element that provides descriptive text for the input value's expected format. For example, if the input value should be the name of a US state, an element with the same ID as `inputProperties.describedBy` might be, "Accepts any valid US state name.".

### Internationalization Features

The `ComboBox` makes no assumptions about the format of its underlying data. A function can be passed via the `getResultLabel` property that allows the label of a result data item to be returned. Using this mechanism, any necessary localization can be done on the returned label.

## Example Usage

*Basic Example*
```typescript
import ComboBox from '@dojo/widgets/combobox/ComboBox';
import { w } from '@dojo/widget-core/d';

w(ComboBox, {
results: ['foo', 'bar', 'baz'],
value: this.state.currentValue,
onChange: (value: string) => this.setState({ currentValue: value })
});
```

*Filtered results*
```typescript
import ComboBox from '@dojo/widgets/combobox/ComboBox';
import { w } from '@dojo/widget-core/d';

const data = ['foo', 'bar', 'baz'];

w(ComboBox, {
results: this.state.results,
value: this.state.currentValue,
onChange: (value: string) => this.setState({ currentValue: value }),
onRequestResults: (value: string) => {
// Search for matching results; though a simple array of
// data is used in this example, any data provider or store
// could be queried here instead. See the "Custom Data Provider"
// example.
const results = data.filter(item => {
const match = item.match(new RegExp(`^${ value }`));
return Boolean(match && match.length > 0);
});

this.setState({ results });
}
});
```

*Custom Data Format / Provider*
```typescript
import ComboBox from '@dojo/widgets/combobox/ComboBox';
import { w } from '@dojo/widget-core/d';
// A fictional store for example purposes only; this can be any data provider
import MyAwesomeStore from 'some/amazing/package';

const store = new MyAwesomeStore();

w(ComboBox, {
results: this.state.results,
value: this.state.currentValue,
onChange: (value: string) => this.setState({ currentValue: value }),
onRequestResults: (value: string) => {
// Search for matching results; query whatever data source we
// happen to be using, which in this example, is `MyAwesomeStore`
store.query({ value }).then((results: any) => this.setState({ results }));
}
});
```

*Validation*
```typescript
import ComboBox from '@dojo/widgets/combobox/ComboBox';
import { w } from '@dojo/widget-core/d';

w(ComboBox, {
results: ['foo', 'bar', 'baz'],
value: this.state.currentValue,
invalid: this.state.invalid,
onChange: (value: string) => this.setState({
currentValue: value,
// For this example, any value over 3 characters is deemed invalid
invalid: value.length > 3
})
});
```

*Custom Result Component*
```typescript
import ComboBox from '@dojo/widgets/combobox/ComboBox';
// The component used by default to render a result item
import ResultItem from '@dojo/widfgets/combobox/ResultItem';
import { w } from '@dojo/widget-core/d';

// Extend default ResultItem component to show an icon next to each label
class CustomResultItem extends ResultItem {
// We only need to override one method. Normally this method just returns
// the result; In this case, let's return an <img> and the result
renderResult(result: any) {
return v('div', [
v('img', { src: 'icon.png' }),
result
]);
}
}

w(ComboBox, {
results: ['foo', 'bar', 'baz'],
value: this.state.currentValue,,
customResultItem: CustomResultItem,
onChange: (value: string) => this.setState({ currentValue: value })
});
```

## Theming

The following CSS classes are used to style the `ComboBox` widget and should be provided by custom themes:

- `arrow`: Applied to the custom arrow button
- `clear`: Applied to the custom "clear input" button
- `clearable`: Applied to the input (non-native) when the widget is clearable
- `controls`: Applied to the controls (clear and arrow buttons) container for non-native instances
- `disabled`: Applied to both the input and optional label when the widget is disabled
- `downIcon`: Applied to the down arrow icon
- `icon`: Applied to the clear icon and the down arrow icon
- `input`: Applied to the input node
- `invalid`: Applied to both the input and optional label when the widget is invalid
- `readOnly`: Applied to both the input and optional label when the widget is read-only
- `required`: Applied to both the input and optional label when the widget is required
- `root`: Applied to the top-level wrapper node
- `timesIcon`: Applied to the clear icon
- `trigger`: Applied to button containing the down arrow
8 changes: 4 additions & 4 deletions src/dialog/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ w(Dialog, {
title: 'My Dialog',
open: this.state.open,
onRequestClose: () => this.setState({ open: false })
}, [ 'My dialog content...' ])
}, [ 'My dialog content...' ]);
```

*Modal with underlay*
Expand All @@ -54,7 +54,7 @@ w(Dialog, {
modal: true,
underlay: true,
onRequestClose: () => this.setState({ open: false })
}, [ 'My dialog content...' ])
}, [ 'My dialog content...' ]);
```

*Custom animations*
Expand All @@ -68,7 +68,7 @@ w(Dialog, {
enterAnimation: 'fly-in',
exitAnimation: 'fly-out',
onRequestClose: () => this.setState({ open: false })
}, [ 'My dialog content...' ])
}, [ 'My dialog content...' ]);
```

*Dialog that can't be closed*
Expand All @@ -80,5 +80,5 @@ w(Dialog, {
title: 'My Dialog',
open: this.state.open,
closeable: false
}, [ 'My dialog content...' ])
}, [ 'My dialog content...' ]);
```

0 comments on commit 28aa1eb

Please sign in to comment.