🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@ios27_design_system/rails

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ios27_design_system/rails

iOS 27 design system for Rails 8 + Hotwire — CSS tokens, Stimulus controllers, ERB partials

latest
Source
npmnpm
Version
1.0.0
Version published
Weekly downloads
25
-78.81%
Maintainers
1
Weekly downloads
 
Created
Source

iOS 27 Design System -- Rails 8 + Hotwire

Production-ready implementation of the iOS 27 design language for Rails 8 applications using Stimulus, ERB, and Turbo.

Quick Start

1. Copy Assets into Your Rails Project

app/
  assets/
    stylesheets/
      ios27/
        tokens.css           <-- Design tokens (colors, typography, materials)
        sheet.css            <-- Sheet component styles
        context-menu.css     <-- Context menu styles
  javascript/
    controllers/
      ios27_toolbar_controller.js
      ios27_tab_bar_controller.js
      ios27_sheet_controller.js
      ios27_alert_controller.js
      ios27_context_menu_controller.js
      ios27_dark_mode_controller.js
  views/
    shared/
      ios27/
        _toolbar.html.erb
        _list_row.html.erb
        _list_section.html.erb
        _alert.html.erb
        _button.html.erb
        _tab_bar.html.erb

2. Asset Pipeline Integration

Propshaft (Rails 8 default):

/* app/assets/stylesheets/application.css */
/* Add to your existing stylesheet */
@import "ios27/tokens.css";
@import "ios27/sheet.css";
@import "ios27/context-menu.css";

Sprockets (legacy):

/* app/assets/stylesheets/application.css */
/*
 *= require ios27/tokens
 *= require ios27/sheet
 *= require ios27/context-menu
 */

3. Register Stimulus Controllers

Option A: Bulk registration (recommended)

// app/javascript/controllers/index.js
import { application } from "./application"

import { registerIos27Controllers } from "./ios27_controller"
registerIos27Controllers(application)

Option B: Individual registration

// app/javascript/controllers/index.js
import { application } from "./application"

import { Ios27ToolbarController } from "./ios27_controller"
import { Ios27TabBarController } from "./ios27_controller"
import { Ios27SheetController } from "./ios27_controller"
import { Ios27AlertController } from "./ios27_controller"
import { Ios27ContextMenuController } from "./ios27_controller"
import { Ios27DarkModeController } from "./ios27_controller"

application.register("ios27-toolbar", Ios27ToolbarController)
application.register("ios27-tab-bar", Ios27TabBarController)
application.register("ios27-sheet", Ios27SheetController)
application.register("ios27-alert", Ios27AlertController)
application.register("ios27-context-menu", Ios27ContextMenuController)
application.register("ios27-dark-mode", Ios27DarkModeController)

4. Importmap (if not using bundler)

# config/importmap.rb
pin "@hotwired/stimulus", to: "stimulus.min.js"
pin_all_from "app/javascript/controllers", under: "controllers"

Full Example: Settings Page

A complete Rails view demonstrating the iOS 27 design system in action.

<%# app/views/settings/index.html.erb %>
<% content_for :title, "Settings" %>

<%# -- Toolbar with large title -- %>
<%= render "shared/ios27/toolbar",
      title: "Settings",
      large_title: true %>

<%# -- Main scrollable content -- %>
<main style="background: var(--ios-bg-grouped-primary);
             padding: var(--ios-spacing-lg) 0;
             padding-bottom: calc(49px + var(--ios-safe-area-bottom) + var(--ios-spacing-2xl));
             min-height: 100vh;"
      data-ios27-toolbar-target="scrollContainer">

  <%# -- Profile Section -- %>
  <%= render "shared/ios27/list_section" do %>
    <%= render "shared/ios27/list_row",
          title: current_user.name,
          subtitle: "Apple Account, iCloud, and purchases",
          leading: '<div style="width:44px;height:44px;border-radius:50%;background:var(--ios-color-blue);display:flex;align-items:center;justify-content:center;color:white;font-weight:600;font-size:18px;">SH</div>',
          trailing: '<span class="ios-row__chevron"></span>',
          url: account_path %>
  <% end %>

  <%# -- Connectivity Section -- %>
  <%= render "shared/ios27/list_section" do %>
    <%= render "shared/ios27/list_row",
          title: "Wi-Fi",
          detail: "Home-5G",
          leading: '<div style="background:var(--ios-color-blue);width:29px;height:29px;border-radius:6px;display:flex;align-items:center;justify-content:center;color:white;font-size:14px;">W</div>',
          trailing: '<span class="ios-row__chevron"></span>',
          url: wifi_settings_path %>

    <%= render "shared/ios27/list_row",
          title: "Bluetooth",
          detail: "On",
          leading: '<div style="background:var(--ios-color-blue);width:29px;height:29px;border-radius:6px;display:flex;align-items:center;justify-content:center;color:white;font-size:14px;">B</div>',
          trailing: '<span class="ios-row__chevron"></span>',
          url: bluetooth_settings_path %>

    <%= render "shared/ios27/list_row",
          title: "Cellular",
          leading: '<div style="background:var(--ios-color-green);width:29px;height:29px;border-radius:6px;display:flex;align-items:center;justify-content:center;color:white;font-size:14px;">C</div>',
          trailing: '<span class="ios-row__chevron"></span>',
          url: cellular_settings_path %>
  <% end %>

  <%# -- Notifications (lazy loaded via Turbo Frame) -- %>
  <%= render "shared/ios27/list_section", header: "NOTIFICATIONS" do %>
    <turbo-frame id="notification-prefs" src="<%= notification_preferences_path %>" loading="lazy">
      <div class="ios-row" style="justify-content:center;min-height:88px;">
        <span class="ios-footnote" style="color:var(--ios-label-tertiary);">Loading...</span>
      </div>
    </turbo-frame>
  <% end %>

  <%# -- Danger Zone -- %>
  <%= render "shared/ios27/list_section", footer: "Signing out will remove your data from this device." do %>
    <%= render "shared/ios27/list_row",
          title: "Sign Out",
          destructive: true,
          url: sign_out_confirm_path %>
  <% end %>

</main>

<%# -- Tab Bar -- %>
<%= render "shared/ios27/tab_bar",
      current: "settings",
      tabs: [
        { id: "home", label: "Home", url: root_path,
          icon_html: '<svg width="25" height="25" viewBox="0 0 25 25"><path d="M3 10.5L12.5 3L22 10.5V21H15.5V15H9.5V21H3V10.5Z" fill="currentColor"/></svg>' },
        { id: "search", label: "Search", url: search_path,
          icon_html: '<svg width="25" height="25" viewBox="0 0 25 25"><circle cx="11" cy="11" r="7" stroke="currentColor" stroke-width="2" fill="none"/><line x1="16" y1="16" x2="22" y2="22" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>' },
        { id: "settings", label: "Settings", url: settings_path,
          icon_html: '<svg width="25" height="25" viewBox="0 0 25 25"><circle cx="12.5" cy="12.5" r="3" stroke="currentColor" stroke-width="2" fill="none"/><path d="M12.5 2L14 5H11L12.5 2Z" fill="currentColor"/></svg>' }
      ] %>

<%# -- Dark mode toggle (optional) -- %>
<div style="position:fixed;top:var(--ios-spacing-sm);right:var(--ios-spacing-sm);z-index:200;">
  <button data-controller="ios27-dark-mode"
          data-action="ios27-dark-mode#toggle"
          class="ios-btn ios-btn--liquid_glass ios-btn--small">
    Dark Mode
  </button>
</div>

Layout Template

<%# app/views/layouts/application.html.erb %>
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="default">
  <title><%= yield(:title) || "App" %></title>

  <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
  <%= javascript_importmap_tags %>
</head>
<body style="font-family: var(--ios-font-family);
             color: var(--ios-label-primary);
             background: var(--ios-bg-grouped-primary);
             margin: 0;
             -webkit-font-smoothing: antialiased;">

  <%# Alerts and sheets render into this container via Turbo Streams %>
  <div id="modal-container"></div>

  <%= yield %>

</body>
</html>

File Reference

FilePurpose
tokens.cssAll 50+ CSS custom properties: colors, typography, materials, spacing, animation
_ios27_helpers.html.erbERB partials: toolbar, list_row, list_section, alert, button, tab_bar
ios27_controller.js6 Stimulus controllers: toolbar, tab-bar, sheet, alert, context-menu, dark-mode
components.mdComponent mapping guide with ERB code examples
README.mdThis file -- setup and usage guide

Design Token Reference

All tokens use the --ios- prefix. Key categories:

CategoryExample VariableLight Value
System Colors--ios-color-blue#0088ff
Labels--ios-label-primaryrgba(0,0,0,1)
Backgrounds--ios-bg-grouped-primary#f2f2f7
Fills--ios-fill-primaryrgba(120,120,120,0.2)
Grays--ios-gray#8e8e93
Glass--ios-glass-bg-mediumrgba(245,245,245,0.6)
Typography--ios-body-size17px
Spacing--ios-spacing-md16px
Radius--ios-radius-md12px
Animation--ios-duration-normal250ms

Dark mode values override automatically via @media (prefers-color-scheme: dark) or manually via the .ios27-dark class on <html>.

Turbo Integration Patterns

Turbo Drive (Full-Page Navigation)

Default behavior. All <a> tags get SPA-like navigation. Toolbar and tab bar persist.

Turbo Frames (Partial Updates)

Use for tab content, lazy-loaded sections, and inline editing.

<turbo-frame id="content">
  <%# Only this frame updates on navigation %>
</turbo-frame>

Turbo Streams (Real-Time Updates)

Use for alerts, notifications, and server-pushed changes.

# Controller
respond_to do |format|
  format.turbo_stream {
    render turbo_stream: turbo_stream.append("modal-container",
      partial: "shared/ios27/alert",
      locals: { title: "Done!", message: "Item saved.", actions: [{ label: "OK", variant: :cancel }] }
    )
  }
end

Browser Support

  • Safari 15.4+ (required for backdrop-filter, :has(), env())
  • Chrome 105+
  • Firefox 103+
  • Edge 105+

The Liquid Glass effect (backdrop-filter: blur()) degrades gracefully to a solid background on unsupported browsers.

Keywords

ios27

FAQs

Package last updated on 30 Jul 2026

Did you know?

Socket

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.

Install

Related posts