Opinions: How do you handle different functionality on mobile vs desktop?

Looking to hear your opinions/strategies on handling different functionality requirements for the same component depending on if a user is on mobile vs desktop.

The Scenario

A UX designer has come to you with designs for a filter bar on a responsive web app. On desktop the filters are displayed in the bar in categories and you access them by clicking on the category title which opens a dropdown menu to display all the filters for that category. There is one filter category that sits outside the bar, but is also a dropdown menu. On mobile the filters are accessed by clicking a button which then displays a modal with all the filter categories. You access the filters by tapping on the category title which open an accordion showing all the related filters. The one filter category that sat outside the bar on desktop, is in the modal with the other filter categories.

I have my thoughts, preferences, and opinions on how to approach this, but I’m curious… How do you approach this and what are the pros/cons of your approach?

This is how I do it, on my root component:

data(){
  return {
    mobile:window.innerWidth <= 700
  }
},
created(){
  addEventListener('resize', () => {
    this.mobile = innerWidth <= 700
  })
}
<div class="container" :class="{mobile, hasSidebar, hasHeader, showSidebar}">

Then I can access this.$root.mobile in any component, both in templates with v-if and in scripts. I can also use the .mobile css class to make special css rules like

.mobile .itemCard
  font-size 14px

In regards to different functionality, how do you handle that? Will you then conditionally render a component based on this.$root.mobile? In my filter bar scenario, desktop displays and functions quite differently from mobile. Do you create 2 separate components? One for mobile, one for desktop. Do you try to create one component that responsively adjusts it’s functionality? (I feel that would get very complicated quickly). Or do you build individual components that are resolution agnostic and then piece them together into components for mobile & desktop views.

I don’t use $root.mobile very often, mostly I just use CSS. I would rather make one component which is responsive, instead of separate components for mobile and desktop, that would probably lead to a lot of duplicate code. I don’t really have any components with radically different functionality on mobile and desktop, it’s mostly the display that is different.

For your example, if the user first had a small window which turned the app into mobile mode, clicked to open the modal, and then resized the window to desktop mode, I don’t think it’s a big deal wether the modal stays up, or if it disappears. And the component should always emit the same data (the chosen category/categories) wether on mobile or desktop.

Agreed. That’s the approach I’ve taken thus far (single component functionality tailored with responsive views) and it’s worked quite well. I’m mainly curious how others are tackling this issue. Whether they give in to UX and write conditional functionality, but potentially quite messy code or push back on designers for the sake of easier to maintain code… especially because I’ll have to discuss with the UX designers as to why they’re trying to make my life hell :wink: so I’d like to know my opinions are well founded :slight_smile:

This is a great topic. I have the same issue with approaching mobile rendering. You can always control a vue component with css media queries. However, it would be nice if vue had a conditional render (not based on hide or show) that allowed multiple components. Meaning developers can render seperate mobile components that have a directive/setting/property which deploys those components on mobile devices (based on screen size or browser sniffing) and destroys the desktop components.

This means that I could copy my current vue desktop nav component (‘Nav.vue’), and save it in say a mobile/components/ directory. Then by adding a directive to both the desktop version v-display=“non-mobile” and for mobile v-display=“mobile”. Something like this would ideally destroy/remove or conditionally render nodes to the dom. Meaning I could easily have duplicate components with the same id’s and logic that I can approach differently knowing that one will be rendered for mobile, whilst the other would be rendered for desktop.

A simple directive could solve this issue and give developers the chance to easily create mobile and desktop interfaces that they can copy, modify and finally customize with css.

Just jump in with what I do (using Vuetify breakpoints), but for my parallax component for example a computed property like:

parallaxHeight() {
      switch (this.$vuetify.breakpoint.name) {
        case 'xs':
          return '350'
        case 'sm':
          return '400'
        case 'md':
          return '450'
        case 'lg':
          return this.windowHeight
        case 'xl':
          return this.windowHeight
        default:
          return '350'
      }
    }

Then the component gets:

<v-parallax
   :height="parallaxHeight"
....
>

Similar concept with my widget headers. Pretty fat and tall on larger screens since there is space, but on smaller / mobile they are condensed to take up less real-estate.

I like the idea, but it requires vuetify and also needs some installation and coding to work. My point above is the idea of DOM removal via a standard vue directive for components across Desktop and Mobile. Does your method actually remove and allow for the duplication of components and id’s, or is it based on css display values - display: ‘none’ / ‘block/inline/inline-block’ based on viewport/screen size?

On internal functions of components I never had a need to limit anything based on view size.
But in some cases certain navigation components are hidden / changed / removed depending on screen size.

So on actual internal functionality i guess the answer is no in that regards.
Never had to, yet anyways :slight_smile:

I do think there is a breakpoint for actual sizes, not like in my example above which uses names. But a simple v-if="screenSize >= your needs to hide / show a component, or pass the :size="screenSize to a component as a prop for internal modifications. But there must be a native js that can do that similar to Vuetify.

Yep, I understand where you are coming from. I have built an app with 3 - 5 components that have internal logic and non vue logic/code associated to them also. My idea for the v-display=“mobile” directive (that destroys or removes it’s cloned desktop counterpart when a mobile is used) would allow developers to easily copy components (for the purposes of mobile rendering) whilst not having to worry about #id clashes/double-ups across devices. It would be (possibly) a very easy way to develop responsive apps. Yes, you can still do the same with multiple components (that have different selectors/ids) and media queries, but that would require additional coding and logic.

It would be nice to copy, say a desktop Nav.vue component, add a simple directive (mobile v-display=“mobile”) and know that the id #nav will be the only id and component when on mobile (even though there are 2 components). So easy, could apply media queries if needed and could also customize and edit the component itself (as there are 2, 1 for mobile, 1 for desktop/tablet etc). The mobile components could all go in there own dir e.g. /mobile-components/Nav.vue. So you have a clear and logical seperation of concern with mobile components in their own dir.

I think it comes back to the idea that some developers even with vue’s component structure are still going to target dom id’s for complex user interface development.

My biggest issue is the idea of multiple #ids with plain hide/show. I need dom removal to ensure no ui bugs will surface. Cloning internal component html and removing with additional code could work. I think the vue.js wizzards could come up with an approach like I mentioned.

A nice simple way to destroy a component on mobile and add another. (Not hide/show with css).

Just found out that v-if does conditional rendering, so it will suffice as a solution for now. I will do a device width check and render a mobile version of my components all within the same component (2 divs, one for mobile & one for desktop).

You wont even need 2 divs or even load both components.
Vue Dynamic Components

<component :is="getComponent()"></component>

And perhaps a simple method to dedice what one to show.

getComponent() {
   // isMobile would be some check to determine the validity of that, how ever you check for that 
   return isMobile ? 'MobileVersionComponent' : 'DesktopVersionComponent'
},