样式
使用 Tailwind 或 StyleSheet API 为 HeroUI Native 组件编写样式
HeroUI Native 提供灵活的样式方案:Tailwind CSS 工具类、StyleSheet API,以及用于动态样式的 render props。
样式原则
HeroUI Native 以 className 作为主要样式入口,所有组件均可通过 className 使用 Tailwind 类。
StyleSheet 优先级: 同时传入 style(StyleSheet)与 className 时,style 优先级更高,可在需要时覆盖 Tailwind。
动画样式: 部分样式属性由 react-native-reanimated 驱动,与 StyleSheet 类似,其优先级也高于 className。要确认哪些属性受动画占用、无法仅靠 className 设置:
- 在 IDE 中悬停
className— TypeScript 定义会提示可用属性 - 查阅组件文档 — 组件页顶部通常有样式源码链接,其中会标注动画相关限制
自定义动画样式: 若某属性被动画占用,可在支持 animation 属性的组件上通过 animation 进行调整。
基础样式
使用 className: 所有 HeroUI Native 组件都支持 className:
import { Button } from 'heroui-native';
<Button className="bg-accent px-6 py-3 rounded-lg">
<Button.Label>Custom Button</Button.Label>
</Button>;使用 style: 也可通过 style 传入内联样式:
import { Button } from 'heroui-native';
<Button style={{ backgroundColor: '#8B5CF6', paddingHorizontal: 24 }}>
<Button.Label>Styled Button</Button.Label>
</Button>;Render Props
使用渲染函数读取组件状态并动态定制内容:
import { RadioGroup, Label, cn } from 'heroui-native';
<RadioGroup value={value} onValueChange={setValue}>
<RadioGroup.Item value="option1">
{({ isSelected, isInvalid, isDisabled }) => (
<>
<Label
className={cn(
'text-foreground',
isSelected && 'text-accent font-semibold'
)}
>
Option 1
</Label>
<Radio
className={cn(
'border-2 rounded-full',
isSelected && 'border-accent bg-accent'
)}
>
{isSelected && <CustomIcon />}
</Radio>
</>
)}
</RadioGroup.Item>
</RadioGroup>;封装可复用组件
结合 tailwind-variants(Tailwind 优先的变体 API)封装自定义组件:
import { Button } from 'heroui-native';
import type { ButtonRootProps } from 'heroui-native';
import { tv, type VariantProps } from 'tailwind-variants';
const customButtonVariants = tv({
base: 'font-semibold rounded-lg',
variants: {
intent: {
primary: 'bg-blue-500',
secondary: 'bg-gray-200',
danger: 'bg-red-500',
},
},
defaultVariants: {
intent: 'primary',
},
});
const customLabelVariants = tv({
base: '',
variants: {
intent: {
primary: 'text-white',
secondary: 'text-gray-800',
danger: 'text-white',
},
},
defaultVariants: {
intent: 'primary',
},
});
type CustomButtonVariants = VariantProps<typeof customButtonVariants>;
interface CustomButtonProps
extends Omit<ButtonRootProps, 'className' | 'variant'>,
CustomButtonVariants {
className?: string;
labelClassName?: string;
}
export function CustomButton({
intent,
className,
labelClassName,
children,
...props
}: CustomButtonProps) {
return (
<Button
className={customButtonVariants({ intent, className })}
{...props}
>
<Button.Label
className={customLabelVariants({ intent, className: labelClassName })}
>
{children}
</Button.Label>
</Button>
);
}使用组件自带的 classNames
每个 HeroUI Native 组件都会导出与内部一致的 classNames 工具对象,便于让自定义组件在视觉上与库内组件保持一致。
例如,让自定义 Link 看起来像 Button:
import { buttonClassNames, cn } from 'heroui-native';
import { Pressable, Text } from 'react-native';
interface LinkProps {
href: string;
variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
size?: 'sm' | 'md' | 'lg';
children: React.ReactNode;
className?: string;
}
export function Link({
href,
variant = 'primary',
size = 'md',
children,
className,
}: LinkProps) {
return (
<Pressable
className={cn(
buttonClassNames.root({ variant, size }),
className
)}
onPress={() => {
// Handle navigation
}}
>
<Text className={buttonClassNames.label({ variant, size })}>
{children}
</Text>
</Pressable>
);
}可用的 classNames 导出:
每个组件都会导出对应的 classNames 对象,例如:
buttonClassNames— 包含root与label函数cardClassNames— 包含root、header、body、footer、label与description函数chipClassNames— 包含root与label函数- 其他组件同理……
典型用法:
import { buttonClassNames } from 'heroui-native';
// Use with variant and size options
const rootClasses = buttonClassNames.root({
variant: 'primary',
size: 'md',
className: 'custom-class', // Optional: merge with your own classes
});
const labelClasses = buttonClassNames.label({
variant: 'primary',
size: 'md',
});classNames 函数的变体参数与对应组件一致,便于在自定义组件与 HeroUI 组件之间保持视觉一致。
响应式设计
HeroUI Native 通过 Uniwind 支持 Tailwind 的响应式断点前缀,如 sm:、md:、lg:、xl:,按屏幕宽度条件应用样式。
移动优先: 先写无前缀的小屏样式,再用断点为大屏增强。
响应式排版与间距
import { Button } from 'heroui-native';
import { View, Text } from 'react-native';
<View className="px-4 sm:px-6 lg:px-8 py-6 sm:py-8">
<Text className="text-2xl sm:text-3xl lg:text-4xl font-bold mb-4 sm:mb-6">
Responsive Heading
</Text>
<Button className="px-3 sm:px-4 lg:px-6">
<Button.Label className="text-sm sm:text-base lg:text-lg">
Responsive Button
</Button.Label>
</Button>
</View>;响应式布局
import { View, Text } from 'react-native';
<View className="flex-row flex-wrap">
{/* Mobile: 1 column, Tablet: 2 columns, Desktop: 3 columns */}
<View className="w-full sm:w-1/2 lg:w-1/3 p-2">
<View className="bg-accent p-4 rounded-lg">
<Text className="text-accent-foreground">Item 1</Text>
</View>
</View>
</View>;默认断点:
sm:640pxmd:768pxlg:1024pxxl:1280px2xl:1536px
自定义断点与更多说明见 Uniwind 断点文档。
工具函数
HeroUI Native 提供一些样式相关的工具。
cn
cn 用于合并 Tailwind 类并处理冲突,适合条件类或与 props 传入的类合并:
import { cn } from 'heroui-native';
import { View } from 'react-native';
function MyComponent({ className, isActive }) {
return (
<View
className={cn(
'bg-background p-4 rounded-lg',
'border border-separator',
isActive && 'bg-accent',
className
)}
/>
);
}cn 基于 tailwind-variants,具备:
- 自动合并 Tailwind 类(
twMerge: true) - 自定义透明度分组等能力
- 合理的冲突解决(靠后的类覆盖靠前的类)
冲突示例:
// 'bg-accent' overrides 'bg-background'
cn('bg-background p-4', 'bg-accent');
// Result: 'p-4 bg-accent'useThemeColor
从 CSS 变量读取主题色,支持单色或一次读取多种颜色(后者更高效)。
单色:
import { useThemeColor } from 'heroui-native';
function MyComponent() {
const accentColor = useThemeColor('accent');
const dangerColor = useThemeColor('danger');
return (
<View style={{ borderColor: accentColor }}>
<Text style={{ color: dangerColor }}>Error message</Text>
</View>
);
}多色(推荐在需要多个 token 时使用):
import { useThemeColor } from 'heroui-native';
function MyComponent() {
const [accentColor, backgroundColor, dangerColor] = useThemeColor([
'accent',
'background',
'danger',
]);
return (
<View style={{ borderColor: accentColor, backgroundColor }}>
<Text style={{ color: dangerColor }}>Error message</Text>
</View>
);
}类型签名:
// Single color
useThemeColor(themeColor: ThemeColor): string
// Multiple colors (with type inference for tuples)
useThemeColor<T extends readonly [ThemeColor, ...ThemeColor[]]>(
themeColor: T
): CreateStringTuple<T['length']>
// Multiple colors (array)
useThemeColor(themeColor: ThemeColor[]): string[]可用主题色包括:background、foreground、surface、accent、default、success、warning、danger 及其 hover、soft、foreground 等变体,以及 muted、border、separator、field、overlay 等语义色。