<View width="280px" maxWidth="100%"> <Table border> <Table.Row highlighted> <Table.Heading>Product</Table.Heading> <Table.Heading align="end" width="auto"> Price </Table.Heading> </Table.Row> <Table.Row> <Table.Cell>Coffee</Table.Cell> <Table.Cell align="end">$4</Table.Cell> </Table.Row> <Table.Row> <Table.Cell>Sandwich</Table.Cell> <Table.Cell align="end">$6.50</Table.Cell> </Table.Row> </Table> </View>
We're adding a new Table component that provides common compound components for rendering individual table elements and gives you a lot of flexibility through composition. This approach allows teams to build both, simple table with text content and rich tables with interactive content that are integrated with libraries like TanStack Table.
With the recent theming improvements, we're adding a new website page for previewing theme values on a real component examples. This is a first step towards making it easier to create new themes. In the upcoming releases, we're planning to expand its functionality with user interface for the runtime theme editing and theme values auto-generation.
function Demo() { const [customTheme, setCustomTheme] = React.useState(false); const css = customTheme && getThemeCSS("myTheme", { color: { backgroundPrimary: { hex: "#1abc9c", hexDark: "#16a085" }, backgroundPrimaryHighlighted: { hex: "#16a085", hexDark: "#1abc9c" }, }, }); return ( <> {css && <style>{css}</style>} <Theme name={customTheme ? "myTheme" : "reshaped"}> <View gap={4} align="start"> <FormControl> <View direction="row" gap={2}> <Switch name="theme" onChange={() => setCustomTheme((prev) => !prev)} /> <FormControl.Label>Toggle custom theme</FormControl.Label> </View> </FormControl> <Button color="primary">Primary button</Button> </View> </Theme> </> ); }
We have added a new way to work with themes without building them using our CLI ahead of time. With the new runtime theming feature, you can create new themes directly in the browser and insert them as a style tag, or create themes dynamically in Node.js and return css file contents.
<View gap={4} align="start"> <Button.Group> <Button variant="faded">File</Button> <Button variant="faded">Edit</Button> <Button variant="faded">View</Button> </Button.Group> <Button.Group> <Button>Save changes</Button> <DropdownMenu> <DropdownMenu.Trigger> {(attributes) => <Button icon={IconDown} attributes={attributes} />} </DropdownMenu.Trigger> <DropdownMenu.Content> <DropdownMenu.Item>Copy link</DropdownMenu.Item> <DropdownMenu.Item>Update permissions</DropdownMenu.Item> <DropdownMenu.Item>Save to folder</DropdownMenu.Item> </DropdownMenu.Content> </DropdownMenu> </Button.Group> </View>
We're adding a new compound component for Button – Button.Group, which lets you wrap any number of buttons to colocate multiple actions together. It leverages the composition approach, which means you can combine items with other components like DropdownMenu.
Haven't used Reshaped before and interested in trying out our NPM package for the first time? Check our standalone release announcement covering core Reshaped principles.
Don't forget to resync the theme in Figma in case you're using the default theme or copy line-height variables into your custom theme from the Reshaped theme file.
<Card padding={6}> <Text color="primary" variant="body-1" weight="medium" attributes={{ style: { fontFamily: 'monospace' } }}> npm install reshaped </Text> </Card>
Since the very beginning of Reshaped, we wanted to find more ways to give back to the community and it was very challenging to do without sacrificing our whole business model and keeping the development sustainable. In the past few months, we've started switching the focus of our paid assets and services more towards companies creating their design systems and we can finally start giving more of our content for free to let individual developers try our Reshaped.
In v2.2 we've published our React package to npm and it's now available to everyone for free. We hope this could help more indie hackers in building their new projects, as well as for everyone who has been asking us about how to use Reshaped in their open-source projects – you finally can.
For teams considering buying the Pro version with the library source code, free npm access could help with making the decision without having to pay for the individual licenses.
We're very excited to see more people using Reshaped and get more feedback to see what we can improve further on 🚀
function DemoFiltering() { const [value, setValue] = React.useState(""); const options = ["Pizza", "Pie", "Ice-cream"]; const handleChange = (args) => setValue(args.value); return ( <View width="300px" maxWidth="100%"> <Autocomplete name="fruit" placeholder="Pick your food" value={value} onChange={handleChange} > {options.map((option) => { if (!option.toLowerCase().includes(value.toLowerCase())) return; if (option === value) return; return ( <Autocomplete.Item key={option} value={option}> {option} </Autocomplete.Item> ); })} </Autocomplete> </View> ); }
We're extending our form fields collection with a new Autocomplete component that comes with full accessibility support and keyboard navigation. Like in many other components, we're following our composition approach here so you would see its primitives are built using TextField and DropdownMenu and let you control its internal composition and state based on your own requirements.
<View paddingBlock={4} maxWidth="100%" width="300px"> <Slider range name="slider" defaultMinValue={20} defaultMaxValue={60} renderValue={(args) => `$${args.value}`} /> </View>
One of the requests we had was a component to pick a range of values, so we're adding support for the Slider component. It comes with built-in accessibility and keybord navigation, works for individual values and value ranges, as well as it supports all typical form states and can be combined with the FormControl utility.
Don't forget to resync the theme in Figma in case you're using the default theme or copy line-height variables into your custom theme from the Reshaped theme file.
function Demo() { const [theme, setTheme] = React.useState('reshaped'); return ( <> <View position="absolute" insetTop={4} insetStart={4}> <Select options={[ { label: 'Reshaped', value: 'reshaped' }, { label: 'Slate', value: 'slate' }, { label: 'Figma', value: 'figma' } ]} onChange={({ value }) => setTheme(value)} /> </View> <Theme name={theme}> <View width="300px"> <Card elevated> <View gap={3}> <FormControl> <FormControl.Label>Your name</FormControl.Label> <TextField name="name" placeholder="Paul" /> </FormControl> <FormControl hasError> <FormControl.Label>Your email</FormControl.Label> <TextField name="name" value="hello@reshaped" /> <FormControl.Error> Invalid email address </FormControl.Error> </FormControl> <Button color="primary" fullWidth>Submit</Button> </View> </Card> </View> </Theme> </> ) }
In this release, we are introducing two new themes. One of the themes is called Slate, which features a color palette inspired by productivity applications and developer tools. It primarily utilizes shades of gray that are closer to monochrome values.
Second theme is a theme based on the Figma interface and can help with building Figma plugins with a familiar set of components.
<View gap={2} direction="row"> <Badge size="large" onDismiss={() => {}} color="positive"> In progress </Badge> <Badge icon={IconHeart} color="primary" variant="faded" size="large" onClick={() => {}}> Locals favorite </Badge> </View>
Badge has been enhanced with the following additional properties, expanding its versatility and usage in various scenarios:
These additional properties empower you to leverage badges creatively in new scenarios, providing flexibility and enhancing the user experience.
We're excited to announce our v2.0 release today 🎉
For the past 6 months, we've been working hard rethinking every single piece of Reshaped and what should be our next steps. It led us to rebuilding our Figma library from ground-up, increasing all components reliability, helping you compose them together without unexpected layout issues and adopting the latest features features, like Figma Variables.
With more teams purchasing Reshaped Pro license, we've spent additional time making sure we can provide the best experience for those teams starting with their design systems. What they value the most is how fast they can start building their custom features without spending any time on the setup. To support them, we have completely revamped our Pro license development environment to cover all technical requirements for a modern design system.
Look for ⚡ emoji in the changelog. These changes update the API of components and features and might require attention on your product.
Don't forget to regenerate themes in React and Figma after updating to v2.
We've updated our source code structured and moved it away from an internal monorepo. This way we can ensure that our development environment works without any manual adjustments for other teams and dependency resolutions. At the same time you can still include it into your own monorepo and store all components right next to your product.
While working on this, we've also improved the overall setup of the source code. We've switched from Webpack to vite for bundling the library and storybook, added stylelint and git hooks for running automatic linting on commit. With all the changes in place – making a full library build now takes ~10-15 seconds.
⚡ Figma gives us a lot of new features to improve the quality of design system assets. We've been using component variants and properties in Reshaped for quite some time, but there were parts of the library we could only change after the major release.
In 2.0, we've revamped the whole library to be even more aligned with code and use these features to their full potential, as well as be ready for the new features Figma will announce on Figma Config this year:
⚡ We have updated our font design tokens structure to reduce the complexity of working with the design tokens in Figma and reduce the size of the theme CSS file by almost 60%.
Here is a mapping of the old typography values to the new ones:
// Before After display-1 title-1 ... title-2 [new] display-2 title-3 ... title-4 [new] display-3 title-5 ... title-6 [new] title-1 featured-1, weight: bold title-2 featured-2, weight: bold title-3 featured-3, weight: bold featured-1 featured-1 featured-2 featured-2 featured-3 featured-3 ... body-1 [new] body-1 body-2 body-2 body-3 body-medium-1 body-2, weight: medium body-medium-2 body-3, weight: medium body-strong-1 body-2, weight: bold body-strong-2 body-3, weight: bold caption-1 caption-1 caption-2 caption-2
<View direction="row" gap={4}> <Theme colorMode="light"> <View backgroundColor="neutral-faded" padding={8} borderRadius="large" direction="row" gap={3}> <div style={{ backgroundColor: "var(--rs-color-background-elevation-base)", border: "1px solid var(--rs-color-border-neutral-faded)", borderRadius: "var(--rs-unit-radius-medium)", width: 60, height: 60, }} /> <div style={{ backgroundColor: "var(--rs-color-background-elevation-raised)", border: "1px solid var(--rs-color-border-neutral-faded)", borderRadius: "var(--rs-unit-radius-medium)", width: 60, height: 60, boxShadow: "var(--rs-shadow-raised)", }} /> <div style={{ backgroundColor: "var(--rs-color-background-elevation-overlay)", border: "1px solid var(--rs-color-border-neutral-faded)", borderRadius: "var(--rs-unit-radius-medium)", width: 60, height: 60, boxShadow: "var(--rs-shadow-overlay)", }} /> </View> </Theme> <Theme colorMode="dark"> <View backgroundColor="neutral-faded" padding={8} borderRadius="large" direction="row" gap={3}> <div style={{ backgroundColor: "var(--rs-color-background-elevation-base)", border: "1px solid var(--rs-color-border-neutral-faded)", borderRadius: "var(--rs-unit-radius-medium)", width: 60, height: 60, }} /> <div style={{ backgroundColor: "var(--rs-color-background-elevation-raised)", border: "1px solid var(--rs-color-border-neutral-faded)", borderRadius: "var(--rs-unit-radius-medium)", width: 60, height: 60, boxShadow: "var(--rs-shadow-raised)", }} /> <div style={{ backgroundColor: "var(--rs-color-background-elevation-overlay)", border: "1px solid var(--rs-color-border-neutral-faded)", borderRadius: "var(--rs-unit-radius-medium)", width: 60, height: 60, boxShadow: "var(--rs-shadow-overlay)", }} /> </View> </Theme> </View>
⚡ We've slightly updated our elevation system with the design token name changes and a new color token to align color and shadow tokens completely. This change is inspired by Atlassian Design System's work on its foundations.
// Before After shadow-base shadow-raised shadow-elevated shadow-overlay ... color-background-elevation-base [new] color-background-base color-background-elevation-raised color-background-elevated color-background-elevation-overlay
We have reviewed our color palette to work better across various edge cases, especially in the dark mode:
<View gap={3}> <View gap={3} direction="row" align="center"> <Button onClick={() => {}}> Solid button </Button> <Button variant="faded" onClick={() => {}}> Faded button </Button> <Button variant="outline" onClick={() => {}}> Outline button </Button> <Button variant="ghost" onClick={() => {}}> Ghost button </Button> </View> <View gap={3} direction="row" align="center"> <Button color="primary" onClick={() => {}}> Solid button </Button> <Button color="primary" variant="faded" onClick={() => {}}> Faded button </Button> <Button color="primary" variant="outline" onClick={() => {}}> Outline button </Button> <Button color="primary" variant="ghost" onClick={() => {}}> Ghost button </Button> </View> </View>
The button is the component every design system usually starts with, and there are so many different use cases we need them for in our products. In this release, we're adding a new faded variant to the Button component and have slightly updated the existing variants' styles to ensure we cover as many typical use cases as possible.
You can find more information about the available variants in the documentation:
We've added support for more complicated menus with nesting. To achieve that, we have introduced two new componenets inside DropdownMenu: DropdownMenu.SubMenu and DropdownMenu.SubTrigger. By using them together with previously available parts of the DropdownMenu, you will automatically get trap focus support for multiple levels of menus and new hotkeys for working with submenus.
<DropdownMenu> <DropdownMenu.Trigger> {(attributes) => <Button attributes={attributes}>Open</Button>} </DropdownMenu.Trigger> <DropdownMenu.Content> <DropdownMenu.Item onClick={() => {}}>Item 1</DropdownMenu.Item> <DropdownMenu.SubMenu> <DropdownMenu.SubTrigger>Item 2</DropdownMenu.SubTrigger> <DropdownMenu.Content> <DropdownMenu.Item onClick={() => {}}>SubItem 1</DropdownMenu.Item> <DropdownMenu.Item onClick={() => {}}>SubItem 2</DropdownMenu.Item> </DropdownMenu.Content> </DropdownMenu.SubMenu> <DropdownMenu.Item onClick={() => {}}>Item 3</DropdownMenu.Item> </DropdownMenu.Content> </DropdownMenu>