Security News
Node.js EOL Versions CVE Dubbed the "Worst CVE of the Year" by Security Experts
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
@createinc/archetype
Advanced tools
The design system system.
Archetype is an opinionated design system stack. Learn more
This package is the core of Archetype, and contains three main parts:
README
focuses on this part.Archetype provides a design token system that is built on top of Tailwind and provides strong type-safety and ergonomic features.
To get started, create tokens of various types with createArchetypeTokens(<type>, <tokens)
.
For example, here's how you can create color tokens:
export const colors = createArchetypeTokens("colors", {
primary: "hsl(222.2 47.4% 11.2%)",
});
Then, create the global tokens object:
export const tokens = createArchetypeTokens("all", {
colors,
typography,
});
You can use the tokens object directly if you wish, but it is recommended to configure Tailwind CSS with them and use it instead.
You can use withArchetypeTailwind(<config>)
to create a Tailwind configuration helper. This utility also allows specifying both base styles and custom Tailwind configurations for more advanced use cases:
export const withTokens = withArchetypeTailwind({
tokens,
baseStyles: (theme) => ({
body: { backgroundColor: theme("colors.background") },
}),
tailwindConfig: { plugins: [tailwindcssAnimate] },
});
Finally, the withTokens
function can be used to create a Tailwind configuration that is pre-loaded with your design tokens. Use it in the Tailwind configuration file of your project:
export default withTokens({
content: [
// ...
],
// project-specific Tailwind configuration...
});
Archetype exports a few utilities that help you build specific components. They have been created with composition and customization in mind.
For example, the useAvatar
utility handles a lot of typical avatar features for you, like:
It's simple to use:
// in your Avatar component
const { avatarState, computedInitials, initialsColor } = useAvatar({
name,
initials,
image,
initialsColorOptions,
});
// you can then use these values to render the avatar UI, e.g.
if (avatarState === "initials") color = initialsColor;
avatarState === "fallback" ? <Icon icon={fallbackIcon} /> : null;
<span>{computedInitials}</span>;
Archetype simplifies many common design system challenges through a structured and consistent way of authoring design system components. This is supported by a robust set of utilities, tools, and types.
Here's an incomplete list of challenges addressed by Archetype:
as
prop).Let's learn how to author a component using Archetype.
🛈 Styles are meant to be authored with the help of the Scope and Better states PostCSS plugins.
Create the stylesheet as ComponentName.scoped.css
.
Import it in the component file (ComponentName.tsx
):
import "./ComponentName.scoped.css";
Create the styles
object using scopedStyles
:
const styles = scopedStyles("ComponentName");
All classes are scoped by default. Use styles.nameOfTheClass
to reference them, e.g.:
<div className={styles.avatar} />
Classes that start with underscore (e.g. ._my-class
) are unscoped (a.k.a. "global"), use them directly:
<div className="my-class" />
Note that the underscore is removed.
🛈 Using unscoped classes is only intended as a escape hatch (e.g. a class from a third party library that you have no control over).
If class scoping gets in the way, try other strategies like targeting
data-
attributes before resorting to unscoped classes.
TODO: Archetype styling guidelines.
There are two types of components: simple and polymorphic.
Simple components render a specific HTML element consistently (e.g. div
). This is the most common type of component.
Polymorphic components can be rendered as different elements depending on the value of the as
prop (e.g. button
or a
).
Component options
For both simple and polymorphic components, create an "options" type with any props you want to add:
/** `Button` options. */
export type ButtonOptions = {
/**
* The button's visual appearance.
*
* @default "primary"
*/
variant?:
| "primary"
| "destructive"
| "outline"
| "secondary"
| "ghost"
| "link";
};
🛈 Archetype design systems make a disctinction between "options" and "props".
- Options: design-system-specific props like
variant
,size
, etc.- Props: all props including options, e.g. the
<button />
onClick
prop.
Component props
You can create the props type with ExtendedProps
or PolymorphicProps
.
🛈 Archetype components always "extend" from either an HTML element or a different component, like a UI primitive from Ariakit, Radix, etc.
This means that the component will accept all props from component it's extending from, in addition to options. For example, a component that extends from
<button />
will acceptonClick
.
Simple components
You can extend an HTML element:
/** `Button` props. */
export type ButtonProps = ExtendedProps<"button", ButtonOptions>;
Or another component:
/** `Button` props. */
export type ButtonProps = ExtendedProps<Ariakit.ButtonProps, ButtonOptions>;
To create a component that uses these props, use createComponent
and annotate the type with Component
:
/**
* A button. Rendered as `<button />`.
*
* @example
*
* ```tsx
* <Button variant="secondary">Click me!</Button>;
* ```
*/
export const Button: Component<ButtonProps> = createComponent(
({ variant, ...props }) => (
<button
data-variant={variant}
{...props}
className={clsx(styles.button, props.className)}
/>
)
);
Polymorphic components
First, create a "polymorphic spec" type that defines a default as
value and maps as
values to the base component props:
/** `Button` polymorphic spec. */
export type ButtonAs = {
// the default `as` value
default: "button";
// base props can be from plain HTML elements
a: "a";
// or from other components
button: Ariakit.ButtonProps;
};
Then create the props type with PolymorphicProps
. Note that the As
type has to be generic for proper type-checking, and the default must match the default
value in the "polymorphic spec" type:
/** `Button` props. */
export type ButtonProps<As extends "div" | "button" | "a" = "div"> =
PolymorphicProps<ButtonAs, As, ButtonOptions>;
🛈 Notice how the combination of the "polymorphic spec" type and
PolymorphicProps
achieves the same result asExtendedProps
, except it allows multiple options depending on the value of theas
prop.
To create the component, use createPolymorphicComponent
and annotate it with PolymorphicComponent
. Pass it the "polymorphic spec" type and the options type (not the props type!):
/**
* A button.
*
* Use the `as` prop to render as:
*
* - `"button"` (default) - [`<Ariakit.Button
* />`](https://ariakit.org/reference/button)
* - `"a"` - `<a />`
*
* @example
*
* ```tsx
* <Button variant="secondary">Click me!</Button>;
* ```
*
* @example
*
* ```tsx
* // as link
* <Button as="a" href="https://dio.la/">
* Visit my blog
* </Button>;
* ```
*/
export const Button: PolymorphicComponent<AvatarAs, AvatarOptions> =
createPolymorphicComponent(({ as = "button", variant, ...props }) => {
const Element = as === "button" ? Ariakit.Button : as;
return (
<Element
data-variant={variant}
{...props}
className={clsx(styles.button, props.className)}
/>
);
});
No options?
In some cases, you might not have any options to add. You can simply omit it in all places where you would normally pass it (ExtendedProps
, PolymorphicProps
, createComponent
, createPolymorphicComponent
).
Default props
To define default props, use satisfies
to create an object:
const DEFAULT_PROPS = {
variant: "primary",
} satisfies Partial<ButtonProps>;
Then, use it when destructuring props:
export const Button = createComponent<ButtonProps>(
({ as = "button", variant = DEFAULT_PROPS.variant, ...props }) => {
/* ... */
}
);
🛈 If you're on an older TypeScript version that doesn't support
satisfies
, you useas const
to achieve similar types (with less type-safety thought!).
TODO: open/closed, polymorphic, etc.
TODO: second
Component
type argument, documentation, etc.
TODO: Ariakit stores, stores as component properties, etc.
TODO: extension and rendering docs, polymorphic, examples, etc.
TODO: recommended file structure, packaging, etc.
FAQs
Unknown package
We found that @createinc/archetype demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 29 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
Security News
cURL and Go security teams are publicly rejecting CVSS as flawed for assessing vulnerabilities and are calling for more accurate, context-aware approaches.
Security News
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.