{"id":20380522,"url":"https://github.com/tobua/responsive-react-native","last_synced_at":"2025-10-30T12:42:53.579Z","repository":{"id":57838537,"uuid":"528128223","full_name":"tobua/responsive-react-native","owner":"tobua","description":"Responsifies regular pixel-based React Native styles.","archived":false,"fork":false,"pushed_at":"2025-02-18T19:27:44.000Z","size":1712,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-26T03:41:42.800Z","etag":null,"topics":["react-native","responsive","styled-components"],"latest_commit_sha":null,"homepage":"https://tobua.github.io/responsive-react-native/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tobua.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-08-23T19:05:25.000Z","updated_at":"2025-02-19T13:03:59.000Z","dependencies_parsed_at":"2024-01-17T00:27:59.275Z","dependency_job_id":"07ed44d0-a8b6-4c89-ad4c-45695d28fd6b","html_url":"https://github.com/tobua/responsive-react-native","commit_stats":{"total_commits":30,"total_committers":1,"mean_commits":30.0,"dds":0.0,"last_synced_commit":"f9d5126ce072840a9c02ae335d7dbc4c8ad48d89"},"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobua%2Fresponsive-react-native","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobua%2Fresponsive-react-native/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobua%2Fresponsive-react-native/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobua%2Fresponsive-react-native/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tobua","download_url":"https://codeload.github.com/tobua/responsive-react-native/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248231459,"owners_count":21069333,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["react-native","responsive","styled-components"],"created_at":"2024-11-15T02:07:40.437Z","updated_at":"2025-10-30T12:42:48.532Z","avatar_url":"https://github.com/tobua.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://tobua.github.io/responsive-react-native/\"\u003e\n    \u003cimg src=\"https://github.com/tobua/responsive-react-native/raw/main/video.gif\" alt=\"Responsive Video\" width=\"250\"\u003e\n    \u003c!--- Recorded in iOS Simulator and converted with Gifsky from Mac App Store. --\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n# responsive-react-native\n\nUnlike web browsers React Native doesn't support media queries to create responsive designs. With this plugin one can keep regular numeric values in the styles that are automatically adapted based on the current viewport size.\n\n- Uses regular pixel based values\n- No refactoring required (backwards compatible with default RN styling)\n- Automatically scales values linearly\n- Supports breakpoints\n- Size calculated based on viewport size or user preference\n- Styled-components like component interface to avoid rerender\n- Type checking with TypeScript\n- Check out the web based [documentation](https://tobua.github.io/responsive-react-native/) with examples\n- Here is a [blog post](https://onwebfocus.com/styled) discussing this plugin\n\n## Installation and Usage\n\n```\nnpm install responsive-react-native\n```\n\n```jsx\nimport { createStyles } from 'responsive-react-native'\n\nconst styles = createStyles({\n  view: {\n    padding: 20,\n    height: 40,\n    flex: 1, // Remains unmodified.\n    backgroundColor: 'blue',\n  },\n  text: {\n    fontSize: 16,\n  },\n})\n\nexport const App = () =\u003e (\n  \u003cView style={styles.view}\u003e\n    \u003cText style={styles.text}\u003eHello Responsive World\u003c/Text\u003e\n  \u003c/View\u003e\n)\n```\n\n## Scaled Values\n\nInstead of the values just jumping between breakpoints as is usually done this plugin will linearly scale all values automatically.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/tobua/responsive-react-native/main/scale.svg\" alt=\"Scaled values\"\u003e\n\u003c/p\u003e\n\n```js\nimport { createStyles } from 'responsive-react-native'\n\nconst styles = createStyles({\n  view: {\n    height: 100, // =\u003e 100px for 480px viewport width, 80px for 320px viewport, 120px for 640px viewport.\n    marginHorizontal: 20, // =\u003e 20px for 480px viewport width, 16px for 320px viewport, 24px for 640px viewport.\n  },\n})\n```\n\nThe viewports as well as the strength of the scaling can be [configured](#configuration) as described below.\n\n## Adaptive Values (Breakpoints and Orientation)\n\nSimilar to breakpoints in CSS values can be customized inline based on the current breakpoint or the orientation. An array `[portrait, landscape]` will pick the appropriate value depending on the orientation while an object `{ small: any, large: any }` will pick the value appropriate for the current breakpoint. If the current breakpoint is missing the nearest one below will be used.\n\n```js\nimport { createStyles } from 'responsive-react-native'\n\nconst styles = createStyles({\n  view: {\n    backgroundColor: ['blue', 'red'], // =\u003e blue in portrait, red in landscape.\n    height: { small: 40, large: 80 }, // =\u003e 40 for small and medium breakpoint, 80 on large breakpoint.\n    padding: [\n      { small: 40, medium: 60 },\n      { small: 20, large: 80 },\n    ], // Both approaches can be combined either way.\n  },\n})\n```\n\n## Rerendering\n\nSince neither native Android or iOS have support for something like media queries this plugin requires the responsive parts of the application to be rerendered when the size changes. Full rerendering usually takes some time and will not result in an application that can be dynamically resized. A rerender can be triggered when the user adapts the size preference using the built-in `\u003cSelectBreakpoint /\u003e` component or when the application switches between landscape and portrait mode.\n\nAny component that is rendered using responsive styles should be rendered inside the `Rerender` component. A rerender can be manually triggered using the `rerender` method or occurs, upon changes to `\u003cSelectBreakpoint /\u003e`, when the orientation changes or when the breakpoint is changed using `setBreakpoint`.\n\n```jsx\nimport { Rerender, SelectBreakpoint, rerender } from 'responsive-react-native'\n\nfunction App() {\n  return (\n    \u003cView\u003e\n      \u003cRerender\u003e{() =\u003e \u003cView key={getSize()} style={styles.view}\u003e\u003c/View\u003e}\u003c/Rerender\u003e\n      \u003cText\u003eStatic Text\u003c/Text\u003e\n      \u003cSelectBreakpoint /\u003e\n      \u003cButton title=\"Rerender App\" onPress={() =\u003e rerender()}\u003e\n    \u003c/View\u003e\n  )\n}\n```\n\n## Refactoring\n\nSince the method is compatible with the default way of initializing styles once using `StyleSheet.create` an existing application can be migrated by reassigning the method to use the one from this plugin.\n\n```js\n// refactor-stylesheet.js\nimport { StyleSheet } from 'react-native'\nimport { createStyles } from 'responsive-react-native'\n\nObject.assign(StyleSheet, { create: createStyles })\n```\n\n```js\n// index.js\nimport { AppRegistry } from 'react-native'\nimport './refactor-stylesheet' // Import this before any other markup.\nimport App from './App'\n\nAppRegistry.registerComponent('responsive-app', () =\u003e App)\n```\n\n## Styled Components to Avoid Rerendering\n\nSimilar to most CSS-in-JS React approaches known from the web this interface allows you to apply styles to components. When using props, breakpoints or the platform as conditional keys the styles will automatically be merged. This approach doesn't require a `\u003cRerender /\u003e` component and only the styles need to be recalculated when the breakpoint or window size changes. Numeric values are automatically scaled responsively.\n\n```jsx\nimport { View } from 'react-native'\nimport { Styled } from 'responsive-react-native'\n\nconst CustomView = Styled(\n  View,\n  {\n    backgroundColor: ['gray', 'white'], // White in landscape.\n    padding: 10,\n  },\n  {\n    // Truthy prop.\n    highlight: {\n      backgroundColor: 'red',\n      padding: { small: 20, large: 60 }, // Full stylesheet support.\n    },\n    // Current breakpoint.\n    large: {\n      backgroundColor: 'blue',\n    },\n    // Current OS.\n    ios: {\n      padding: 5,\n    },\n  },\n)\n\nexport default () =\u003e \u003cCustomView highlight /\u003e\n```\n\n## Connect Styles to MobX Observables\n\nWhen passing a function returning a stylesheet and `mobx` is installed the styles will automatically be updated whenever any state changes.\n\n```jsx\nimport { observable } from 'mobx'\nimport { Styled } from 'responsive-react-native'\n\nconst Store = observable({ highlight: false })\n\nconst ObservableView = Styled('View', () =\u003e ({\n  backgroundColor: Store.highlight ? 'red' : 'gray',\n}))\n\nexport default () =\u003e (\n  \u003cView\u003e\n    \u003cObservableView /\u003e\n    \u003cButton\n      title=\"Highlight\"\n      onPress={() =\u003e\n        runInAction(() =\u003e {\n          Store.highlight = !Store.highlight\n        })\n      }\n    /\u003e\n  \u003c/View\u003e\n)\n```\n\n## `useResponsive`\n\nThis React hook also avoids the need for components to be wrapped in `\u003cRerender /\u003e` and can be handy when dynamically rendering something based on the current breakpoint.\n\n```jsx\nimport { useResponsive } from 'responsive-react-native'\n\nexport default function App() {\n  const { breakpoint, setBreakpoint, orientation } = useResponsive()\n  return (\n    \u003cView style={{ margin: breakpoint === 'large' ? 0 : 10 }}\u003e\n      \u003cText\u003eCurrent breakpoint: {breakpoint}\u003c/Text\u003e\n      \u003cButton title=\"Set Breakpoint to Small\" onPress={() =\u003e setBreakpoint('small')} /\u003e\n    \u003c/View\u003e\n  )\n}\n```\n\n## Configuration\n\nThe scaling of responsive values as well as the breakpoints can be configured.\n\n```ts\nimport { configure } from 'responsive-react-native'\n\nconfigure({\n  // Initial breakpoint, default inferred from breakpoint values.\n  breakpoint: 'small',\n  // Available breakpoints, default { small: 360, medium: 420, large: 999 }.\n  breakpoints: {\n    tiny: 300,\n    normal: 600,\n    huge: 800,\n  },\n  // Responsive scaling configuration, default { minimum: 320, maximum: 520, factor: 0.5 }.\n  scale: {\n    minimum: 300,\n    maximum: 600,\n    factor: 1,\n  },\n  // Method used to calculate responsive values, default linear scaling according to \"scale\" configuration.\n  value: (value: number, breakpoint: string, orientation: 'portrait' | 'landscape') =\u003e {\n    if (breakpoint === 'medium') {\n      return value\n    }\n\n    const halfValue = Math.round(value / 6)\n\n    if (breakpoint === 'small') {\n      return value - halfValue\n    }\n\n    return value + halfValue\n  },\n})\n```\n\nThe `scale.factor` describes the degree to which the values are scaled between the viewports defined. A factor of `1` means that `0.5` times the `value` will be added or subtracted when the minimum or maximum viewport is reached. While very extreme a factor of `2` would lead to zero values at the minimum viewport and double the value at the maximum. The default of `0.5` has proven useful for mobile applications and will scale the value by 25%. This still results in a 50% difference between the minimum and maximum values.\n\nWhen configuring breakpoints with TypeScript use the following to override `CustomBreakpoints` types for proper type checking.\n\n```ts\ndeclare module 'responsive-react-native' {\n  interface CustomBreakpoints {\n    tiny: number\n    normal: number\n    huge: number\n  }\n}\n```\n\n## Similar Approaches\n\nA previous approach to make mobile applications responsive is to calculate percentages based on the full width of the screen. This approach is used by other responsive plugins for React Native and also used in Swift UI by using `UIScreen.main.bounds.width`. While this approach can certainly work it doesn't feel very intuitive. On the web similar units called `vw` (viewport width, 100vw = 100% viewport) and `vh` (viewport height) exist but are rarely used when compared to breakpoints. The approach taken by this plugin tries to get the best of both world by combining breakpoints and pixel based values. For accessibility purposes users often want to scale the font size system wide which this plugin automatically supports similar to `ScaledMetric` in iOS.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftobua%2Fresponsive-react-native","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftobua%2Fresponsive-react-native","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftobua%2Fresponsive-react-native/lists"}