How to Create a React Component
Spor uses Chakra UI as its component library for building and customizing UI components. Before creating a new component or extending an existing one, check the Chakra UI documentation to see if a suitable component or feature already exists. Reusing Chakra's built-in components and patterns helps maintain consistency and reduces unnecessary custom code.
Project Structure
Each component lives in packages/spor-react/src and should follow the same structure as in Figma for easy reference.
A typical component folder contains:
ComponentName.tsx– The main component file.index.ts– Exports the component.
And for the styling, add it to the /theme/recipes or /theme/slot-recipes folder:
component.ts– Defines the component’s styles.
Step-by-Step Guide
1. Create the Component File
Create a new file in the appropriate folder and name it after the component (e.g., Button.tsx).
import {type ButtonProps as ChakraButtonProps,Button as ChakraButton,type RecipeVariantProps,} from "@chakra-ui/react";type ButtonVariantProps = RecipeVariantProps<typeof buttonRecipe>; // this is created in step 2export type ButtonProps = Omit<ChakraButtonProps,"size" | "variant" | "colorPalette" // Exclude props from Chakra if needed> & PropsWithChildren<ButtonVariantProps> & {/* The props */}export const Button = ({ref, ...props} : ButtonProps & {ref?: React.Ref<HTMLDivElement>;}) => {const { variant = "primary", size = "md", ...rest } = props;const recipe = useRecipe({ key: "button" });const styles = recipe({ variant, size });return (<ChakraButton ref={ref} css={styles.root} {...rest}>{props.children}</ChakraButton>);});
2. Define the Component Recipe
Spor uses Chakra UI's Recipe and Slot Recipe APIs for component styling. The component styles should therefore be placed in a separate recipe.ts file, placed in either src/theme/recipes or src/theme/slot-recipes .
Most styling changes should happen inside the recipe instead of directly in the React component.
Difference between recipe and slot-recipe
Use a recipe when the component consists of a single element. Examples include components like Button and Badge. Read more about Chakra Recipe in Chakra’s documentationEkstern lenke.
Use a slot recipe when a component consists of multiple styled parts. Examples include components such as Dialog, Select, and Menu.
A slot recipe allows each part of the component (called a slot) to have its own styling. Typical slots might include:
- root
- trigger
- content
- label
- icon
This makes it possible to style complex components while keeping everything type-safe and consistent. Read more about Chakra’s slot-recipe in Chakra’s documentationEkstern lenke.
Best practices when defining a recipe:
- Use design tokens instead of hardcoded values for colors, spacing, and typography.
- Use full names for properties – instead of shorthand like
bgorpx, usebackgroundorpaddingXfor better clarity. - Define defaults in
defaultPropsinstead of in the recipe – sometimes, definingdefaultVariantinside the recipe can cause a bug where other variants inherit styles from the default one.
import { defineRecipe } from "@vygruppen/spor-react";export const buttonRecipe = defineRecipe({base: {root: {fontWeight: "bold",borderRadius: "md",},},variants: {variant: {primary: {root: {backgroundColor: "brand.surface",color: "white",_hover: {backgroundColor: "brand.surface.hover"},},},floating: {root: {backgroundColor: "floating.surface",color: "white",_hover: {backgroundColor: "floating.surface.hover"},},},},size: {sm: {root: {fontSize: "sm",paddingX: 3,paddingY: 2}},md: {root: {fontSize: "md",paddingX: 4,paddingY: 3}},},},});
3. Export the Component
Ensure your component is exported from index.ts.
export * from "./Button";
And remember to add your recipe to the theme system:
import { buttonRecipe } from '../button'export const recipes = {button: buttonRecipe,/* Other recipes */}
4. Testing the changes
To test your changes, run the following command from the root of the repository.
pnpm dev
This starts the designmanual-frontend application on port 3008.
Once it's running, open http://localhost:3008/ in your browser.
If you've modified an existing component, you can test your changes by using the examples on that component's documentation page. For more advanced testing, use the Playground at http://localhost:3008/playground, where you can write and experiment with your own code.
5. Writing Tests
Component tests live in the ___tests___ folder. When adding a new feature to an existing component, add a test to that component’s test file to cover the new functionality. When introducing a new component, create a componentName.test.tsx file and include the relevant tests.
Read more about writing tests in the guide Tests and StorybookEkstern lenke.
6. Create a Changeset & Open a PR
Since this is a new component, create a changeset so it gets included in the next release.
npx changeset
Follow the prompts to document the changes, commit the changeset, and push your branch. See the page on Releasing new versionEkstern lenke for a more detailed guide on how to write a changeset.
Once the PR is merged, a Version Packages PR will be generated. When that gets merged (by a Spor administrator) your changes will be available in a new version of Spor.
Best Practices
✔ Use design tokens (brand.primary, spacing.md) instead of hardcoded values.
✔ Keep components small & modular—split complex components into smaller ones.
✔ Use props instead of deeply nested children when possible.
✔ Follow naming conventions (variant, size, colorPalette).
✔ Ensure accessibility—always test with keyboard & screen readers.
For more tips and best practices, read the guide on Best Practices for Component DevelopmentEkstern lenke.