简体   繁体   中英

How do I get tailwinds active breakpoint in JavaScript?

I am building tailwind with config file and including it in a react project.

I would like to get the active breakpoint value in javascript/React. How can I achieve the same.?

 <div class="block sm:hidden md:hidden lg:hidden xl:hidden">al</div> <div class="hidden sm:block md:hidden lg:hidden xl:hidden">sm</div> <div class="hidden sm:hidden md:block lg:hidden xl:hidden">md</div> <div class="hidden sm:hidden md:hidden lg:block xl:hidden">lg</div> <div class="hidden sm:hidden md:hidden lg:hidden xl:block">xl</div> </div>

The above shows the active breakpoint. but how do i get the same in js without including any of the above markup.?

From the tailwind docs, you can import your config from the tailwindcss node module:

import resolveConfig from 'tailwindcss/resolveConfig'
import tailwindConfig from './tailwind.config.js'

const fullConfig = resolveConfig(tailwindConfig)

fullConfig.theme.width[4]
// => '1rem'

fullConfig.theme.screens.md
// => '768px'

fullConfig.theme.boxShadow['2xl']
// => '0 25px 50px -12px rgba(0, 0, 0, 0.25)'

As you can see above, you can get your breakpoints by referencing fullConfig.theme.screens.{breakpoint} . You should be able to compare this to your current screen width using javascript.

See more here .

Here's what I wrote in Typescript that returns the current breakpoint based on device width. You can place it in a standalone file and import the methods whenever needed in any file:

import resolveConfig from 'tailwindcss/resolveConfig';
import tailwindConfig from './tailwind.config'; // Fix the path

const fullConfig = resolveConfig(tailwindConfig);

export const getBreakpointValue = (value: string): number =>
  +fullConfig.theme.screens[value].slice(
    0,
    fullConfig.theme.screens[value].indexOf('px')
  );

export const getCurrentBreakpoint = (): string => {
  let currentBreakpoint: string;
  let biggestBreakpointValue = 0;
  for (const breakpoint of Object.keys(fullConfig.theme.screens)) {
    const breakpointValue = getBreakpointValue(breakpoint);
    if (
      breakpointValue > biggestBreakpointValue &&
      window.innerWidth >= breakpointValue
    ) {
      biggestBreakpointValue = breakpointValue;
      currentBreakpoint = breakpoint;
    }
  }
  return currentBreakpoint;
};

Edit: in newer Typescript versions you have to add these two parameters to tsconfig.json under compilerOptions in order to be able import js files:

"compilerOptions": {
  "allowJs": true,
  "allowsyntheticdefaultimports": true
}

Also, if you are on Angular and get the error that process is not defined, you have to add these lines to the end of your polyfills.ts file (you have to install the process package of course):

import * as process from 'process';
window['process'] = process;

If anyone is looking for an approach that doesn't use tailwind's config, you can achieve this by using tailwind's breakpoint system to control the visibility of several 0x0 divs, and test for the visibility of those divs to determine the current active breakpoint.

For example, you might embed several divs of size 0 in your body like so:

<div id="breakpoint-sm" class="hidden sm:block md:hidden lg:hidden xl:hidden 2xl:hidden w-0 h-0"></div>
<div id="breakpoint-md" class="hidden sm:hidden md:block lg:hidden xl:hidden 2xl:hidden w-0 h-0"></div>
<div id="breakpoint-lg" class="hidden sm:hidden md:hidden lg:block xl:hidden 2xl:hidden w-0 h-0"></div>
<div id="breakpoint-xl" class="hidden sm:hidden md:hidden lg:hidden xl:block 2xl:hidden w-0 h-0"></div>
<div id="breakpoint-2xl" class="hidden sm:hidden md:hidden lg:hidden xl:hidden 2xl:block w-0 h-0"></div>

Then, you can write a function that looks for these elements and checks if they are visible via each element's offsetParent property:

const getCurrentBreakpoint = (): string => {
    const breakpointUnknown: string = 'unknown';
    const breakpointSM: string | null = document.getElementById('breakpoint-sm')?.offsetParent === null ? null : 'sm';
    const breakpointMD: string | null = document.getElementById('breakpoint-md')?.offsetParent === null ? null : 'md';
    const breakpointLG: string | null = document.getElementById('breakpoint-lg')?.offsetParent === null ? null : 'lg';
    const breakpointXL: string | null = document.getElementById('breakpoint-xl')?.offsetParent === null ? null : 'xl';
    const breakpoint2XL: string | null = document.getElementById('breakpoint-2xl')?.offsetParent === null ? null : '2xl';
    const breakpoint = breakpointSM ?? breakpointMD ?? breakpointLG ?? breakpointXL ?? breakpoint2XL ?? breakpointUnknown;
    return breakpoint;
};

Now you can test for the current breakpoint string to perform some logic:

const breakpoint = getCurrentBreakpoint();
const desktopBreakpoints: string[] = ['sm', 'md', 'lg', 'xl'];
if (desktopBreakpoints.includes(breakpoint)) {
   // On Desktop (in Tailwind's eyes)
} else {
   // On Mobile (in Tailwind's eyes)
}

You'll need to ensure whatever breakpoints you have Tailwind using are both applied to a 0x0 div somewhere in your document that you can obtain, and to check for those breakpoints in your getCurrentBreakpoint() function. But this gets the job done without needing to inspect Tailwind's config and uses Tailwind's actual breakpoint system to determine which is currently active.

Here is a little hook for those using TypeScript 4.5+. It's based on the useMediaQuery hook from the react-responsive package. Modify it as you please!

import { useMediaQuery } from 'react-responsive';
import { theme } from '../../tailwind.config'; // Your tailwind config

const breakpoints = theme.screens;

type BreakpointKey = keyof typeof breakpoints;

export function useBreakpoint<K extends BreakpointKey>(breakpointKey: K) {
  const bool = useMediaQuery({
    query: `(min-width: ${breakpoints[breakpointKey]})`,
  });
  const capitalizedKey = breakpointKey[0].toUpperCase() + breakpointKey.substring(1);
  type Key = `is${Capitalize<K>}`;
  return {
    [`is${capitalizedKey}`]: bool,
  } as Record<Key, boolean>;
}

Inside your component, use it like this

const { isSm } = useBreakpoint('sm');
const { isMd } = useBreakpoint('md');
const { isLg } = useBreakpoint('lg');
return (
      <div>
        {isSm && (
          {/* Visible for sm: (min-width: 640px) */}
          <div>Content</div>
        )}

        {isMd && (
          {/* Visible for md: (min-width: 768px) */}
          <div>Content</div>
        )}
      </div>
  );

For this purpose I use this peace of code :

import { theme } from '../../tailwind.config';

export function getCurrentBreakpoints() {
    return Object.keys(theme.screens).find((key) => window.innerWidth > theme.screens[key]);
}

I can resolve this in React like this:

{/* MOBILE FIRST */}
<div className="sm:hidden">
  <Component breakpoint="mobile" />
</div>

{/* SMALL */}
<div className="hidden sm:block md:hidden">
  <Component breakpoint="sm" />
</div>


{/* MEDIUM */}
<div className="hidden md:block lg:hidden">
  <Component breakpoint="md" />
</div>


{/* LARGE */}
<div className="hidden lg:block xl:hidden">
  <Component breakpoint="xl" />
</div>

{/* EXTRA LARGE */}
<div className="hidden xl:block 2xl:hidden">
  <Component breakpoint="xl" />
</div>

and in my Component.jsx

import React from 'react'

const Component = (prop) => {
  const { breakpoint } = prop;
  return (
    <div>{breakpoint}</div>
  )
}
export default Component

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM