Design Systems
Put together your own design system.
Build a shared component package that keeps its types, themes, and compiler optimizations in every app that consumes it.
If you only use styled() inside your app, the compiler cannot optimize those
components, because it needs to know about them at build time.
Let’s break down how to set this up in more detail.
Step 1: Create a package
Your design system needs to live in its own npm module, which can be private to just your app. That way you can later direct the compiler to look for that package.
Design systems can extend from each other. In fact, tamagui extends
@tamagui/core, which contains simple base-level components.
So, for example, if you’d like to use the Tamagui XStack, YStack, Button
and Paragraph in your design system, you would add tamagui to your design
system’s package.json.
If you want to build more from scratch, then use @tamagui/core and only import
either the View or Text components. For the purpose of this guide, we’ll use
@tamagui/core.
Add package.json:
If using TypeScript, a tsconfig.json of your choosing:
tsconfig.json
There are a few things to note here:
- We’re using
@tamagui/buildto build this package, which is a small script built aroundesbuildandtypescriptthat makes sure you output your components with JSX preserved. - We then set
module:jsx, which then needs to be added to your webpackresolve.mainFields.- The Next.js plugin handles this for you automatically.
sideEffectsfield is important, otherwise webpack will remove the generated CSS in production.
Step 2: Create your design system
Check the configuration for more detail on this step.
You’ll be creating a tamagui.config.ts at the root of your app. It will
contain a full suite of tokens, themes, and fonts exported onto a single named
config export.
Step 3: Define and export components
Now, create and export your components. You can re-export components from
tamagui or @tamagui/core as well. Let’s create a Circle component:
Circle.tsx:
v3 removed runtime spread, resolver-name, and type-key variant matching. Brand
value-to-style functions with styled.dynamic; its generic parameter is the
accepted prop type, and one function handles the whole value domain.
And then export from index.tsx:
Step 4: Set up your build
Now in your app, add @ourapp/components and tamagui (since we are extending
it) to your package.json, and update your tamagui build configuration.
Webpack
In your webpack.config.js:
Next.js
In your next.config.js:
React Native
In your metro.config.js:
Configuration notes
You only need tamagui in your components array if you extend it, otherwise
no need. You can also extend your own base level module so long as they export
Tamagui styled components.
Step 5: Test it out
In your app, you should now be able to import and use your Circle component.
Using the debug pragma, you can also verify the extraction is working. Make sure
the build settings logTimings: true and disableExtraction: false are set so
you can see the compiler at work:
Anywhere in your app:
When it compiles you should see something like:
Terminal
To get more information on any extraction, use the // debug pragma:
You should see much more log output with details on how it extracted, including the final CSS and JS.