@bccampus/react-composite

Base React component to create a composite components, like Listbox,TreeView, with selection and expansion management

Installation

yarn add @bccampus/react-composite

Usage

Kim Tornado

Software Developer

Aria Patel

Data Scientist

Elena Rodriguez

UX/UI Designer

Liam Carter

Marketing Specialist

Sophie Williams

Financial Analyst

Adrian Smith

Project Manager

Mia Johnson

Graphic Designer

Jessica Brown

Customer Support Specialist

Raj Gupta

Network Engineer

Emily Chang

Human Resources Manager

<Composite
  role="listbox"
  navigableChildRole="option"
  items={people}
  defaultValue={[1, 8]}
  disabledKeys={[4, 5]}
  focusOptions={{ loop: true }}
  selectionOptions={{ multiple: true }}
  renderItem={(item: PersonProfile, { selected, disabled }, props) => (
    <Paper {...props} withBorder p="xs" my="xs" miw="15rem" className={classes.compositeItem}>
      <Checkbox
        checked={selected}
        disabled={disabled}
        label={item.fullname}
        description={item.title}
      />
    </Paper>
  )}
/>

Focus behavior

Composite component applies different focus movement and selection strategies based on the layout (Keyboard navigation). Currently, it provides focus behaviors for vertical lists, horizontal lists, and layout grids.

Options

Kim TornadoAria PatelElena RodriguezLiam CarterSophie WilliamsAdrian SmithMia JohnsonJessica BrownRaj GuptaEmily Chang
function Demo(props: DemoCompositeComponentProps) {
  return (
    <ConfiguratorDemoGrid
      renderItem={(item, { selected, disabled }, itemProps) => (
        <ImageCell item={item} selected={selected} disabled={disabled} {...itemProps} />
      )}
    />
  );
}

Defining custom keys

By default, Composite uses id or key property of items as their unique identifier. If your items do not contain any of these properties, you can use getItemKey property to define a custom key.

<Composite
  ...
  getItemKey={(item) => item.slug}
/>

Selection state

Box

@mantine/core

Base component for all Mantine components

Button

@mantine/core

Button component to render button or link

Loader

@mantine/core

Indicate loading state

Container

@mantine/core

Center content with padding and max-width

Anchor

@mantine/core

Display link with theme styles

Input

@mantine/core

Base component to create custom inputs

ActionIcon

@mantine/core

Icon button

CloseButton

@mantine/core

Button with close icon

CopyButton

@mantine/core

Copies given text to clipboard

FileButton

@mantine/core

Open file picker with a button click

UnstyledButton

@mantine/core

Unstyled polymorphic button

Tabs

@mantine/core

Switch between different views

BackgroundImage

@mantine/core

Displays image as background

Blockquote

@mantine/core

Blockquote with optional cite

Breadcrumbs

@mantine/core

Separates list of react nodes with given separator

Burger

@mantine/core

Open/close navigation button

Center

@mantine/core

Centers content vertically and horizontally

Code

@mantine/core

Inline and block code

Collapse

@mantine/core

Animate presence with slide down/up transition

ColorPicker

@mantine/core

Pick colors in hex(a), rgb(a), hsl(a) and hsv(a) formats

ColorSwatch

@mantine/core

Displays color

FocusTrap

@mantine/core

Trap focus at child node

Group

@mantine/core

Compose elements and components in a horizontal flex container

Highlight

@mantine/core

Highlight given part of a string with mark

Kbd

@mantine/core

Display keyboard key

Mark

@mantine/core

Highlight part of the text

NativeSelect

@mantine/core

Native select element based on Input

Notification

@mantine/core

Show dynamic notifications and alerts to user, part of notifications system

Paper

@mantine/core

Renders white or dark background depending on color scheme

Popover

@mantine/core

Display popover section relative to given target element

Portal

@mantine/core

Renders component outside of parent element tree

ScrollArea

@mantine/core

Area with custom scrollbars

SegmentedControl

@mantine/core

A linear set of two or more segments

Slider

@mantine/core

Slider and RangeSlider components

Stack

@mantine/core

Compose elements and components in a vertical flex container

Switch

@mantine/core

Capture boolean input from user

Table

@mantine/core

Render table with theme styles

Text

@mantine/core

Display text

TextInput

@mantine/core

Capture string input from user

Title

@mantine/core

h1-h6 heading

Badge

@mantine/core

Display badge, pill or tag

Tooltip

@mantine/core

Renders tooltip at given element on mouse over or other event

Transition

@mantine/core

Animate presence of component with pre-made animations

TypographyStylesProvider

@mantine/core

Styles provider for html content

VisuallyHidden

@mantine/core

Hide element visually but keep it accessible for screen readers

Divider

@mantine/core

Horizontal line with optional label or vertical divider

AspectRatio

@mantine/core

Maintain responsive consistent width/height ratio

Overlay

@mantine/core

Overlays parent element with div element with any color and opacity

Avatar

@mantine/core

Display user profile image, initials or fallback icon

Alert

@mantine/core

Attract user attention with important static message

Affix

@mantine/core

Renders children inside portal at fixed position

Fieldset

@mantine/core

Group related elements in a form

Checkbox

@mantine/core

Capture boolean input from user

Combobox

@mantine/core

Create custom select, autocomplete or multiselect inputs

Modal

@mantine/core

An accessible overlay dialog

Drawer

@mantine/core

Display overlay area at any side of the screen

Accordion

@mantine/core

Divide content into collapsible sections

Pill

@mantine/core

Removable and non-removable tags

PillsInput

@mantine/core

Base component for custom tags inputs and multi selects

Autocomplete

@mantine/core

Autocomplete user input with any list of options

TagsInput

@mantine/core

Capture a list of values from user with free input and suggestions

Select

@mantine/core

Custom searchable select

MultiSelect

@mantine/core

Custom searchable multi select

Pagination

@mantine/core

Display active page and navigate between multiple pages

AppShell

@mantine/core

Responsive shell for your application with header, navbar, aside and footer

Skeleton

@mantine/core

Indicate content loading state

SimpleGrid

@mantine/core

Responsive grid in which each item takes equal amount of space

Grid

@mantine/core

Responsive 12 columns grid system

HoverCard

@mantine/core

Display popover section when target element is hovered

Menu

@mantine/core

Combine a list of secondary actions into single interactive area

Progress

@mantine/core

Give user feedback for status of the task

RingProgress

@mantine/core

Give user feedback for status of the task with circle diagram

Chip

@mantine/core

Pick one or multiple values with inline controls

PinInput

@mantine/core

Capture pin code or one time password from the user

Rating

@mantine/core

Pick and display rating

Space

@mantine/core

Add horizontal or vertical spacing from theme

Indicator

@mantine/core

Display element at the corner of another element

Textarea

@mantine/core

Autosize or regular textarea

JsonInput

@mantine/core

Capture json data from user

Image

@mantine/core

Image with optional fallback

Card

@mantine/core

Card with sections

PasswordInput

@mantine/core

Capture password data from user

FileInput

@mantine/core

Capture files from user

Stepper

@mantine/core

Display content divided into a steps sequence

ColorInput

@mantine/core

Capture color from user

ThemeIcon

@mantine/core

Render icon inside element with theme colors

NumberInput

@mantine/core

Capture number from user

LoadingOverlay

@mantine/core

An overlay with centered loader

Radio

@mantine/core

Wrapper for input type radio

Timeline

@mantine/core

Display list of events in chronological order

Dialog

@mantine/core

Display a fixed overlay dialog at any side of the screen

Flex

@mantine/core

Compose elements in a flex container

List

@mantine/core

Display ordered or unordered list

Spoiler

@mantine/core

Hide long sections of content under a spoiler

NavLink

@mantine/core

Navigation link

NumberFormatter

@mantine/core

Format number with thousands/decimal separators and suffix/prefix

use-form

@mantine/form

Manage form state

Form context

@mantine/form

Add context support to use-form with createFormContext

Form errors

@mantine/form

Manipulate form errors with use-form hook

Nested fields

@mantine/form

Manage nested arrays and object state with use-form hook

Recipes

@mantine/form

use-form examples

Touched & dirty

@mantine/form

Get fields and form touched and dirty status

Form validation

@mantine/form

Validate fields with use-form hook

Form schema validation

@mantine/form

use-form schema based validation with zod, yup, joi and superstruct

Form validators

@mantine/form

Premade validation functions

Form values

@mantine/form

Manipulate form values with use-form

Form actions

@mantine/form

Change form state from anywhere in the application

Getting started

@mantine/dates

Calendar

@mantine/dates

Base component for custom date pickers

DateInput

@mantine/dates

Free form date input

DatePicker

@mantine/dates

Inline date, multiple dates and dates range picker

DatePickerInput

@mantine/dates

Date, multiple dates and dates range picker input

DatesProvider

@mantine/dates

Settings provider for @mantine/dates components

DateTimePicker

@mantine/dates

Capture datetime from the user

MonthPicker

@mantine/dates

Inline month, multiple months and months range picker

MonthPickerInput

@mantine/dates

Month, multiple months and months range picker input

TimeInput

@mantine/dates

Capture time from the user

YearPicker

@mantine/dates

Inline year, multiple years and years range picker

YearPickerInput

@mantine/dates

Inline year, multiple years and years range picker

Notifications system

@mantine/notifications

Mantine notifications system

Spotlight

@mantine/spotlight

Command center for your application

Carousel

@mantine/carousel

Embla based carousel component

Dropzone

@mantine/dropzone

Capture files from user with drag and drop

NavigationProgress

@mantine/nprogress

Navigation progress bar

CodeHighlight

@mantine/code-highlight

Highlight code with highlight.js

Modals manager

@mantine/modals

Centralized modals manager with option to handle state of multi-step modals

Rich text editor

@mantine/tiptap

Tiptap based rich text editor

Selected component:
const focusOptions = { loop: true, moveToNextRow: true };
const selectionOptions = { multiple: true };

function Demo() {
  const [selections, setSelections] = useState<Key[]>([]);

  return (
    <Flex direction="column">
      <ScrollArea h="30rem">
        <LayoutGrid
          value={selections}
          onChange={setSelections}
          selectionOptions={selectionOptions}
          focusOptions={focusOptions}
          items={mantineComponents}
          getItemKey={(item) => item.slug}
          renderItem={(item, { selected, disabled }, itemProps) => (
            <ComponentCardCell item={item} selected={selected} disabled={disabled} {...itemProps} />
          )}
        />
      </ScrollArea>
      <Divider />
      <Paper p="sm">Selected component: {selections.join(', ')}</Paper>
    </Flex>
  );
}

Expansion state

Introduction to Algorithms, Fourth Edition

Preface

IV Advanced Design and Analysis Techniques

Introduction

Bibliography

Index

const focusOptions: FocusOptions = { loop: false, includeGroups: true, includeDisabledItems: true };
const selectionOptions: SelectionOptions = {
  multiple: false,
  allowGroupSelection: true,
  makeInferredSelection: true,
};
const expansionOptions: ExpansionOptions = {
  multiple: true,
};
const disabledKeys = [2, 1500];

<Composite
  type="TreeView"
  items={book.content}
  getChildren={(item) => item.sections}
  focusOptions={focusOptions}
  disabledKeys={disabledKeys}
  selectionOptions={selectionOptions}
  selectionState={selections}
  onSelectionChange={setSelections}
  expansionOptions={expansionOptions}
  expandedKeys={expansions}
  onExpansionChange={setExpansions}
  renderRoot={({ children, ...props }) => (
    <Paper {...props} w="30rem" my="sm" p="sm" shadow="sm" withBorder>
      <Text size="lg" fw={500}>
        {book.title}
      </Text>
      {children}
    </Paper>
  )}
  renderGroup={renderGroup}
  renderItem={renderItem}
/>

Disabled items

You can disable items in a Composite component by setting the disabledKeys option. Disabled options can not be selected and the focus movement skips these items.

Additionaly, aria-disabled HTML attribute is set to true for these items, which can be used for custom styling.

.listItem {
  &[aria-disabled='true'] {
    @mixin light {
      background: var(--mantine-color-gray-2);
    }
    @mixin dark {
      background: var(--mantine-color-dark-7);
    }
  }
  &[aria-disabled='true'] * {
    text-decoration: none;
    @mixin light {
      color: var(--mantine-color-gray-6);
    }
    @mixin dark {
      color: var(--mantine-color-gray-7);
    }
  }
}

Composite context

CompositeContext provides two boolean values multiple and selectionMode to identify the selection type and whether the component in the selection mode. selectionMode changes only if selectionOptions.trackSelectioMode is set to true.

The following example shows how items can change based on these values. If nothing is selected (selectionMode: false), an overlay and checkbox is shown only if an item is hovered. After an item is selected (selectionMode: true), all items render their overlays.

const ctx = useCompositeContext();
...
<Overlay display={ctx.selectionMode ? 'block' : undefined}>
  <Checkbox
    tabIndex={-1}
    checked={selected}
    disabled={disabled}
    readOnly
    aria-hidden
    size="md"
    radius={ctx.multiple ? 'sm' : 'lg'}
  />
</Overlay>
...

Kim Tornado

Software Developer

Passionate about creating efficient and scalable software solutions. Experienced in full-stack development with a focus on web applications. Enjoys tackling complex coding challenges and learning new technologies.

Aria Patel

Data Scientist

Data enthusiast with expertise in statistical analysis and machine learning. Proficient in using Python and R for data manipulation and modeling. Excited about uncovering meaningful insights from complex datasets.

Elena Rodriguez

UX/UI Designer

Creative designer with a passion for crafting engaging user experiences. Skilled in creating intuitive interfaces that blend aesthetics with functionality. Enjoys staying updated on design trends and user-centered design principles.

Liam Carter

Marketing Specialist

Results-driven marketer with a focus on digital marketing strategies. Experienced in campaign management, SEO, and social media marketing. Enjoys analyzing market trends and developing creative marketing initiatives.

Sophie Williams

Financial Analyst

Detail-oriented financial analyst with expertise in financial modeling and forecasting. Proficient in analyzing financial statements and providing insights for informed decision-making. Enjoys working with numbers and solving financial puzzles.

Adrian Smith

Project Manager

Seasoned project manager with a track record of successful project delivery. Skilled in team coordination, resource allocation, and risk management. Enjoys leading cross-functional teams and ensuring projects are completed on time and within budget.

Mia Johnson

Graphic Designer

Creative graphic designer with a passion for visual storytelling. Proficient in Adobe Creative Suite and experienced in creating visually stunning designs for both print and digital media. Enjoys bringing ideas to life through impactful visuals.

Jessica Brown

Customer Support Specialist

Dedicated customer support specialist with excellent communication and problem-solving skills. Experienced in addressing customer inquiries, resolving issues, and ensuring customer satisfaction. Enjoys providing top-notch support and building positive customer relationships.

Raj Gupta

Network Engineer

Experienced network engineer with expertise in designing and implementing robust network infrastructure. Skilled in troubleshooting network issues and optimizing performance. Enjoys staying updated on the latest networking technologies and security protocols.

Emily Chang

Human Resources Manager

Strategic human resources manager with a focus on talent acquisition and employee development. Skilled in workforce planning, performance management, and HR policy implementation. Enjoys fostering a positive work environment and supporting organizational growth.

function Demo(props: DemoCompositeComponentProps) {
  return (
    <LayoutGrid
      {...props}
      multiple
      trackSelectioMode
      renderItem={(item, { selected, disabled }, itemProps) => (
        <PersonCardCell item={item} selected={selected} disabled={disabled} {...itemProps} />
      )}
    />
  );
}

Keyboard navigation

Vertical/Horizontal List

Focus:

  • Down Arrow / Right Arrow: Moves focus to the next option.
    • If focus is on the last item and focusOptions.loop: true, focus moves to the first item.
  • Up Arrow / Left Arrow: Moves focus to the previous option.
    • If focus is on the first item and focusOptions.loop: true, focus moves to the last item.
  • Page Down: Moves focus down focusOptions.pageSize number of items. If focus is in the last item of the list, focus does not move.
  • Page Up: Moves focus up focusOptions.pageSize number of items. If focus is in the first item of the list, focus does not move.
  • Home: Moves focus to first option.
  • End: Moves focus to last option.

Selection:

  • Space: changes the selection state of the focused option.

  • Control + A: Selects all options in the list. If all options are selected, it unselect all options.

    In a single-select list, selection also move with focus when selectionOptions.followFocus options is set true.

    In a multi-select list, focus movements with Shift modifier, selects contiguous items from the most recently selected item to the focused item. For example, Shift + Home selects the focused option and all options up to the first option, and moves focus to the first option.

Layout Grid

Focus:

  • Right Arrow: Moves focus one cell to the right.
    • If focus is on the right-most cell in the row and
      • focusOptions.moveToNextRow: true, focus moves to the first cell in the following row.
      • focusOptions.moveToNextRow: false and focusOptions.loop: true, focus moves to the first cell in the same row.
      • focusOptions.moveToNextRow: false and focusOptions.loop: false, focus does not move.
    • If focus is on the last cell in the grid and focusOptions.loop: true, focus moves to the first cell in the grid; otherwise, focus does not move.
  • Left Arrow: Moves focus one cell to the left.
    • If focus is on the left-most cell in the row and
      • focusOptions.moveToNextRow: true, focus moves to the last cell in the previous row.
      • focusOptions.moveToNextRow: false and focusOptions.loop: true, focus moves to the first cell in the same row.
      • focusOptions.moveToNextRow: false and focusOptions.loop: false, focus does not move.
    • If focus is on the first cell in the grid and focusOptions.loop: true, focus moves to the last cell in the grid; otherwise, focus does not move.
  • Down Arrow: Moves focus one cell down.
    • If focus is on the bottom cell in the column and
      • focusOptions.moveToNextColumn: true, focus moves to the top cell in the following column.
      • focusOptions.moveToNextColumn: false and focusOptions.loop: true, focus moves to the top cell in the same column.
      • focusOptions.moveToNextColumn: false and focusOptions.loop: false, focus does not move.
    • If focus is on the bottom cell in the last column and focusOptions.loop: true, focus moves to the first cell in the grid; otherwise, focus does not move.
  • Up Arrow: Moves focus one cell up.
    • If focus is on the top cell in the column and
      • focusOptions.moveToNextColumn: true, focus moves to the bottom cell in the previous column.
      • focusOptions.moveToNextColumn: false and focusOptions.loop: true, focus moves to the bottom cell in the same column.
      • focusOptions.moveToNextColumn: false and focusOptions.loop: false, focus does not move.
    • If focus is on the first cell in the grid and focusOptions.loop: true, focus moves to the bottom cell in the last column; otherwise, focus does not move.
  • Page Down: Moves focus down focusOptions.pageSize number of rows. If focus is in the last row of the grid, focus does not move.
  • Page Up: Moves focus up focusOptions.pageSize number of rows. If focus is in the first row of the grid, focus does not move.
  • Home: moves focus to the first cell in the row that contains focus.
  • End: moves focus to the last cell in the row that contains focus.
  • Control + Home: moves focus to the first cell in the first row.
  • Control + End: moves focus to the last cell in the last row.

Selection:

  • Space: Changes the selection state of the focused option.

  • Control + A: Selects all options in the list. If all options are selected, it unselect all options.

    In a single-select grid, selection also move with focus when selectionOptions.followFocus options is set true.

    In a multi-select grid, focus movements with Shift modifier, selects contiguous items from the most recently selected item to the focused item. For example, Control + Shift + Home selects the focused option and all options up to the first option in the grid, and moves focus to the first option.