├── src
├── primitives
│ ├── Div
│ │ ├── index.js
│ │ └── index.native.js
│ ├── Span
│ │ ├── index.js
│ │ └── index.native.js
│ ├── Window
│ │ ├── index.js
│ │ └── index.native.js
│ └── index.js
├── introduction.md
├── utilities
│ ├── Hidden
│ │ ├── style.js
│ │ └── index.js
│ ├── Visible
│ │ ├── style.js
│ │ └── index.js
│ └── ScreenClassRender
│ │ ├── Readme.md
│ │ └── index.js
├── config.js
├── index.js
├── context
│ ├── ScreenClassResolver
│ │ └── index.js
│ └── ScreenClassProvider
│ │ ├── Readme.md
│ │ └── index.js
├── context.md
├── grid
│ ├── Container
│ │ ├── style.js
│ │ └── index.js
│ ├── Row
│ │ ├── style.js
│ │ └── index.js
│ └── Col
│ │ ├── style.js
│ │ └── index.js
├── utils.js
├── utilities.md
└── grid.md
├── .gitignore
├── .babelrc.js
├── .prettierrc.json
├── .eslintrc
├── docs
├── index.html
└── build
│ └── bundle.4b7c0373.js.LICENSE.txt
├── .github
└── workflows
│ └── node.js.yml
├── styleguide.config.js
├── LICENSE
├── eslint.config.mjs
├── package.json
├── index.d.ts
└── README.md
/src/primitives/Div/index.js:
--------------------------------------------------------------------------------
1 | export default 'div'
2 |
--------------------------------------------------------------------------------
/src/primitives/Span/index.js:
--------------------------------------------------------------------------------
1 | export default 'span'
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | example/build/
4 | /build
5 |
--------------------------------------------------------------------------------
/.babelrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['@babel/preset-react', '@babel/preset-env'],
3 | }
4 |
--------------------------------------------------------------------------------
/src/primitives/Span/index.native.js:
--------------------------------------------------------------------------------
1 | import { View } from 'react-native'
2 |
3 | export default View
4 |
--------------------------------------------------------------------------------
/src/primitives/Window/index.js:
--------------------------------------------------------------------------------
1 | /* global window */
2 |
3 | export default typeof window !== 'undefined' ? window : undefined;
4 |
--------------------------------------------------------------------------------
/src/primitives/index.js:
--------------------------------------------------------------------------------
1 | export { default as Div } from './Div';
2 |
3 | export { default as Span } from './Span';
4 |
5 | export { default as Window } from './Window';
6 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "tabWidth": 2,
3 | "semi": true,
4 | "singleQuote": true,
5 | "printWidth": 200,
6 | "useTabs": false,
7 | "trailingComma": "all",
8 | "bracketSpacing": true,
9 | "arrowParens": "always"
10 | }
11 |
--------------------------------------------------------------------------------
/src/introduction.md:
--------------------------------------------------------------------------------
1 | A powerful Bootstrap-like responsive grid system for React.
2 |
3 | For more information on these components, view this project on GitHub: [https://github.com/sealninja/react-grid-system](https://github.com/sealninja/react-grid-system)
4 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 | "parser": "@babel/eslint-parser",
4 | "rules": {
5 | "react/jsx-filename-extension": "off",
6 | "react/prefer-stateless-function": "off",
7 | "react/destructuring-assignment": "off"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/primitives/Div/index.native.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { View } from 'react-native'
3 |
4 | export default ({
5 | children,
6 | style,
7 | ...rest
8 | }) => (
9 |
13 | {children}
14 |
15 | )
16 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | React Grid System (v8.2.1)
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/utilities/Hidden/style.js:
--------------------------------------------------------------------------------
1 | export const hidden = ({
2 | screenClass, xs, sm, md, lg, xl, xxl, xxxl,
3 | }) => {
4 | if (screenClass === 'xxl') return xxl;
5 | if (screenClass === 'xxxl') return xxxl;
6 | if (screenClass === 'xl') return xl;
7 | if (screenClass === 'lg') return lg;
8 | if (screenClass === 'md') return md;
9 | if (screenClass === 'sm') return sm;
10 | return xs;
11 | };
12 |
13 | export default hidden;
14 |
--------------------------------------------------------------------------------
/src/utilities/Visible/style.js:
--------------------------------------------------------------------------------
1 | export const visible = ({
2 | screenClass, xs, sm, md, lg, xl, xxl, xxxl
3 | }) => {
4 | if (screenClass === 'xxl') return xxl;
5 | if (screenClass === 'xxxl') return xxxl;
6 | if (screenClass === 'xl') return xl;
7 | if (screenClass === 'lg') return lg;
8 | if (screenClass === 'md') return md;
9 | if (screenClass === 'sm') return sm;
10 | return xs;
11 | };
12 |
13 | export default visible;
14 |
--------------------------------------------------------------------------------
/src/utilities/ScreenClassRender/Readme.md:
--------------------------------------------------------------------------------
1 | Example usage, rendering a font size based on the screen class:
2 |
3 | ```
4 | (
5 |
6 | Screen class: {screenClass}
7 |
8 | )} />
9 |
10 | ```
11 |
12 | Alternatively, the `useScreenClass` hook can be used for rendering a component differently based on the screen class.
13 |
--------------------------------------------------------------------------------
/src/config.js:
--------------------------------------------------------------------------------
1 | let configuration = {
2 | breakpoints: [576, 768, 992, 1200, 1600, 1920],
3 | containerWidths: [540, 750, 960, 1140, 1540, 1810],
4 | gutterWidth: 30,
5 | gridColumns: 12,
6 | defaultScreenClass: 'xxl',
7 | maxScreenClass: 'xxl',
8 | };
9 |
10 | export const getConfiguration = () => configuration;
11 |
12 | export const setConfiguration = (newConfiguration) => {
13 | configuration = { ...configuration, ...newConfiguration };
14 | };
15 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | // Grid
2 | export { default as Col } from './grid/Col';
3 | export { default as Container } from './grid/Container';
4 | export { default as Row } from './grid/Row';
5 |
6 | // Utilities
7 | export { default as Hidden } from './utilities/Hidden';
8 | export { default as Visible } from './utilities/Visible';
9 | export { default as ScreenClassRender } from './utilities/ScreenClassRender';
10 | export { default as ScreenClassProvider, ScreenClassContext } from './context/ScreenClassProvider';
11 | export { setConfiguration } from './config';
12 | export { useScreenClass } from './utils';
13 |
--------------------------------------------------------------------------------
/src/utilities/ScreenClassRender/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import ScreenClassResolver from '../../context/ScreenClassResolver';
4 |
5 | const ScreenClassRender = ({ render }) => (
6 |
7 | {(screenClass) => render(screenClass)}
8 |
9 | );
10 |
11 | ScreenClassRender.propTypes = {
12 | /**
13 | * The function which return value will be rendered.
14 | * Will be called with one argument: the screen class.
15 | */
16 | render: PropTypes.func.isRequired,
17 | };
18 |
19 | export default ScreenClassRender;
20 |
--------------------------------------------------------------------------------
/src/primitives/Window/index.native.js:
--------------------------------------------------------------------------------
1 | import { Dimensions } from 'react-native'
2 |
3 | const WindowRef = { current: null }
4 |
5 | const { width, height } = Dimensions.get('window')
6 |
7 | WindowRef.current = {
8 | innerWidth: width,
9 | innerHeight: height,
10 | addEventListener: (___, callback) => {
11 | Dimensions.addEventListener('change', ({ window }) => {
12 | const {
13 | current: Window
14 | } = WindowRef
15 | Window.innerWidth = window.width
16 | Window.innerHeight = window.height
17 | callback()
18 | })
19 | },
20 | removeEventListener: (___, callback) => {
21 | Dimensions.removeEventListener('change', callback)
22 | },
23 | }
24 |
25 | export default WindowRef.current
26 |
--------------------------------------------------------------------------------
/.github/workflows/node.js.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: Node.js CI
5 |
6 | on:
7 | push:
8 | branches: [master]
9 | pull_request:
10 | branches: [master]
11 |
12 | jobs:
13 | build:
14 | runs-on: ubuntu-latest
15 |
16 | strategy:
17 | matrix:
18 | node-version: [22]
19 |
20 | steps:
21 | - uses: actions/checkout@v2
22 | - name: Use Node.js ${{ matrix.node-version }}
23 | uses: actions/setup-node@v2
24 | with:
25 | node-version: ${{ matrix.node-version }}
26 | - run: yarn --frozen-lockfile
27 | - run: yarn build
28 | - run: yarn lint
29 | - run: yarn docs
30 |
--------------------------------------------------------------------------------
/src/context/ScreenClassResolver/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import ScreenClassProvider, { ScreenClassContext, NO_PROVIDER_FLAG } from '../ScreenClassProvider';
4 |
5 | const ScreenClassResolver = ({ children }) => (
6 |
7 | {(screenClassCheck) => {
8 | if (screenClassCheck === NO_PROVIDER_FLAG) {
9 | return (
10 |
11 |
12 | {(screenClassResolved) => children(screenClassResolved)}
13 |
14 |
15 | );
16 | }
17 | return children(screenClassCheck);
18 | }}
19 |
20 | );
21 |
22 | ScreenClassResolver.propTypes = {
23 | children: PropTypes.func.isRequired,
24 | };
25 |
26 | export default ScreenClassResolver;
27 |
--------------------------------------------------------------------------------
/src/context.md:
--------------------------------------------------------------------------------
1 | Internally, every component that requires the current `screenClass` (which is a human-readable string version of the `window.innerWidth` relating to the user's breakpoints) subscribes to a `ScreenClassProvider`. The provider utilizes the [React Context API](https://reactjs.org/docs/context.html) to send down the current `screenClass` as it updates. By default, each instance of every component subscribes to a separate provider, creating `resize` listeners for each. This can cut down renders during a resize event from ~300 to 4 (one for each breakpoint) making the grid much more performant.
2 |
3 | ---
4 |
5 | ### Do I need to change anything in my code?
6 |
7 | This new API is entirely opt-in and current implementations will continue to work. However, for a signficiant performance increase, you will need to add the `ScreenClassProvider` to your application, typically at the highest level in the React node tree (i.e, App.js).
8 |
--------------------------------------------------------------------------------
/src/context/ScreenClassProvider/Readme.md:
--------------------------------------------------------------------------------
1 | ```jsx static
2 | import React from 'react';
3 | import { ScreenClassProvider } from 'react-grid-system';
4 |
5 | export default function App() {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 | ```
15 |
16 | Internally, the `ScreenClassProvider` attaches a `resize` listener and then updates `state.screenClass` exclusively when a new breakpoint is hit. The `state.screenClass` value is then attached to `ScreenClassContext.Provider`. ScreenClass-dependent components are wrapped with `ScreenClassResolver` which checks to see if there is a valid provider above it and provides one if there is not.
17 |
18 | The performance benefit comes from _you_ adding a `ScreenClassProvider` to your application which allows `react-grid-system` components to subscribe to **one source of truth** for the ScreenClass.
19 |
--------------------------------------------------------------------------------
/styleguide.config.js:
--------------------------------------------------------------------------------
1 | const { version } = require('./package.json');
2 |
3 | module.exports = {
4 | title: `React Grid System (v${version})`,
5 | sections: [
6 | {
7 | name: 'Introduction',
8 | content: 'src/introduction.md',
9 | },
10 | {
11 | name: 'Responsive grid',
12 | components: 'src/grid/**/index.js',
13 | content: 'src/grid.md',
14 | },
15 | {
16 | name: 'Responsive utilities',
17 | components: 'src/utilities/**/index.js',
18 | content: 'src/utilities.md',
19 | },
20 | {
21 | name: 'ScreenClass Context API',
22 | components: 'src/context/ScreenClassProvider/index.js',
23 | content: 'src/context.md',
24 | },
25 | ],
26 | styleguideDir: './docs',
27 | exampleMode: 'expand',
28 | usageMode: 'expand',
29 | webpackConfig: {
30 | module: {
31 | rules: [
32 | {
33 | test: /\.js$/,
34 | exclude: /node_modules/,
35 | loader: 'babel-loader',
36 | },
37 | ],
38 | },
39 | },
40 | };
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Sealninja
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/utilities/Hidden/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import * as style from "./style";
4 | import ScreenClassResolver from "../../context/ScreenClassResolver";
5 |
6 | const Hidden = ({
7 | children,
8 | xs = false,
9 | sm = false,
10 | md = false,
11 | lg = false,
12 | xl = false,
13 | xxl = false,
14 | xxxl = false,
15 | }) => (
16 |
17 | {(screenClass) =>
18 | style.hidden({
19 | screenClass,
20 | xs,
21 | sm,
22 | md,
23 | lg,
24 | xl,
25 | xxl,
26 | xxxl,
27 | })
28 | ? null
29 | : children
30 | }
31 |
32 | );
33 |
34 | Hidden.propTypes = {
35 | /**
36 | * Content of the component
37 | */
38 | children: PropTypes.node.isRequired,
39 | /**
40 | * Hide on extra small devices
41 | */
42 | xs: PropTypes.bool,
43 | /**
44 | * Hide on small devices
45 | */
46 | sm: PropTypes.bool,
47 | /**
48 | * Hide on medium devices
49 | */
50 | md: PropTypes.bool,
51 | /**
52 | * Hide on large devices
53 | */
54 | lg: PropTypes.bool,
55 | /**
56 | * Hide on xlarge devices
57 | */
58 | xl: PropTypes.bool,
59 | /**
60 | * Hide on xxlarge devices
61 | */
62 | xxl: PropTypes.bool,
63 | /**
64 | * Hide on xxxlarge devices
65 | */
66 | xxxl: PropTypes.bool,
67 | };
68 |
69 | export default Hidden;
70 |
--------------------------------------------------------------------------------
/src/utilities/Visible/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import * as style from "./style";
4 | import ScreenClassResolver from "../../context/ScreenClassResolver";
5 |
6 | const Visible = ({
7 | children,
8 | xs = false,
9 | sm = false,
10 | md = false,
11 | lg = false,
12 | xl = false,
13 | xxl = false,
14 | xxxl = false,
15 | }) => (
16 |
17 | {(screenClass) =>
18 | !style.visible({
19 | screenClass,
20 | xs,
21 | sm,
22 | md,
23 | lg,
24 | xl,
25 | xxl,
26 | xxxl,
27 | })
28 | ? null
29 | : children
30 | }
31 |
32 | );
33 |
34 | Visible.propTypes = {
35 | /**
36 | * Content of the component
37 | */
38 | children: PropTypes.node.isRequired,
39 | /**
40 | * Show on extra small devices
41 | */
42 | xs: PropTypes.bool,
43 | /**
44 | * Show on small devices
45 | */
46 | sm: PropTypes.bool,
47 | /**
48 | * Show on medium devices
49 | */
50 | md: PropTypes.bool,
51 | /**
52 | * Show on large devices
53 | */
54 | lg: PropTypes.bool,
55 | /**
56 | * Show on xlarge devices
57 | */
58 | xl: PropTypes.bool,
59 | /**
60 | * Show on xxlarge devices
61 | */
62 | xxl: PropTypes.bool,
63 | /**
64 | * Show on xxxlarge devices
65 | */
66 | xxxl: PropTypes.bool,
67 | };
68 |
69 | export default Visible;
70 |
--------------------------------------------------------------------------------
/src/grid/Container/style.js:
--------------------------------------------------------------------------------
1 | export default ({
2 | fluid,
3 | xs,
4 | sm,
5 | md,
6 | lg,
7 | xl,
8 | xxl,
9 | xxxl,
10 | screenClass,
11 | containerWidths,
12 | gutterWidth,
13 | moreStyle,
14 | }) => {
15 | const styles = {
16 | boxSizing: 'border-box',
17 | position: 'relative',
18 | marginLeft: 'auto',
19 | marginRight: 'auto',
20 | paddingLeft: gutterWidth / 2,
21 | paddingRight: gutterWidth / 2,
22 | };
23 |
24 | if (fluid && !xs && !sm && !md && !lg && !xl) {
25 | return { ...styles, ...moreStyle };
26 | }
27 |
28 | if (screenClass === 'xs' && containerWidths[0] && !xs) {
29 | styles.maxWidth = containerWidths[0];
30 | }
31 |
32 | if (screenClass === 'sm' && containerWidths[0] && !sm) {
33 | styles.maxWidth = containerWidths[0];
34 | }
35 |
36 | if (screenClass === 'md' && containerWidths[1] && !md) {
37 | styles.maxWidth = containerWidths[1];
38 | }
39 |
40 | if (screenClass === 'lg' && containerWidths[2] && !lg) {
41 | styles.maxWidth = containerWidths[2];
42 | }
43 |
44 | if (screenClass === 'xl' && containerWidths[3] && !xl) {
45 | styles.maxWidth = containerWidths[3];
46 | }
47 |
48 | if (screenClass === 'xxl' && containerWidths[4] && !xxl) {
49 | styles.maxWidth = containerWidths[4];
50 | }
51 | if (screenClass === 'xxxl' && containerWidths[5] && !xxxl) {
52 | styles.maxWidth = containerWidths[5];
53 | }
54 |
55 | return { ...styles, ...moreStyle };
56 | };
57 |
--------------------------------------------------------------------------------
/src/grid/Row/style.js:
--------------------------------------------------------------------------------
1 | export default ({
2 | gutterWidth, align, justify, debug, moreStyle, direction, wrap
3 | }) => {
4 | // Vertical alignment
5 | let alignItems = align;
6 | if (align === 'start') alignItems = 'flex-start';
7 | if (align === 'end') alignItems = 'flex-end';
8 |
9 | // Horizontal alignment
10 | let justifyContent = justify;
11 | if (justify === 'start') justifyContent = 'flex-start';
12 | if (justify === 'end') justifyContent = 'flex-end';
13 | if (justify === 'between') justifyContent = 'space-between';
14 | if (justify === 'around') justifyContent = 'space-around';
15 | if (justify === 'center') justifyContent = 'center';
16 | if (justify === 'initial') justifyContent = 'initial';
17 | if (justify === 'inherit') justifyContent = 'inherit';
18 |
19 | const flexDirection = ['column', 'row', 'column-reverse', 'row-reverse'].includes(direction) ? direction : undefined;
20 |
21 | let flexWrap = wrap;
22 | if (wrap === 'nowrap') flexWrap = 'nowrap';
23 | if (wrap === 'wrap') flexWrap = 'wrap';
24 | if (wrap === 'reverse') flexWrap = 'wrap-reverse';
25 |
26 | const styles = {
27 | marginLeft: -gutterWidth / 2,
28 | marginRight: -gutterWidth / 2,
29 | display: 'flex',
30 | flexGrow: 0,
31 | flexShrink: 0,
32 | alignItems,
33 | justifyContent,
34 | flexDirection,
35 | flexWrap
36 | };
37 |
38 | if (debug) {
39 | styles.background = 'rgba(128,128,128,.05)';
40 | }
41 |
42 | return { ...styles, ...moreStyle };
43 | };
44 |
--------------------------------------------------------------------------------
/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import prettier from 'eslint-plugin-prettier';
2 | import babelParser from '@babel/eslint-parser';
3 | import path from 'node:path';
4 | import { fileURLToPath } from 'node:url';
5 | import js from '@eslint/js';
6 | import { FlatCompat } from '@eslint/eslintrc';
7 | import { fixupPluginRules, fixupConfigRules } from '@eslint/compat';
8 | import importPlugin from 'eslint-plugin-import';
9 |
10 | const __filename = fileURLToPath(import.meta.url);
11 | const __dirname = path.dirname(__filename);
12 | const compat = new FlatCompat({
13 | baseDirectory: __dirname,
14 | recommendedConfig: js.configs.recommended,
15 | allConfig: js.configs.all,
16 | });
17 |
18 | export default [
19 | ...fixupConfigRules(compat.extends('airbnb', 'airbnb/hooks')),
20 | ...compat.extends('prettier', 'plugin:prettier/recommended'),
21 | {
22 | plugins: {
23 | prettier,
24 | import: fixupPluginRules(importPlugin),
25 | },
26 |
27 | languageOptions: {
28 | globals: {
29 | fetch: 'readonly',
30 | JSX: true,
31 | },
32 |
33 | parser: babelParser,
34 | },
35 |
36 | settings: {
37 | 'import/resolver': {
38 | node: {},
39 | exports: {},
40 | },
41 | },
42 |
43 | rules: {
44 | 'react/jsx-filename-extension': 'off',
45 | 'no-underscore-dangle': 'off',
46 | 'react/forbid-prop-types': 'off',
47 | 'react/jsx-fragments': 'off',
48 | 'import/no-named-as-default': 'off',
49 | 'import/no-named-as-default-member': 'off',
50 | },
51 | },
52 | ];
53 |
--------------------------------------------------------------------------------
/src/context/ScreenClassProvider/index.js:
--------------------------------------------------------------------------------
1 | import React, { useRef, useState, useEffect } from "react";
2 | import PropTypes from "prop-types";
3 | import { useScreenClass } from "../../utils";
4 | import { getConfiguration } from "../../config";
5 | import { Div } from "../../primitives";
6 |
7 | export const NO_PROVIDER_FLAG = "NO_PROVIDER_FLAG";
8 |
9 | export const ScreenClassContext = React.createContext(NO_PROVIDER_FLAG);
10 |
11 | const ScreenClassProvider = ({
12 | useOwnWidth = false,
13 | children,
14 | fallbackScreenClass = null,
15 | }) => {
16 | const screenClassRef = useRef();
17 | const [mounted, setMounted] = useState(false);
18 | const detectedScreenClass = useScreenClass(
19 | screenClassRef,
20 | fallbackScreenClass
21 | );
22 | const { defaultScreenClass } = getConfiguration();
23 |
24 | const screenClass = mounted
25 | ? detectedScreenClass
26 | : fallbackScreenClass || defaultScreenClass;
27 |
28 | useEffect(() => setMounted(true), []);
29 |
30 | return (
31 |
32 | {useOwnWidth ? (
33 | {children}
34 | ) : (
35 | <>{children}>
36 | )}
37 |
38 | );
39 | };
40 |
41 | ScreenClassProvider.propTypes = {
42 | /**
43 | * Children of the ScreenClassProvider.
44 | * This should be all your child React nodes that are using `react-grid-system`.
45 | */
46 | children: PropTypes.node.isRequired,
47 | /**
48 | * Boolean to determine whether own width should be used as source.
49 | * When provided, the screen class is derived from own dimensions instead of the window.
50 | */
51 | useOwnWidth: PropTypes.bool,
52 | /**
53 | * Screen class to use when it cannot be determined otherwise.
54 | * Useful for server side rendering.
55 | */
56 | fallbackScreenClass: PropTypes.oneOf([
57 | null,
58 | "xs",
59 | "sm",
60 | "md",
61 | "lg",
62 | "xl",
63 | "xxl",
64 | "xxxl",
65 | ]),
66 | };
67 |
68 | export default ScreenClassProvider;
69 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-grid-system",
3 | "version": "8.2.1",
4 | "description": "A powerful Bootstrap-like responsive grid system for React.",
5 | "main": "./build/index.js",
6 | "scripts": {
7 | "start": "styleguidist server",
8 | "build": "rimraf build && npx browserslist --update-db && babel src -d build",
9 | "docs": "styleguidist build",
10 | "lint": "eslint *.js src/**/*.js",
11 | "test": "echo \"Error: no test specified\" && exit 1",
12 | "prepare": "npm run build"
13 | },
14 | "types": "./index.d.ts",
15 | "files": [
16 | "build",
17 | "src",
18 | "index.d.ts"
19 | ],
20 | "repository": {
21 | "type": "git",
22 | "url": "git+https://github.com/sealninja/react-grid-system.git"
23 | },
24 | "keywords": [
25 | "react",
26 | "bootstrap",
27 | "grid",
28 | "responsive"
29 | ],
30 | "author": "Sealninja",
31 | "license": "MIT",
32 | "bugs": {
33 | "url": "https://github.com/sealninja/react-grid-system/issues"
34 | },
35 | "homepage": "https://github.com/sealninja/react-grid-system/issues",
36 | "browserslist": "> 0.5%, last 2 versions, Firefox ESR, not dead",
37 | "peerDependencies": {
38 | "react": "^16.8.0 || ^17.x || ^18.x"
39 | },
40 | "dependencies": {
41 | "prop-types": "15.8.1"
42 | },
43 | "devDependencies": {
44 | "@babel/cli": "7.28.3",
45 | "@babel/core": "7.28.5",
46 | "@babel/eslint-parser": "7.28.5",
47 | "@babel/preset-env": "7.28.5",
48 | "@babel/preset-react": "7.28.5",
49 | "babel-eslint": "10.1.0",
50 | "babel-loader": "9.2.1",
51 | "eslint": "9.39.2",
52 | "@eslint/compat": "2.0.0",
53 | "@eslint/eslintrc": "3.3.3",
54 | "@eslint/js": "9.39.2",
55 | "eslint-config-airbnb": "19.0.4",
56 | "eslint-config-prettier": "10.1.8",
57 | "eslint-plugin-import": "2.32.0",
58 | "eslint-plugin-jsx-a11y": "6.10.2",
59 | "eslint-plugin-prettier": "5.5.4",
60 | "eslint-plugin-react": "7.37.5",
61 | "eslint-plugin-react-hooks": "7.0.1",
62 | "prettier": "3.7.4",
63 | "react": "19.2.3",
64 | "react-dom": "19.2.3",
65 | "react-styleguidist": "13.1.4",
66 | "rimraf": "6.1.2",
67 | "webpack": "5.104.1"
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/utils.js:
--------------------------------------------------------------------------------
1 | /* global window */
2 |
3 | import { useState, useEffect } from 'react';
4 | import { getConfiguration } from './config';
5 | import { Window } from './primitives'
6 |
7 | const getViewPort = (source) => {
8 | if (source && source.current && source.current.clientWidth) {
9 | return source.current.clientWidth;
10 | }
11 | if (typeof Window !== 'undefined' && Window.innerWidth) {
12 | return Window.innerWidth;
13 | }
14 | return null;
15 | };
16 |
17 | export const screenClasses = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl', 'xxxl'];
18 |
19 | export const useScreenClass = (source, fallbackScreenClass) => {
20 | const getScreenClass = () => {
21 | const { breakpoints, defaultScreenClass, maxScreenClass } = getConfiguration();
22 |
23 | let newScreenClass = defaultScreenClass;
24 |
25 | const viewport = getViewPort(source);
26 | if (viewport) {
27 | newScreenClass = 'xs';
28 | if (breakpoints[0] && viewport >= breakpoints[0]) newScreenClass = 'sm';
29 | if (breakpoints[1] && viewport >= breakpoints[1]) newScreenClass = 'md';
30 | if (breakpoints[2] && viewport >= breakpoints[2]) newScreenClass = 'lg';
31 | if (breakpoints[3] && viewport >= breakpoints[3]) newScreenClass = 'xl';
32 | if (breakpoints[4] && viewport >= breakpoints[4]) newScreenClass = 'xxl';
33 | if (breakpoints[5] && viewport >= breakpoints[5]) newScreenClass = 'xxxl';
34 | } else if (fallbackScreenClass) {
35 | newScreenClass = fallbackScreenClass;
36 | }
37 |
38 | const newScreenClassIndex = screenClasses.indexOf(newScreenClass);
39 | const maxScreenClassIndex = screenClasses.indexOf(maxScreenClass);
40 | if (maxScreenClassIndex >= 0 && newScreenClassIndex > maxScreenClassIndex) {
41 | newScreenClass = screenClasses[maxScreenClassIndex];
42 | }
43 |
44 | return newScreenClass;
45 | };
46 |
47 | const [screenClass, setScreenClass] = useState(() => getScreenClass());
48 |
49 |
50 | useEffect(() => {
51 | const handleWindowResized = () => setScreenClass(getScreenClass());
52 |
53 | Window.addEventListener('resize', handleWindowResized, false);
54 |
55 | return () => {
56 | Window.removeEventListener('resize', handleWindowResized, false);
57 | };
58 | }, []);
59 |
60 | return screenClass;
61 | };
62 |
--------------------------------------------------------------------------------
/docs/build/bundle.4b7c0373.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /*
2 | object-assign
3 | (c) Sindre Sorhus
4 | @license MIT
5 | */
6 |
7 | /*!
8 | * @overview es6-promise - a tiny implementation of Promises/A+.
9 | * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
10 | * @license Licensed under MIT license
11 | * See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
12 | * @version v4.2.8+1e68dce6
13 | */
14 |
15 | /*!
16 | * The buffer module from node.js, for the browser.
17 | *
18 | * @author Feross Aboukhadijeh
19 | * @license MIT
20 | */
21 |
22 | /*!
23 | * regjsgen 0.5.2
24 | * Copyright 2014-2020 Benjamin Tan
25 | * Available under the MIT license
26 | */
27 |
28 | /*! clipboard-copy. MIT License. Feross Aboukhadijeh */
29 |
30 | /*! https://mths.be/regenerate v1.4.2 by @mathias | MIT license */
31 |
32 | /**
33 | * @license React
34 | * react-dom.production.min.js
35 | *
36 | * Copyright (c) Facebook, Inc. and its affiliates.
37 | *
38 | * This source code is licensed under the MIT license found in the
39 | * LICENSE file in the root directory of this source tree.
40 | */
41 |
42 | /**
43 | * @license React
44 | * react.production.min.js
45 | *
46 | * Copyright (c) Facebook, Inc. and its affiliates.
47 | *
48 | * This source code is licensed under the MIT license found in the
49 | * LICENSE file in the root directory of this source tree.
50 | */
51 |
52 | /**
53 | * @license React
54 | * scheduler.production.min.js
55 | *
56 | * Copyright (c) Facebook, Inc. and its affiliates.
57 | *
58 | * This source code is licensed under the MIT license found in the
59 | * LICENSE file in the root directory of this source tree.
60 | */
61 |
62 | /**
63 | * A better abstraction over CSS.
64 | *
65 | * @copyright Oleg Isonen (Slobodskoi) / Isonen 2014-present
66 | * @website https://github.com/cssinjs/jss
67 | * @license MIT
68 | */
69 |
70 | /**
71 | * Prism: Lightweight, robust, elegant syntax highlighting
72 | *
73 | * @license MIT
74 | * @author Lea Verou
75 | * @namespace
76 | * @public
77 | */
78 |
--------------------------------------------------------------------------------
/src/grid/Col/style.js:
--------------------------------------------------------------------------------
1 | import { screenClasses } from '../../utils';
2 |
3 | const hasWidth = (widths) => Object.keys(widths).reduce((acc, cur) => acc || widths[cur], false);
4 |
5 | const getWidth = (width, gridColumns) => {
6 | if (typeof width !== 'number') return undefined;
7 | const normalizedWidth = Math.max(0, Math.min(gridColumns, width));
8 | return `${(100 / gridColumns) * normalizedWidth}%`;
9 | };
10 |
11 | export default ({
12 | forceWidth = null,
13 | width = {},
14 | offset = {},
15 | pull = {},
16 | push = {},
17 | order = {},
18 | debug,
19 | screenClass,
20 | gutterWidth,
21 | moreStyle,
22 | gridColumns,
23 | }) => {
24 | const styles = {
25 | boxSizing: 'border-box',
26 | minHeight: 1,
27 | position: 'relative',
28 | paddingLeft: gutterWidth / 2,
29 | paddingRight: gutterWidth / 2,
30 | width: '100%',
31 | };
32 |
33 | if (debug) {
34 | styles.outline = '1px solid silver';
35 | styles.background = 'rgba(0,0,0,.05)';
36 | styles.lineHeight = '32px';
37 | }
38 |
39 | styles.flexBasis = '100%';
40 | styles.flexGrow = 0;
41 | styles.flexShrink = 0;
42 | styles.maxWidth = '100%';
43 | styles.marginLeft = '0%';
44 | styles.right = 'auto';
45 | styles.left = 'auto';
46 |
47 | screenClasses.forEach((size, index) => {
48 | if (screenClasses.indexOf(screenClass) >= index) {
49 | const currentWidth = getWidth(width[size], gridColumns);
50 | const isSizedToContent = width[size] === 'content';
51 |
52 | styles.flexBasis = (isSizedToContent ? 'auto' : (currentWidth || styles.flexBasis));
53 | styles.width = styles.flexBasis;
54 | styles.maxWidth = currentWidth || styles.maxWidth;
55 | styles.marginLeft = getWidth(offset[size], gridColumns) || styles.marginLeft;
56 | styles.right = getWidth(pull[size], gridColumns) || styles.right;
57 | styles.left = getWidth(push[size], gridColumns) || styles.left;
58 | if(order[size]) {
59 | styles.order = order[size]
60 | }
61 | }
62 | });
63 |
64 | if (!hasWidth(width)) {
65 | styles.flexBasis = 0;
66 | styles.flexGrow = 1;
67 | }
68 |
69 | if (forceWidth) {
70 | styles.flexBasis = 'unset';
71 | styles.flexGrow = 'unset';
72 | styles.flexShrink = 'unset';
73 | styles.width = forceWidth;
74 | }
75 |
76 | return { ...styles, ...moreStyle };
77 | };
78 |
--------------------------------------------------------------------------------
/src/utilities.md:
--------------------------------------------------------------------------------
1 | Resize your browser or load on different devices to test the responsive utility components.
2 |
3 | ```js
4 | import { Row, Col, Visible, Hidden } from '.';
5 |
6 |
7 | Your current screen class is
8 | xs
9 | sm
10 | md
11 | lg
12 | xl
13 | xxl
14 | .
15 |
16 | ```
17 |
18 | In below examples, green indicates the element is visible in your current viewport.
19 |
20 | ```js
21 | import { Row, Col, Visible, Hidden } from '.';
22 |
23 |
24 |
25 | x-small
26 | Visible on x-small
27 |
28 |
29 | Small
30 | Visible on small
31 |
32 |
33 | Medium
34 | Visible on medium
35 |
36 |
37 | Large
38 | Visible on large
39 |
40 |
41 | x-large
42 | Visible on x-large
43 |
44 |
45 | xx-large
46 | Visible on xx-large
47 |
48 |
49 | ```
50 |
51 | ```js
52 | import { Row, Col, Visible, Hidden } from '.';
53 |
54 |
55 |
56 | Extra small and small
57 | Visible on extra small and small
58 |
59 |
60 | Medium and large
61 | Visible on medium and large
62 |
63 |
64 | x-large and xx-large
65 | Visible on x-large and xx-large
66 |
67 |
68 | ```
69 |
--------------------------------------------------------------------------------
/src/grid/Row/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 | import { getConfiguration } from "../../config";
4 | import getStyle from "./style";
5 | import { Div } from "../../primitives";
6 |
7 | export const GutterWidthContext = React.createContext(false);
8 |
9 | const Row = React.forwardRef(
10 | (
11 | {
12 | children,
13 | style = {},
14 | align = "normal",
15 | justify = "start",
16 | wrap = "wrap",
17 | debug = false,
18 | nogutter = false,
19 | gutterWidth = null,
20 | component = Div,
21 | direction = "row",
22 | ...otherProps
23 | },
24 | ref
25 | ) => {
26 | let theGutterWidth = getConfiguration().gutterWidth;
27 | if (nogutter) theGutterWidth = 0;
28 | if (typeof gutterWidth === "number") theGutterWidth = gutterWidth;
29 | const theStyle = getStyle({
30 | gutterWidth: theGutterWidth,
31 | align,
32 | justify,
33 | debug,
34 | moreStyle: style,
35 | direction,
36 | wrap,
37 | });
38 | return React.createElement(
39 | component,
40 | { ref, style: theStyle, ...otherProps },
41 |
42 | {children}
43 |
44 | );
45 | }
46 | );
47 |
48 | Row.propTypes = {
49 | /**
50 | * Content of the element
51 | */
52 | children: PropTypes.node.isRequired,
53 | /**
54 | * Vertical column alignment
55 | */
56 | align: PropTypes.oneOf(["normal", "start", "center", "end", "stretch"]),
57 | /**
58 | * Horizontal column alignment
59 | */
60 | justify: PropTypes.oneOf([
61 | "start",
62 | "center",
63 | "end",
64 | "between",
65 | "around",
66 | "initial",
67 | "inherit",
68 | ]),
69 | /**
70 | * flex-direction style attribute
71 | */
72 | direction: PropTypes.oneOf([
73 | "column",
74 | "row",
75 | "column-reverse",
76 | "row-reverse",
77 | ]),
78 | /**
79 | * flex-wrap style attribute
80 | */
81 | wrap: PropTypes.oneOf(["nowrap", "wrap", "reverse"]),
82 | /**
83 | * No gutter for this row
84 | */
85 | nogutter: PropTypes.bool,
86 | /**
87 | * Custom gutter width for this row
88 | */
89 | gutterWidth: PropTypes.number,
90 | /**
91 | * Optional styling
92 | */
93 | style: PropTypes.objectOf(
94 | PropTypes.oneOfType([PropTypes.number, PropTypes.string])
95 | ),
96 | /**
97 | * Set to apply some debug styling
98 | */
99 | debug: PropTypes.bool,
100 | /**
101 | * Use your own component
102 | */
103 | component: PropTypes.elementType,
104 | };
105 |
106 | Row.displayName = "Row";
107 |
108 | export default Row;
109 |
--------------------------------------------------------------------------------
/src/grid/Container/index.js:
--------------------------------------------------------------------------------
1 | import React, { createElement } from "react";
2 | import PropTypes from "prop-types";
3 | import getStyle from "./style";
4 | import { getConfiguration } from "../../config";
5 | import ScreenClassResolver from "../../context/ScreenClassResolver";
6 | import { Div } from "../../primitives";
7 |
8 | const Container = React.forwardRef(
9 | (
10 | {
11 | children,
12 | fluid = false,
13 | xs = false,
14 | sm = false,
15 | md = false,
16 | lg = false,
17 | xl = false,
18 | xxl = false,
19 | xxxl = false,
20 | style = {},
21 | component = Div,
22 | ...otherProps
23 | },
24 | ref
25 | ) => (
26 |
27 | {(screenClass) =>
28 | createElement(
29 | component,
30 | {
31 | ref,
32 | style: getStyle({
33 | fluid,
34 | xs,
35 | sm,
36 | md,
37 | lg,
38 | xl,
39 | xxl,
40 | xxxl,
41 | screenClass,
42 | containerWidths: getConfiguration().containerWidths,
43 | gutterWidth: getConfiguration().gutterWidth,
44 | moreStyle: style,
45 | }),
46 | ...otherProps,
47 | },
48 | children
49 | )
50 | }
51 |
52 | )
53 | );
54 |
55 | Container.propTypes = {
56 | /**
57 | * Content of the component
58 | */
59 | children: PropTypes.node.isRequired,
60 | /**
61 | * True makes the container full-width, false fixed-width
62 | */
63 | fluid: PropTypes.bool,
64 | /**
65 | * This is in combination with fluid enabled
66 | * True makes container fluid only in xs, not present means fluid everywhere
67 | */
68 | xs: PropTypes.bool,
69 | /**
70 | * This is in combination with fluid enabled
71 | * True makes container fluid only in sm, not present means fluid everywhere
72 | */
73 | sm: PropTypes.bool,
74 | /**
75 | * This is in combination with fluid enabled
76 | * True makes container fluid only in md, not present means fluid everywhere
77 | */
78 | md: PropTypes.bool,
79 | /**
80 | * This is in combination with fluid enabled
81 | * True makes container fluid only in lg, not present means fluid everywhere
82 | */
83 | lg: PropTypes.bool,
84 | /**
85 | * This is in combination with fluid enabled
86 | * True makes container fluid only in xl, not present means fluid everywhere
87 | */
88 | xl: PropTypes.bool,
89 | /**
90 | * This is in combination with fluid enabled
91 | * True makes container fluid only in xxl, not present means fluid everywhere
92 | */
93 | xxl: PropTypes.bool,
94 | /**
95 | * This is in combination with fluid enabled
96 | * True makes container fluid only in xxxl, not present means fluid everywhere
97 | */
98 | xxxl: PropTypes.bool,
99 | /**
100 | * Optional styling
101 | */
102 | style: PropTypes.objectOf(
103 | PropTypes.oneOfType([PropTypes.number, PropTypes.string])
104 | ),
105 | /**
106 | * Use your own component
107 | */
108 | component: PropTypes.elementType,
109 | };
110 |
111 | Container.displayName = "Container";
112 |
113 | export default Container;
114 |
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'react-grid-system' {
2 | import * as React from 'react';
3 |
4 | type Align = 'normal' | 'start' | 'center' | 'end' | 'stretch'
5 | type Justify = 'start' | 'center' | 'end' | 'between' | 'around' | 'initial' | 'inherit';
6 | type Direction = 'column' | 'row' | 'column-reverse' | 'row-reverse'
7 | type Wrap = 'nowrap' | 'wrap' | 'reverse';
8 | type ScreenClass = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'| 'xxxl';
9 | type ScreenClassMap = Partial>;
10 |
11 | type Offsets = ScreenClassMap;
12 | type Orders = ScreenClassMap;
13 | type Push = ScreenClassMap;
14 | type Pull = ScreenClassMap;
15 |
16 | type ColProps = React.DetailedHTMLProps, HTMLDivElement> & {
17 | width?: "auto" | number | string,
18 | debug?: boolean,
19 | offset?: Offsets,
20 | order?: Orders,
21 | push?: Push,
22 | pull?: Pull,
23 | style?: object,
24 | component?: (() => string) | string
25 | } & ScreenClassMap;
26 |
27 | type ContainerProps = React.DetailedHTMLProps, HTMLDivElement> & {
28 | fluid?: boolean,
29 | style?: object,
30 | component?: (() => string) | string
31 | } & ScreenClassMap;
32 |
33 | type RowProps = React.DetailedHTMLProps, HTMLDivElement> & {
34 | align?: Align,
35 | justify?: Justify,
36 | direction?: Direction,
37 | wrap?: Wrap,
38 | debug?: boolean,
39 | style?: object,
40 | nogutter?: boolean,
41 | component?: (() => string) | string,
42 | gutterWidth?: number
43 | }
44 |
45 | type ClearFixProps = { children: React.ReactNode } & ScreenClassMap;
46 | type VisibleProps = { children: React.ReactNode } & ScreenClassMap;
47 | type HiddenProps = { children: React.ReactNode } & ScreenClassMap;
48 |
49 | type ScreenClassRenderProps = {
50 | render?: (screenClass: ScreenClass) => Exclude
51 | }
52 |
53 | type Configuration = {
54 | breakpoints?: Array,
55 | containerWidths?: Array,
56 | gutterWidth?: number,
57 | gridColumns?: number,
58 | defaultScreenClass?: ScreenClass,
59 | maxScreenClass?: ScreenClass
60 | }
61 |
62 | type ScreenClassProviderProps = {
63 | children: React.ReactNode,
64 | fallbackScreenClass?: ScreenClass,
65 | useOwnWidth?: boolean
66 | }
67 |
68 | export function setConfiguration(configuration: Configuration): void
69 | export function useScreenClass(elementRef?: React.MutableRefObject): ScreenClass
70 |
71 | export class Col extends React.Component { }
72 | export class Container extends React.Component { }
73 | export class Row extends React.Component { }
74 | export class ClearFix extends React.Component { }
75 | export class Hidden extends React.Component { }
76 | export class ScreenClassRender extends React.Component { }
77 | export class Visible extends React.Component { }
78 | export class ScreenClassProvider extends React.Component { }
79 | }
80 |
--------------------------------------------------------------------------------
/src/grid/Col/index.js:
--------------------------------------------------------------------------------
1 | import React, { createElement } from "react";
2 | import PropTypes from "prop-types";
3 | import getStyle from "./style";
4 | import { getConfiguration } from "../../config";
5 | import { GutterWidthContext } from "../Row";
6 | import ScreenClassResolver from "../../context/ScreenClassResolver";
7 | import { Div } from "../../primitives";
8 |
9 | const Col = React.forwardRef(
10 | (
11 | {
12 | children = null,
13 | xs = null,
14 | sm = null,
15 | md = null,
16 | lg = null,
17 | xl = null,
18 | xxl = null,
19 | xxxl = null,
20 | offset = {},
21 | pull = {},
22 | push = {},
23 | order = {},
24 | debug = false,
25 | style = {},
26 | component = Div,
27 | width = null,
28 | ...otherProps
29 | },
30 | ref
31 | ) => (
32 |
33 | {(screenClass) => (
34 |
35 | {(gutterWidth) => {
36 | const theStyle = getStyle({
37 | forceWidth: width,
38 | width: {
39 | xs,
40 | sm,
41 | md,
42 | lg,
43 | xl,
44 | xxl,
45 | xxxl,
46 | },
47 | offset,
48 | pull,
49 | push,
50 | order,
51 | debug,
52 | screenClass,
53 | gutterWidth,
54 | gridColumns: getConfiguration().gridColumns,
55 | moreStyle: style,
56 | });
57 | return createElement(component, {
58 | ref,
59 | style: theStyle,
60 | ...otherProps,
61 | children,
62 | });
63 | }}
64 |
65 | )}
66 |
67 | )
68 | );
69 |
70 | Col.propTypes = {
71 | /**
72 | * Content of the column
73 | */
74 | children: PropTypes.node,
75 | /**
76 | * The width of the column for screenclass `xs`, either a number between 0 and 12, or "content"
77 | */
78 | xs: PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf(["content"])]),
79 | /**
80 | * The width of the column for screenclass `sm`, either a number between 0 and 12, or "content"
81 | */
82 | sm: PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf(["content"])]),
83 | /**
84 | * The width of the column for screenclass `md`, either a number between 0 and 12, or "content"
85 | */
86 | md: PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf(["content"])]),
87 | /**
88 | * The width of the column for screenclass `lg`, either a number between 0 and 12, or "content"
89 | */
90 | lg: PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf(["content"])]),
91 | /**
92 | * The width of the column for screenclass `xl`, either a number between 0 and 12, or "content"
93 | */
94 | xl: PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf(["content"])]),
95 | /**
96 | * The width of the column for screenclass `xxl`, either a number between 0 and 12, or "content"
97 | */
98 | xxl: PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf(["content"])]),
99 | /**
100 | * The width of the column for screenclass `xxl`, either a number between 0 and 12, or "content"
101 | */
102 | xxxl: PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf(["content"])]),
103 | /**
104 | * A fixed width of the column for all screenclasses"
105 | */
106 | width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
107 | /**
108 | * The offset of this column for all screenclasses
109 | */
110 | offset: PropTypes.shape({
111 | xs: PropTypes.number,
112 | sm: PropTypes.number,
113 | md: PropTypes.number,
114 | lg: PropTypes.number,
115 | xl: PropTypes.number,
116 | xxl: PropTypes.number,
117 | xxxl: PropTypes.number,
118 | }),
119 | /**
120 | * The amount this column is pushed to the right for all screenclasses
121 | */
122 | push: PropTypes.shape({
123 | xs: PropTypes.number,
124 | sm: PropTypes.number,
125 | md: PropTypes.number,
126 | lg: PropTypes.number,
127 | xl: PropTypes.number,
128 | xxl: PropTypes.number,
129 | xxxl: PropTypes.number,
130 | }),
131 | /**
132 | * The amount this column is pulled to the left for all screenclasses
133 | */
134 | pull: PropTypes.shape({
135 | xs: PropTypes.number,
136 | sm: PropTypes.number,
137 | md: PropTypes.number,
138 | lg: PropTypes.number,
139 | xl: PropTypes.number,
140 | xxl: PropTypes.number,
141 | xxxl: PropTypes.number,
142 | }),
143 | /**
144 | * The order this column is pulled to the left for all screenclasses
145 | */
146 | order: PropTypes.shape({
147 | xs: PropTypes.number,
148 | sm: PropTypes.number,
149 | md: PropTypes.number,
150 | lg: PropTypes.number,
151 | xl: PropTypes.number,
152 | xxl: PropTypes.number,
153 | xxxl: PropTypes.number,
154 | }),
155 | /**
156 | * Optional styling
157 | */
158 | style: PropTypes.objectOf(
159 | PropTypes.oneOfType([PropTypes.number, PropTypes.string])
160 | ),
161 | /**
162 | * Set to apply some debug styling
163 | */
164 | debug: PropTypes.bool,
165 | /**
166 | * Use your own component
167 | */
168 | component: PropTypes.elementType,
169 | };
170 |
171 | Col.displayName = "Col";
172 |
173 | export default Col;
174 |
--------------------------------------------------------------------------------
/src/grid.md:
--------------------------------------------------------------------------------
1 | Resize your browser or load on different devices to test the grid system.
2 |
3 | ### Example: Equal-width
4 |
5 | ```js
6 | import { Container, Row, Col } from '.';
7 |
8 |
9 |
10 | 1 of 2
11 | 2 of 2
12 |
13 |
14 |
15 | 1 of 3
16 | 2 of 3
17 | 3 of 3
18 |
19 |
20 | ```
21 |
22 | ### Example: Stacked to horizontal
23 |
24 | ```js
25 | import { Container, Row, Col } from '.';
26 |
27 |
28 |
29 | md=1
30 | md=1
31 | md=1
32 | md=1
33 | md=1
34 | md=1
35 | md=1
36 | md=1
37 | md=1
38 | md=1
39 | md=1
40 | md=1
41 |
42 |
43 |
44 | md=8
45 | md=4
46 |
47 |
48 |
49 | md=4
50 | md=4
51 | md=4
52 |
53 |
54 |
55 | md=6
56 | md=6
57 |
58 |
59 | ```
60 |
61 | ### Example: Mix and match
62 |
63 | ```js
64 | import { Container, Row, Col } from '.';
65 |
66 |
67 |
68 | xs=12 md=8
69 | xs=6 md=4
70 |
71 |
72 |
73 | xs=6 md=4
74 | xs=6 md=4
75 | xs=6 md=4
76 |
77 |
78 |
79 | xs=6
80 | xs=6
81 |
82 |
83 | ```
84 |
85 | ### Example: Column wrapping
86 |
87 | ```js
88 | import { Container, Row, Col } from '.';
89 |
90 |
91 |
92 | xs=9
93 | xs=4
Since 9 + 4 = 13 > 12, this 4-column-wide Col gets wrapped onto a new line as one contiguous unit.
94 | xs=6
Subsequent columns continue along the new line.
95 |
96 |
97 | ```
98 |
99 | ### Example: Vertical alignment
100 |
101 | ```js
102 | import { Container, Row, Col } from '.';
103 |
104 |
105 |
106 | 1 of 3
107 | 2 of 3
108 | 3 of 3
109 |
110 |
111 |
112 | 1 of 3
113 | 2 of 3
114 | 3 of 3
115 |
116 |
117 |
118 | 1 of 3
119 | 2 of 3
120 | 3 of 3
121 |
122 |
123 |
124 | 1 of 3
125 | 2 of 3
126 | 3 of 3
127 |
128 |
129 | ```
130 |
131 | ### Example: Horizontal alignment
132 |
133 | ```js
134 | import { Container, Row, Col } from '.';
135 |
136 |
137 |
138 | 1 of 3
139 | 2 of 3
140 | 3 of 3
141 |
142 |
143 |
144 | 1 of 3
145 | 2 of 3
146 | 3 of 3
147 |
148 |
149 |
150 | 1 of 3
151 | 2 of 3
152 | 3 of 3
153 |
154 |
155 |
156 | 1 of 3
157 | 2 of 3
158 | 3 of 3
159 |
160 |
161 |
162 | 1 of 3
163 | 2 of 3
164 | 3 of 3
165 |
166 |
167 |
168 | 1 of 3
169 | 2 of 3
170 | 3 of 3
171 |
172 |
173 |
174 | 1 of 3
175 | 2 of 3
176 | 3 of 3
177 |
178 |
179 | ```
180 |
181 | ### Example: Direction prop for order and orientation of Row children
182 |
183 | ```js
184 | import { Container, Row, Col } from '.';
185 |
186 |
187 |
188 | 1 of 3
189 | 2 of 3
190 | 3 of 3
191 |
192 |
193 |
194 | 1 of 3
195 | 2 of 3
196 | 3 of 3
197 |
198 |
199 |
200 | 1 of 3
201 | 2 of 3
202 | 3 of 3
203 |
204 |
205 |
206 | 1 of 3
207 | 2 of 3
208 | 3 of 3
209 |
210 |
211 |
212 |
213 | ```
214 |
215 | ### Example: Offsetting columns
216 |
217 | ```js
218 | import { Container, Row, Col } from '.';
219 |
220 |
221 |
222 | md=4
223 | md=4 offset-md=4
224 |
225 |
226 |
227 | md=3 offset-md=3
228 | md=3 offset-md=3
229 |
230 |
231 |
232 | md=6 offset-md=3
233 |
234 |
235 | ```
236 |
237 | ### Example: Nesting columns
238 |
239 | ```js
240 | import { Container, Row, Col } from '.';
241 |
242 |
243 |
244 |
245 | Level 1: sm=9
246 |
247 |
248 | Level 2: xs=8 sm=6
249 |
250 |
251 | Level 2: xs=4 sm=6
252 |
253 |
254 |
255 |
256 |
257 | ```
258 |
259 | ### Example: Column ordering
260 |
261 | ```js
262 | import { Container, Row, Col } from '.';
263 |
264 |
265 |
266 | md=9 push-md=3
267 | md=3 pull-md=9
268 |
269 |
270 | ```
271 |
272 | ### Example: Custom gutter width
273 |
274 | ```js
275 | import { Container, Row, Col } from '.';
276 |
277 |
278 |
279 | md=8
280 | md=4
281 |
282 |
283 |
284 | md=8
285 | md=4
286 |
287 |
288 | ```
289 |
290 | ### Example: Column width adapted to content
291 |
292 | ```js
293 | import { Container, Row, Col } from '.';
294 |
295 |
296 |
297 | Logo (Flexible column)
298 | Menu with x-items
299 |
300 |
301 | ```
302 |
303 |
304 |
305 | ### Example: Ordering Cols adapted to content
306 |
307 | ```js
308 | import { Container, Row, Col } from '.';
309 |
310 |
311 |
312 | First on md, last on xl
313 | First on xl, last on md
314 |
315 |
316 | ```
317 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Grid System
2 | A powerful Bootstrap-like responsive grid system for React.
3 |
4 | [](https://npmjs.org/package/react-grid-system)
5 | [](https://npmjs.org/package/react-grid-system)
6 |
7 | ## Migration guide
8 |
9 | ### Upgrading to v8
10 |
11 | `react-grid-system` v8 removes the `nowrap` property of `Row` in favor of a new `wrap` property. If you were using ``, replace it with `
`.
12 |
13 | ### Upgrading to v7
14 |
15 | `react-grid-system` v7 adds a new screen class `xxl` for very large screens. This might have consequences for your app. To opt out of this new screen class, use this:
16 |
17 | ```javascript
18 | import { setConfiguration } from 'react-grid-system';
19 |
20 | setConfiguration({ maxScreenClass: 'xl' });
21 | ```
22 |
23 | ## Installation
24 |
25 | ```
26 | npm install react-grid-system --save
27 | ```
28 | ## Getting started
29 |
30 | ### Responsive grid
31 |
32 | `react-grid-system` provides a responsive grid for React inspired by [Bootstrap](https://getbootstrap.com/docs/4.5/layout/grid/). Moreover, it has various additional powerful features, such as setting breakpoints and gutter widths through React's context.
33 |
34 | Three components are provided for creating responsive grids: `Container`, `Row`, and `Col`.
35 |
36 | An example on how to use these:
37 |
38 | ```javascript
39 | import { Container, Row, Col } from 'react-grid-system';
40 |
41 |
42 |
43 |
44 | One of three columns
45 |
46 |
47 | One of three columns
48 |
49 |
50 | One of three columns
51 |
52 |
53 |
54 | ```
55 |
56 | For all features of these components, please have a look at the API documentation: https://sealninja.github.io/react-grid-system/
57 |
58 | ### Responsive utilities
59 |
60 | Next to the grid, two components are provided for showing or hiding content: `Visible` and `Hidden`.
61 | The main difference between these two components and the similar CSS classes provided by Bootstrap is that these two components do not render the content at all when it should be hidden, instead of just hiding it with CSS.
62 |
63 | Some examples on how to use these components:
64 |
65 | ```javascript
66 | import { Visible } from 'react-grid-system';
67 |
68 |
69 | Your current screen class is
70 | xs
71 | sm
72 | md
73 | lg
74 | xl
75 | xxl
76 | .
77 |
78 | ```
79 |
80 | ```javascript
81 | import { Visible, Hidden } from 'react-grid-system';
82 |
83 |
84 | Paragraph visible on extra small and small.
85 |
86 |
87 | Paragraph hidden on extra small and small.
88 |
89 |
90 | Paragraph visible on medium and large.
91 |
92 |
93 | Paragraph hidden on medium and large.
94 |
95 | ```
96 |
97 | Next to that, the `ScreenClassRender` component is provided, for rendering a component differently based on the screen class. An example on how to use this:
98 |
99 | ```javascript
100 | import { ScreenClassRender } from 'react-grid-system';
101 |
102 | (
103 |
104 | Screen class: {screenClass}
105 |
106 | )} />
107 | ```
108 |
109 | Alternatively, the `useScreenClass` hook can be used for rendering a component differently based on the screen class. Some examples on how to use this:
110 |
111 | ```javascript
112 | import React from 'react';
113 | import { useScreenClass } from 'react-grid-system';
114 |
115 | // responsive component based the screen width
116 | function Example1() {
117 | const screenClass = useScreenClass();
118 | return (
119 |
120 | Screen class: {screenClass}
121 |
122 | );
123 | }
124 |
125 | // responsive component based the div width
126 | function Example2() {
127 | const elementRef = useRef(null);
128 | const screenClass = useScreenClass(elementRef);
129 | return (
130 |
131 |
132 | Screen class: {screenClass}
133 |
134 |
135 | );
136 | }
137 | ```
138 |
139 | ## Configuration
140 |
141 | The following settings can be configured, to alter the responsive behavior of the grid components:
142 |
143 | | Setting | Default Value | Description |
144 | | -------------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------- |
145 | | `breakpoints` | `[576, 768, 992, 1200, 1600, 1920]` | The breakpoints (minimum width) of devices in screen class `sm`, `md`, `lg`, `xl`, `xxl`, and `xxxl`. |
146 | | `containerWidths` | `[540, 740, 960, 1140, 1540, 1810]` | The container widths in pixels of devices in screen class `sm`, `md`, `lg`, `xl`, `xxl`, and `xxxl`. |
147 | | `gutterWidth` | `30` | The gutter width in pixels. A gutter width of 30 means 15px on each side of a column. |
148 | | `gridColumns` | `12` | The number of columns in the grid . |
149 | | `defaultScreenClass` | `xxl` | The screen class used when the view port cannot be determined using `window`. |
150 | | `maxScreenClass` | `xxl` | The maximum screen class to be used. |
151 |
152 | These settings can be configured in the following way:
153 |
154 | ```javascript
155 | import { setConfiguration } from 'react-grid-system';
156 |
157 | setConfiguration({ defaultScreenClass: 'sm', gridColumns: 20 });
158 | ```
159 |
160 | An example on how to use them can be found in the [Example application with SSR](#example-application-with-ssr) below.
161 |
162 | ## ScreenClass Context API
163 |
164 | Internally, every component that requires the current `screenClass` (which is a human-readable string version of the `window.innerWidth` relating to the user's breakpoints) subscribes to a `ScreenClassProvider`. The provider utilizes the [React Context API](https://reactjs.org/docs/context.html) to send down the current `screenClass` as it updates. By default, each instance of every component subscribes to a separate provider, creating `resize` listeners for each. This can cut down renders during a resize event from ~300 to 4 (one for each breakpoint) making the grid much more performant.
165 |
166 | ### Do I need to change anything in my code?
167 |
168 | This new API is entirely opt-in and current implementations will continue to work. However, for a signficiant performance increase, you will need to add the `ScreenClassProvider` to your application, typically at the highest level in the React node tree (i.e, App.js).
169 |
170 |
171 | ### How do I use the ScreenClassProvider?
172 |
173 | ```jsx static
174 | import React from 'react';
175 | import { ScreenClassProvider } from 'react-grid-system';
176 |
177 | export default function App() {
178 | return (
179 |
180 |
181 |
182 |
183 |
184 | );
185 | }
186 | ```
187 |
188 | Internally, the `ScreenClassProvider` attaches a `resize` listener and then updates `state.screenClass` exclusively when a new breakpoint is hit. The `state.screenClass` value is then attached to `ScreenClassContext.Provider`. ScreenClass-dependent components are wrapped with `ScreenClassResolver` which checks to see if there is a valid provider above it and provides one if there is not.
189 |
190 | The performance benefit comes from _you_ adding a `ScreenClassProvider` to your application which allows `react-grid-system` components to subscribe to **one source of truth** for the ScreenClass.
191 |
192 |
193 | ## API documentation
194 |
195 | Extensive documentation of all components can be found at the GitHub pages: https://sealninja.github.io/react-grid-system/
196 |
197 | ## Example application with SSR
198 |
199 | An example application with server-side rendering using features of `react-grid-system` can be found at https://github.com/sealninja/react-ssr-example.
200 |
201 | ## License
202 |
203 | MIT
204 |
--------------------------------------------------------------------------------