nuxt / ui

A UI Library for Modern Web Apps, powered by Vue & Tailwind CSS.
https://ui.nuxt.com
MIT License
4.01k stars 507 forks source link

Buttons size based on device? #2390

Open jeannen opened 2 weeks ago

jeannen commented 2 weeks ago

For what version of Nuxt UI are you asking this question?

v2.x

Description

Hi!

I was wondering if there was an easy way to change variants/sizes etc for components (particularly buttons) based on the user's device

For example,

<UButton size="sm xl:lg"/>

There are lots of instances where a button need to be smaller on mobile, so would be nice to have that! I didn't found anything in the docs

P.S. bought Nuxt UI Pro a couple of days ago to support the team. Keep up the great work! 😄

gregorvoinov commented 2 weeks ago

I think there are two options

1) you can create a computed prop that gets updated on resize

<script setup>
const windowWidth = ref(window?.innerWidth);
onMounted(() => {
  window.addEventListener('resize', () => {
    windowWidth.value = window.innerWidth;
  });
});
const btnSize = computed(() => {
  if (windowWidth.value < 800) {
    return 'md';
  } else {
    return 'xl';
  }
});
</script>
<template>
  <UContainer class="min-h-screen flex items-center">
    <UButton :size="btnSize">Button Size</UButton>
  </UContainer>
</template>

2) or just update the defaults and add responsive breakpoints

padding: {
  '2xs': 'px-1 py-0.5 lg:px-2 lg:py-1',
  xs: 'px-2 py-1 lg:px-2.5 lg:py-1.5',
  sm: 'px-2 py-1 lg:px-2.5 lg:py-1.5',
  md: 'px-2 py-1.5 lg:px-3 lg:py-2',
  lg: 'px-2.5 py-1.5 lg:px-3.5 lg:py-2.5',
  xl: 'px-3 py-1.5 lg:px-4 lg:py-2.5',
},
jeannen commented 2 weeks ago

Option 1 would means adding a computed value for every different button, so that would be a bit overkill

And Option 2 would not really works, some buttons need to keep the same size and others need to get bigger

gregorvoinov commented 2 weeks ago

for sure you have to wrap this around another component let's call it responsiveButton

//responsiveButton.vue
<script setup>
  const props = {
    size: {
      default: 'md',
    },
  };
</script>

<template>
  <UButton 
    :size="props.size"
    :ui={
      padding: {
        '2xs': 'px-1 py-0.5 lg:px-2 lg:py-1',
        xs: 'px-2 py-1 lg:px-2.5 lg:py-1.5',
        sm: 'px-2 py-1 lg:px-2.5 lg:py-1.5',
        md: 'px-2 py-1.5 lg:px-3 lg:py-2',
        lg: 'px-2.5 py-1.5 lg:px-3.5 lg:py-2.5',
        xl: 'px-3 py-1.5 lg:px-4 lg:py-2.5',
      }
    }
  >
    <slot></slot>
  </UButton>
</template>

also for variant 1 you should create a wrapper component around your logic

noook commented 2 weeks ago

Note that you could use useBreakpoints() from VueUse to help you with this