question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Tech Design] Terra Select Responsive Dropdown

See original GitHub issue

Tech Design

Description

Tech design for https://github.com/cerner/terra-core/issues/2383

TLDR

  • Consolidate use of Dropdown and DropdownMenu
    • <DropdownMenu /> is an internal implementation detail of <Dropdown /> and it’s unnecessarily complicating the component by rendering the menu as a renderProp in the <Select /> component
  • Implement (name pending) <ResponsiveDropdown /> (or <Modal />, whatever the UX defined “responsive dropdown” is)
  • Remove render props pattern in Select.jsx
    • In Frame, if this.state.isOpen, then use either the <Dropdown /> or <Modal />
  • Flex between <Dropdown /> and <Modal /> based on if we’re mobile or at 'small' or 'tiny' breakpoints
    • Add isMobile method to SharedUtil which uses the UserAgent to check for iPhone, iPad, and Android
    • Use ActiveBreakpointContext to determine the activeBreakpoint
    • const useModal = isMobile() || activeBreakpoint === 'tiny' || activeBreakpoint === 'small';

Details

Dropdown, DropdownMenu, and the Unnecessary renderProps Pattern

<DropdownMenu /> is just an internal implementation detail of <Dropdown />. We don’t need to be rendering it via render props in <Select />. We can just render the <Frame /> and delegate the dropdown and responsive behavior to the Frame. This allows us to reduce the complexity of the Select component while also giving us the ability to add new behavior easily to the Frame.

Responsive Dropdown Implementation

NOTE: See additional screenshots below for visuals.

The responsive dropdown workflow will live inside a DialogModal. When rendered, it will have an action header and action footer, while the content will be displayed with an input styled just like the current dropdown variant (including tags/pills) and a list of all options.

Action Header

We will need to give the action header a label to display as the title. The action header will call the responsive dropdown component’s onClose prop when the action header’s close button is pressed/clicked and close the modal.

Content

The content will contain an input (for multiple/search/tag variants) and a list of options as well as any extra visual indicators for workflows that exist outside the happy-path (e.g. “No results found”) or normal usage (e.g. “Enter ‘x’ characters to search”).

Action Footer

The action footer will have two buttons. The start button is labeled "Clear All" and will call the responsive dropdown’s onClear prop when pressed/clicked. The end button is labeled "Apply" and will simply approve/commit the state change authored by the user. It will call the responsive dropdown’s onApply prop when pressed/clicked. It is assumed that changes will only be committed when the Apply button is used, while also closing the modal.

isMobile()

class SharedUtil {
  // ...

  static isMobile() {
    const { userAgent } = navigator;
    const isAndroid = userAgent.includes('Android');
    const isIOS = userAgent.includes('iPhone') || userAgent.includes('iPad');

    return isAndroid || isIOS;
  }
}

Flexing between <Dropdown /> and <Modal /> workflows

Right now in Frame, we render a <Dropdown /> (using the renderProps pattern to pass props to a <DropdownMenu /> in <Select />) based on the boolean this.state.isOpen. We can use this plus another boolean to flex between <Dropdown /> and <Modal /> workflows. Using the above isMobile() method and the ActiveBreakpointContext, we can determine if we want to render the <Modal /> or not:

const activeBreakpoint = useContext(ActiveBreakpointContext);
const useModal = isMobile() || activeBreakpoint === 'tiny' || activeBreakpoint === 'small';
const { isOpen } = this.state;

return (
  <div {...stuff}>
    {isOpen &&
      useModal ? <Modal {...modalProps} /> : <Dropdown {...dropdownProps} />
    }
  </div>
);

Additional Context / Screenshots

image

@ Mentions

@bjankord @StephenEsser

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:10 (10 by maintainers)

github_iconTop GitHub Comments

1reaction
StephenEssercommented, May 21, 2019

A little more context about the render prop so the decision to remove it isn’t done under misapprehension.

The Select menu was originally designed to allow a custom implementation of the menu within the dropdown. The render prop was added to allow an entry point for this functionality. A user could implement a Select dropdown using the Frame and provide their own menu which would receive all of the require props from the render prop.

<Frame dropdown={dropdownProps => ( 
  <CustomMenu {...dropdownProps} />)} 
/>

This would allow a user to create a custom menu implementation to meet application specific requirements. This requirement is also why the Frame itself exists as a separate component from the Select and why the dropdown and menu exist separately.

With the introduction of the accessibility changes, general complexity of this component, and the drive towards a standard behavior a custom menu is becoming increasingly more difficult and discouraged to implement.

If we decide to remove the custom render functionality we should also investigate merging the Frame into the Select to cut down on complexity and potential extra renders.

0reactions
bjankordcommented, Jul 18, 2019

Update: We’ve talked about this offline and have landed on implementing a solution that renders the input within the portal instead of rendering the select as a modal on mobile devices. Closing this issue as we’ve decided on a direction to go with this that won’t require the implementation described in the tech design.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Enhance select option navigation experience on iOS when ...
User swipes right and the virtual cursor moves to the select dropdown while focus remains on the text input. VoiceOver announces "Blue.
Read more >
Responsive High Tech Dropdown Menu HTML CSS - YouTube
Create Responsive Dropdown Menu CSS HTML. Source Code:https://www.patreon.com/fdwebdesign Buy Me A ...
Read more >
Terra Theme Manual - epicShops - A Professional Web ...
In the theme customizer, under the “Home Page” section scroll down to the “blog” subsection. Select your number of desired posts from the...
Read more >
Tabbed Brochure Template Version 4.0 Documentation
Responsive design drop-down menu for smaller screens. Change from div to section tags for content areas to address issues with lists. Code files....
Read more >
(Guide) How to Defeat an Alien Invasion in 10 Easy Steps
Step 3 – Research the Right Technologies. The Terra Invicta tech tree is beautiful, complex and inspiring; but also intimidating and ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found