All skills

Create beautiful, accessible user interfaces with shadcn/ui components (built on Radix UI + Tailwind), Tailwind CSS utility-first styling, and canvas-based visual designs. Use when building user interfaces, implementing design systems, creating responsive layouts, adding accessible components (dialogs, dropdowns, forms, tables), customizing themes and colors, implementing dark mode, generating visual designs and posters, or establishing consistent styling patterns across applications.

Use this Skill: https://skilld.dev/gh/nextlevelbuilder/ui-ux-pro-max-skill/ui-styling

This session only. Nothing lands on disk.

referencesshadcn-accessibility.md

≈2.5k tokens on demand. Your agent reads this file only when SKILL.md points to it.

shadcn/ui Accessibility Patterns

ARIA patterns, keyboard navigation, screen reader support, and accessible component usage.

Foundation: Radix UI Primitives

shadcn/ui built on Radix UI primitives - unstyled, accessible components following WAI-ARIA design patterns.

Benefits:

  • Keyboard navigation built-in
  • Screen reader announcements
  • Focus management
  • ARIA attributes automatically applied
  • Tested against accessibility standards

Keyboard Navigation

Focus Management

Focus visible states:

<Button className="focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2">
  Accessible Button
</Button>

Skip to content:

<a href="#main-content" className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:px-4 focus:py-2">
  Skip to content
</a>

<main id="main-content">
  {/* Content */}
</main>

Dialog/Modal Navigation

Dialogs trap focus automatically via Radix Dialog primitive:

import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"

<Dialog>
  <DialogTrigger>Open</DialogTrigger>
  <DialogContent>
    {/* Focus trapped here */}
    <input />  {/* Auto-focused */}
    <Button>Action</Button>
    {/* Esc to close, Tab to navigate */}
  </DialogContent>
</Dialog>

Features:

  • Focus trapped within dialog
  • Esc key closes
  • Tab cycles through focusable elements
  • Focus returns to trigger on close

Dropdown/Menu Navigation

import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"

<DropdownMenu>
  <DropdownMenuTrigger>Open</DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem>Profile</DropdownMenuItem>
    <DropdownMenuItem>Settings</DropdownMenuItem>
    <DropdownMenuItem>Logout</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Keyboard shortcuts:

  • Space/Enter: Open menu
  • Arrow Up/Down: Navigate items
  • Esc: Close menu
  • Tab: Close and move focus

Command Palette Navigation

import { Command } from "@/components/ui/command"

<Command>
  <CommandInput placeholder="Search..." />
  <CommandList>
    <CommandGroup heading="Suggestions">
      <CommandItem>Calendar</CommandItem>
      <CommandItem>Search</CommandItem>
    </CommandGroup>
  </CommandList>
</Command>

Features:

  • Type to filter
  • Arrow keys to navigate
  • Enter to select
  • Esc to close

Screen Reader Support

Semantic HTML

Use proper HTML elements:

// Good: Semantic HTML
<button>Click me</button>
<nav><a href="/">Home</a></nav>

// Avoid: Div soup
<div onClick={handler}>Click me</div>

ARIA Labels

Label interactive elements:

<Button aria-label="Close dialog">
  <X className="h-4 w-4" />
</Button>

<Input aria-label="Email address" type="email" />

Describe elements:

<Button aria-describedby="delete-description">
  Delete Account
</Button>
<p id="delete-description" className="sr-only">
  This action permanently deletes your account and cannot be undone
</p>

Screen Reader Only Text

Use sr-only class for screen reader only content:

<Button>
  <Trash className="h-4 w-4" />
  <span className="sr-only">Delete item</span>
</Button>

// CSS for sr-only
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

Live Regions

Announce dynamic content:

<div aria-live="polite" aria-atomic="true">
  {message}
</div>

// For urgent updates
<div aria-live="assertive">
  {error}
</div>

Toast component includes live region:

const { toast } = useToast()

toast({
  title: "Success",
  description: "Profile updated"
})
// Announced to screen readers automatically

Form Accessibility

Labels and Descriptions

Always label inputs:

import { Label } from "@/components/ui/label"
import { Input } from "@/components/ui/input"

<div>
  <Label htmlFor="email">Email</Label>
  <Input id="email" type="email" />
</div>

Add descriptions:

import { FormDescription, FormMessage } from "@/components/ui/form"

<FormItem>
  <FormLabel>Username</FormLabel>
  <FormControl>
    <Input {...field} />
  </FormControl>
  <FormDescription>
    Your public display name
  </FormDescription>
  <FormMessage />  {/* Error messages */}
</FormItem>

Error Handling

Announce errors to screen readers:

<FormField
  control={form.control}
  name="email"
  render={({ field, fieldState }) => (
    <FormItem>
      <FormLabel>Email</FormLabel>
      <FormControl>
        <Input
          {...field}
          aria-invalid={!!fieldState.error}
          aria-describedby={fieldState.error ? "email-error" : undefined}
        />
      </FormControl>
      <FormMessage id="email-error" />
    </FormItem>
  )}
/>

Required Fields

Indicate required fields:

<Label htmlFor="name">
  Name <span className="text-destructive">*</span>
  <span className="sr-only">(required)</span>
</Label>
<Input id="name" required />

Fieldset and Legend

Group related fields:

<fieldset>
  <legend className="text-lg font-semibold mb-4">
    Contact Information
  </legend>
  <div className="space-y-4">
    <FormField name="email" />
    <FormField name="phone" />
  </div>
</fieldset>

Component-Specific Patterns

Accordion

import { Accordion } from "@/components/ui/accordion"

<Accordion type="single" collapsible>
  <AccordionItem value="item-1">
    <AccordionTrigger>
      {/* Includes aria-expanded, aria-controls automatically */}
      Is it accessible?
    </AccordionTrigger>
    <AccordionContent>
      {/* Hidden when collapsed, announced when expanded */}
      Yes. Follows WAI-ARIA design pattern.
    </AccordionContent>
  </AccordionItem>
</Accordion>

Tabs

import { Tabs } from "@/components/ui/tabs"

<Tabs defaultValue="account">
  <TabsList role="tablist">
    {/* Arrow keys navigate, Space/Enter activates */}
    <TabsTrigger value="account">Account</TabsTrigger>
    <TabsTrigger value="password">Password</TabsTrigger>
  </TabsList>
  <TabsContent value="account">
    {/* Hidden unless selected, aria-labelledby links to trigger */}
    Account content
  </TabsContent>
</Tabs>

Select

import { Select } from "@/components/ui/select"

<Select>
  <SelectTrigger aria-label="Choose theme">
    <SelectValue placeholder="Theme" />
  </SelectTrigger>
  <SelectContent>
    {/* Keyboard navigable, announced to screen readers */}
    <SelectItem value="light">Light</SelectItem>
    <SelectItem value="dark">Dark</SelectItem>
  </SelectContent>
</Select>

Checkbox and Radio

import { Checkbox } from "@/components/ui/checkbox"
import { Label } from "@/components/ui/label"

<div className="flex items-center space-x-2">
  <Checkbox id="terms" aria-describedby="terms-description" />
  <Label htmlFor="terms">Accept terms</Label>
</div>
<p id="terms-description" className="text-sm text-muted-foreground">
  You agree to our Terms of Service and Privacy Policy
</p>

Alert

import { Alert } from "@/components/ui/alert"

<Alert role="alert">
  {/* Announced immediately to screen readers */}
  <AlertTitle>Error</AlertTitle>
  <AlertDescription>
    Your session has expired
  </AlertDescription>
</Alert>

Color Contrast

Ensure sufficient contrast between text and background.

WCAG Requirements:

  • AA: 4.5:1 for normal text, 3:1 for large text
  • AAA: 7:1 for normal text, 4.5:1 for large text

Check defaults:

// Good: High contrast
<p className="text-gray-900 dark:text-gray-100">Text</p>

// Avoid: Low contrast
<p className="text-gray-400 dark:text-gray-600">Hard to read</p>

Muted text:

// Use semantic muted foreground
<p className="text-muted-foreground">
  Secondary text with accessible contrast
</p>

Focus Indicators

Always provide visible focus indicators:

Default focus ring:

<Button className="focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2">
  Button
</Button>

Custom focus styles:

<a href="#" className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:underline">
  Link
</a>

Don't remove focus styles:

// Avoid
<button className="focus:outline-none">Bad</button>

// Use focus-visible instead
<button className="focus-visible:ring-2">Good</button>

Motion and Animation

Respect reduced motion preference:

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

In components:

<div className="transition-all motion-reduce:transition-none">
  Respects user preference
</div>

Testing Checklist

  • All interactive elements keyboard accessible
  • Focus indicators visible
  • Screen reader announces all content correctly
  • Form errors announced and associated
  • Color contrast meets WCAG AA
  • Semantic HTML used
  • ARIA labels provided for icon-only buttons
  • Modal/dialog focus trap works
  • Dropdown/select keyboard navigable
  • Live regions announce updates
  • Respects reduced motion preference
  • Works with browser zoom up to 200%
  • Tab order logical
  • Skip links provided for navigation

Tools

Testing tools:

  • Lighthouse accessibility audit
  • axe DevTools browser extension
  • NVDA/JAWS screen readers
  • Keyboard-only navigation testing
  • Color contrast checkers (Contrast Ratio, WebAIM)

Automated testing:

npm install -D @axe-core/react
import { useEffect } from 'react'

if (process.env.NODE_ENV === 'development') {
  import('@axe-core/react').then((axe) => {
    axe.default(React, ReactDOM, 1000)
  })
}

Source: SKILL.md on GitHub

No alerts12d3 checks · Risk SAFE
  • Gen Agent Trust Hub12d

    The ui-styling skill provides comprehensive resources and automation tools for building user interfaces using Tailwind CSS and shadcn/ui. It includes detailed accessibility and design guides, along with utility scripts for component installation and configuration generation. All automation scripts follow security best practices, such as input validation and safe subprocess execution, and no malicious patterns were identified.

  • Socket12d

    No alerts

  • Snyk12d

    Risk: LOW · No issues

Signed by skilld at de5f12b. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 3 days ago.

Activeupdated 2 weeks ago
argument-hint
[component or layout]
metadata
{
  "author": "claudekit",
  "version": "1.0.0"
}

README badge

README badge for nextlevelbuilder/ui-ux-pro-max-skill/ui-styling